From f7917c009c28c941ba151ee66f04dc7f6a2e1e0b Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 7 Apr 2011 06:57:17 -0700 Subject: chelsio: Move the Chelsio drivers Moves the drivers for the Chelsio chipsets into drivers/net/ethernet/chelsio/ and the necessary Kconfig and Makefile changes. CC: Divy Le Ray CC: Dimitris Michailidis CC: Casey Leedom Signed-off-by: Jeff Kirsher --- MAINTAINERS | 6 +- drivers/infiniband/hw/cxgb3/Makefile | 2 +- drivers/infiniband/hw/cxgb4/Makefile | 2 +- drivers/net/Kconfig | 86 - drivers/net/Makefile | 4 - drivers/net/chelsio/Makefile | 9 - drivers/net/chelsio/common.h | 353 -- drivers/net/chelsio/cphy.h | 175 - drivers/net/chelsio/cpl5_cmd.h | 639 ---- drivers/net/chelsio/cxgb2.c | 1379 ------- drivers/net/chelsio/elmer0.h | 158 - drivers/net/chelsio/espi.c | 373 -- drivers/net/chelsio/espi.h | 68 - drivers/net/chelsio/fpga_defs.h | 232 -- drivers/net/chelsio/gmac.h | 142 - drivers/net/chelsio/mv88e1xxx.c | 397 -- drivers/net/chelsio/mv88e1xxx.h | 127 - drivers/net/chelsio/mv88x201x.c | 260 -- drivers/net/chelsio/my3126.c | 209 -- drivers/net/chelsio/pm3393.c | 796 ---- drivers/net/chelsio/regs.h | 2168 ----------- drivers/net/chelsio/sge.c | 2140 ----------- drivers/net/chelsio/sge.h | 94 - drivers/net/chelsio/subr.c | 1130 ------ drivers/net/chelsio/suni1x10gexp_regs.h | 1643 --------- drivers/net/chelsio/tp.c | 171 - drivers/net/chelsio/tp.h | 72 - drivers/net/chelsio/vsc7326.c | 730 ---- drivers/net/chelsio/vsc7326_reg.h | 297 -- drivers/net/cxgb3/Makefile | 8 - drivers/net/cxgb3/adapter.h | 334 -- drivers/net/cxgb3/ael1002.c | 941 ----- drivers/net/cxgb3/aq100x.c | 354 -- drivers/net/cxgb3/common.h | 775 ---- drivers/net/cxgb3/cxgb3_ctl_defs.h | 189 - drivers/net/cxgb3/cxgb3_defs.h | 114 - drivers/net/cxgb3/cxgb3_ioctl.h | 177 - drivers/net/cxgb3/cxgb3_main.c | 3448 ------------------ drivers/net/cxgb3/cxgb3_offload.c | 1418 -------- drivers/net/cxgb3/cxgb3_offload.h | 209 -- drivers/net/cxgb3/firmware_exports.h | 177 - drivers/net/cxgb3/l2t.c | 445 --- drivers/net/cxgb3/l2t.h | 141 - drivers/net/cxgb3/mc5.c | 438 --- drivers/net/cxgb3/regs.h | 2598 ------------- drivers/net/cxgb3/sge.c | 3303 ----------------- drivers/net/cxgb3/sge_defs.h | 255 -- drivers/net/cxgb3/t3_cpl.h | 1495 -------- drivers/net/cxgb3/t3_hw.c | 3785 ------------------- drivers/net/cxgb3/t3cdev.h | 70 - drivers/net/cxgb3/version.h | 44 - drivers/net/cxgb3/vsc8211.c | 416 --- drivers/net/cxgb3/xgmac.c | 657 ---- drivers/net/cxgb4/Makefile | 7 - drivers/net/cxgb4/cxgb4.h | 722 ---- drivers/net/cxgb4/cxgb4_main.c | 3806 -------------------- drivers/net/cxgb4/cxgb4_uld.h | 239 -- drivers/net/cxgb4/l2t.c | 597 --- drivers/net/cxgb4/l2t.h | 107 - drivers/net/cxgb4/sge.c | 2442 ------------- drivers/net/cxgb4/t4_hw.c | 2856 --------------- drivers/net/cxgb4/t4_hw.h | 140 - drivers/net/cxgb4/t4_msg.h | 678 ---- drivers/net/cxgb4/t4_regs.h | 885 ----- drivers/net/cxgb4/t4fw_api.h | 1623 --------- drivers/net/cxgb4vf/Makefile | 7 - drivers/net/cxgb4vf/adapter.h | 534 --- drivers/net/cxgb4vf/cxgb4vf_main.c | 2947 --------------- drivers/net/cxgb4vf/sge.c | 2465 ------------- drivers/net/cxgb4vf/t4vf_common.h | 274 -- drivers/net/cxgb4vf/t4vf_defs.h | 121 - drivers/net/cxgb4vf/t4vf_hw.c | 1387 ------- drivers/net/ethernet/Kconfig | 1 + drivers/net/ethernet/Makefile | 1 + drivers/net/ethernet/chelsio/Kconfig | 106 + drivers/net/ethernet/chelsio/Makefile | 8 + drivers/net/ethernet/chelsio/cxgb/Makefile | 9 + drivers/net/ethernet/chelsio/cxgb/common.h | 353 ++ drivers/net/ethernet/chelsio/cxgb/cphy.h | 175 + drivers/net/ethernet/chelsio/cxgb/cpl5_cmd.h | 639 ++++ drivers/net/ethernet/chelsio/cxgb/cxgb2.c | 1379 +++++++ drivers/net/ethernet/chelsio/cxgb/elmer0.h | 158 + drivers/net/ethernet/chelsio/cxgb/espi.c | 373 ++ drivers/net/ethernet/chelsio/cxgb/espi.h | 68 + drivers/net/ethernet/chelsio/cxgb/fpga_defs.h | 232 ++ drivers/net/ethernet/chelsio/cxgb/gmac.h | 142 + drivers/net/ethernet/chelsio/cxgb/mv88e1xxx.c | 397 ++ drivers/net/ethernet/chelsio/cxgb/mv88e1xxx.h | 127 + drivers/net/ethernet/chelsio/cxgb/mv88x201x.c | 260 ++ drivers/net/ethernet/chelsio/cxgb/my3126.c | 209 ++ drivers/net/ethernet/chelsio/cxgb/pm3393.c | 796 ++++ drivers/net/ethernet/chelsio/cxgb/regs.h | 2168 +++++++++++ drivers/net/ethernet/chelsio/cxgb/sge.c | 2140 +++++++++++ drivers/net/ethernet/chelsio/cxgb/sge.h | 94 + drivers/net/ethernet/chelsio/cxgb/subr.c | 1130 ++++++ .../net/ethernet/chelsio/cxgb/suni1x10gexp_regs.h | 1643 +++++++++ drivers/net/ethernet/chelsio/cxgb/tp.c | 171 + drivers/net/ethernet/chelsio/cxgb/tp.h | 72 + drivers/net/ethernet/chelsio/cxgb/vsc7326.c | 730 ++++ drivers/net/ethernet/chelsio/cxgb/vsc7326_reg.h | 297 ++ drivers/net/ethernet/chelsio/cxgb3/Makefile | 8 + drivers/net/ethernet/chelsio/cxgb3/adapter.h | 334 ++ drivers/net/ethernet/chelsio/cxgb3/ael1002.c | 941 +++++ drivers/net/ethernet/chelsio/cxgb3/aq100x.c | 354 ++ drivers/net/ethernet/chelsio/cxgb3/common.h | 775 ++++ .../net/ethernet/chelsio/cxgb3/cxgb3_ctl_defs.h | 189 + drivers/net/ethernet/chelsio/cxgb3/cxgb3_defs.h | 114 + drivers/net/ethernet/chelsio/cxgb3/cxgb3_ioctl.h | 177 + drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c | 3448 ++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c | 1418 ++++++++ drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.h | 209 ++ .../net/ethernet/chelsio/cxgb3/firmware_exports.h | 177 + drivers/net/ethernet/chelsio/cxgb3/l2t.c | 445 +++ drivers/net/ethernet/chelsio/cxgb3/l2t.h | 141 + drivers/net/ethernet/chelsio/cxgb3/mc5.c | 438 +++ drivers/net/ethernet/chelsio/cxgb3/regs.h | 2598 +++++++++++++ drivers/net/ethernet/chelsio/cxgb3/sge.c | 3303 +++++++++++++++++ drivers/net/ethernet/chelsio/cxgb3/sge_defs.h | 255 ++ drivers/net/ethernet/chelsio/cxgb3/t3_cpl.h | 1495 ++++++++ drivers/net/ethernet/chelsio/cxgb3/t3_hw.c | 3785 +++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb3/t3cdev.h | 70 + drivers/net/ethernet/chelsio/cxgb3/version.h | 44 + drivers/net/ethernet/chelsio/cxgb3/vsc8211.c | 416 +++ drivers/net/ethernet/chelsio/cxgb3/xgmac.c | 657 ++++ drivers/net/ethernet/chelsio/cxgb4/Makefile | 7 + drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 722 ++++ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 3806 ++++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h | 239 ++ drivers/net/ethernet/chelsio/cxgb4/l2t.c | 597 +++ drivers/net/ethernet/chelsio/cxgb4/l2t.h | 107 + drivers/net/ethernet/chelsio/cxgb4/sge.c | 2442 +++++++++++++ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 2856 +++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/t4_hw.h | 140 + drivers/net/ethernet/chelsio/cxgb4/t4_msg.h | 678 ++++ drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 885 +++++ drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 1623 +++++++++ drivers/net/ethernet/chelsio/cxgb4vf/Makefile | 7 + drivers/net/ethernet/chelsio/cxgb4vf/adapter.h | 534 +++ .../net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c | 2947 +++++++++++++++ drivers/net/ethernet/chelsio/cxgb4vf/sge.c | 2465 +++++++++++++ drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h | 274 ++ drivers/net/ethernet/chelsio/cxgb4vf/t4vf_defs.h | 121 + drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c | 1387 +++++++ drivers/scsi/cxgbi/cxgb3i/Kbuild | 2 +- drivers/scsi/cxgbi/cxgb4i/Kbuild | 2 +- 145 files changed, 57513 insertions(+), 57487 deletions(-) delete mode 100644 drivers/net/chelsio/Makefile delete mode 100644 drivers/net/chelsio/common.h delete mode 100644 drivers/net/chelsio/cphy.h delete mode 100644 drivers/net/chelsio/cpl5_cmd.h delete mode 100644 drivers/net/chelsio/cxgb2.c delete mode 100644 drivers/net/chelsio/elmer0.h delete mode 100644 drivers/net/chelsio/espi.c delete mode 100644 drivers/net/chelsio/espi.h delete mode 100644 drivers/net/chelsio/fpga_defs.h delete mode 100644 drivers/net/chelsio/gmac.h delete mode 100644 drivers/net/chelsio/mv88e1xxx.c delete mode 100644 drivers/net/chelsio/mv88e1xxx.h delete mode 100644 drivers/net/chelsio/mv88x201x.c delete mode 100644 drivers/net/chelsio/my3126.c delete mode 100644 drivers/net/chelsio/pm3393.c delete mode 100644 drivers/net/chelsio/regs.h delete mode 100644 drivers/net/chelsio/sge.c delete mode 100644 drivers/net/chelsio/sge.h delete mode 100644 drivers/net/chelsio/subr.c delete mode 100644 drivers/net/chelsio/suni1x10gexp_regs.h delete mode 100644 drivers/net/chelsio/tp.c delete mode 100644 drivers/net/chelsio/tp.h delete mode 100644 drivers/net/chelsio/vsc7326.c delete mode 100644 drivers/net/chelsio/vsc7326_reg.h delete mode 100644 drivers/net/cxgb3/Makefile delete mode 100644 drivers/net/cxgb3/adapter.h delete mode 100644 drivers/net/cxgb3/ael1002.c delete mode 100644 drivers/net/cxgb3/aq100x.c delete mode 100644 drivers/net/cxgb3/common.h delete mode 100644 drivers/net/cxgb3/cxgb3_ctl_defs.h delete mode 100644 drivers/net/cxgb3/cxgb3_defs.h delete mode 100644 drivers/net/cxgb3/cxgb3_ioctl.h delete mode 100644 drivers/net/cxgb3/cxgb3_main.c delete mode 100644 drivers/net/cxgb3/cxgb3_offload.c delete mode 100644 drivers/net/cxgb3/cxgb3_offload.h delete mode 100644 drivers/net/cxgb3/firmware_exports.h delete mode 100644 drivers/net/cxgb3/l2t.c delete mode 100644 drivers/net/cxgb3/l2t.h delete mode 100644 drivers/net/cxgb3/mc5.c delete mode 100644 drivers/net/cxgb3/regs.h delete mode 100644 drivers/net/cxgb3/sge.c delete mode 100644 drivers/net/cxgb3/sge_defs.h delete mode 100644 drivers/net/cxgb3/t3_cpl.h delete mode 100644 drivers/net/cxgb3/t3_hw.c delete mode 100644 drivers/net/cxgb3/t3cdev.h delete mode 100644 drivers/net/cxgb3/version.h delete mode 100644 drivers/net/cxgb3/vsc8211.c delete mode 100644 drivers/net/cxgb3/xgmac.c delete mode 100644 drivers/net/cxgb4/Makefile delete mode 100644 drivers/net/cxgb4/cxgb4.h delete mode 100644 drivers/net/cxgb4/cxgb4_main.c delete mode 100644 drivers/net/cxgb4/cxgb4_uld.h delete mode 100644 drivers/net/cxgb4/l2t.c delete mode 100644 drivers/net/cxgb4/l2t.h delete mode 100644 drivers/net/cxgb4/sge.c delete mode 100644 drivers/net/cxgb4/t4_hw.c delete mode 100644 drivers/net/cxgb4/t4_hw.h delete mode 100644 drivers/net/cxgb4/t4_msg.h delete mode 100644 drivers/net/cxgb4/t4_regs.h delete mode 100644 drivers/net/cxgb4/t4fw_api.h delete mode 100644 drivers/net/cxgb4vf/Makefile delete mode 100644 drivers/net/cxgb4vf/adapter.h delete mode 100644 drivers/net/cxgb4vf/cxgb4vf_main.c delete mode 100644 drivers/net/cxgb4vf/sge.c delete mode 100644 drivers/net/cxgb4vf/t4vf_common.h delete mode 100644 drivers/net/cxgb4vf/t4vf_defs.h delete mode 100644 drivers/net/cxgb4vf/t4vf_hw.c create mode 100644 drivers/net/ethernet/chelsio/Kconfig create mode 100644 drivers/net/ethernet/chelsio/Makefile create mode 100644 drivers/net/ethernet/chelsio/cxgb/Makefile create mode 100644 drivers/net/ethernet/chelsio/cxgb/common.h create mode 100644 drivers/net/ethernet/chelsio/cxgb/cphy.h create mode 100644 drivers/net/ethernet/chelsio/cxgb/cpl5_cmd.h create mode 100644 drivers/net/ethernet/chelsio/cxgb/cxgb2.c create mode 100644 drivers/net/ethernet/chelsio/cxgb/elmer0.h create mode 100644 drivers/net/ethernet/chelsio/cxgb/espi.c create mode 100644 drivers/net/ethernet/chelsio/cxgb/espi.h create mode 100644 drivers/net/ethernet/chelsio/cxgb/fpga_defs.h create mode 100644 drivers/net/ethernet/chelsio/cxgb/gmac.h create mode 100644 drivers/net/ethernet/chelsio/cxgb/mv88e1xxx.c create mode 100644 drivers/net/ethernet/chelsio/cxgb/mv88e1xxx.h create mode 100644 drivers/net/ethernet/chelsio/cxgb/mv88x201x.c create mode 100644 drivers/net/ethernet/chelsio/cxgb/my3126.c create mode 100644 drivers/net/ethernet/chelsio/cxgb/pm3393.c create mode 100644 drivers/net/ethernet/chelsio/cxgb/regs.h create mode 100644 drivers/net/ethernet/chelsio/cxgb/sge.c create mode 100644 drivers/net/ethernet/chelsio/cxgb/sge.h create mode 100644 drivers/net/ethernet/chelsio/cxgb/subr.c create mode 100644 drivers/net/ethernet/chelsio/cxgb/suni1x10gexp_regs.h create mode 100644 drivers/net/ethernet/chelsio/cxgb/tp.c create mode 100644 drivers/net/ethernet/chelsio/cxgb/tp.h create mode 100644 drivers/net/ethernet/chelsio/cxgb/vsc7326.c create mode 100644 drivers/net/ethernet/chelsio/cxgb/vsc7326_reg.h create mode 100644 drivers/net/ethernet/chelsio/cxgb3/Makefile create mode 100644 drivers/net/ethernet/chelsio/cxgb3/adapter.h create mode 100644 drivers/net/ethernet/chelsio/cxgb3/ael1002.c create mode 100644 drivers/net/ethernet/chelsio/cxgb3/aq100x.c create mode 100644 drivers/net/ethernet/chelsio/cxgb3/common.h create mode 100644 drivers/net/ethernet/chelsio/cxgb3/cxgb3_ctl_defs.h create mode 100644 drivers/net/ethernet/chelsio/cxgb3/cxgb3_defs.h create mode 100644 drivers/net/ethernet/chelsio/cxgb3/cxgb3_ioctl.h create mode 100644 drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c create mode 100644 drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c create mode 100644 drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.h create mode 100644 drivers/net/ethernet/chelsio/cxgb3/firmware_exports.h create mode 100644 drivers/net/ethernet/chelsio/cxgb3/l2t.c create mode 100644 drivers/net/ethernet/chelsio/cxgb3/l2t.h create mode 100644 drivers/net/ethernet/chelsio/cxgb3/mc5.c create mode 100644 drivers/net/ethernet/chelsio/cxgb3/regs.h create mode 100644 drivers/net/ethernet/chelsio/cxgb3/sge.c create mode 100644 drivers/net/ethernet/chelsio/cxgb3/sge_defs.h create mode 100644 drivers/net/ethernet/chelsio/cxgb3/t3_cpl.h create mode 100644 drivers/net/ethernet/chelsio/cxgb3/t3_hw.c create mode 100644 drivers/net/ethernet/chelsio/cxgb3/t3cdev.h create mode 100644 drivers/net/ethernet/chelsio/cxgb3/version.h create mode 100644 drivers/net/ethernet/chelsio/cxgb3/vsc8211.c create mode 100644 drivers/net/ethernet/chelsio/cxgb3/xgmac.c create mode 100644 drivers/net/ethernet/chelsio/cxgb4/Makefile create mode 100644 drivers/net/ethernet/chelsio/cxgb4/cxgb4.h create mode 100644 drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c create mode 100644 drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h create mode 100644 drivers/net/ethernet/chelsio/cxgb4/l2t.c create mode 100644 drivers/net/ethernet/chelsio/cxgb4/l2t.h create mode 100644 drivers/net/ethernet/chelsio/cxgb4/sge.c create mode 100644 drivers/net/ethernet/chelsio/cxgb4/t4_hw.c create mode 100644 drivers/net/ethernet/chelsio/cxgb4/t4_hw.h create mode 100644 drivers/net/ethernet/chelsio/cxgb4/t4_msg.h create mode 100644 drivers/net/ethernet/chelsio/cxgb4/t4_regs.h create mode 100644 drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h create mode 100644 drivers/net/ethernet/chelsio/cxgb4vf/Makefile create mode 100644 drivers/net/ethernet/chelsio/cxgb4vf/adapter.h create mode 100644 drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c create mode 100644 drivers/net/ethernet/chelsio/cxgb4vf/sge.c create mode 100644 drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h create mode 100644 drivers/net/ethernet/chelsio/cxgb4vf/t4vf_defs.h create mode 100644 drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c diff --git a/MAINTAINERS b/MAINTAINERS index af9de64d89aa..0853d00c7d48 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1994,7 +1994,7 @@ M: Divy Le Ray L: netdev@vger.kernel.org W: http://www.chelsio.com S: Supported -F: drivers/net/cxgb3/ +F: drivers/net/ethernet/chelsio/cxgb3/ CXGB3 IWARP RNIC DRIVER (IW_CXGB3) M: Steve Wise @@ -2008,7 +2008,7 @@ M: Dimitris Michailidis L: netdev@vger.kernel.org W: http://www.chelsio.com S: Supported -F: drivers/net/cxgb4/ +F: drivers/net/ethernet/chelsio/cxgb4/ CXGB4 IWARP RNIC DRIVER (IW_CXGB4) M: Steve Wise @@ -2022,7 +2022,7 @@ M: Casey Leedom L: netdev@vger.kernel.org W: http://www.chelsio.com S: Supported -F: drivers/net/cxgb4vf/ +F: drivers/net/ethernet/chelsio/cxgb4vf/ STMMAC ETHERNET DRIVER M: Giuseppe Cavallaro diff --git a/drivers/infiniband/hw/cxgb3/Makefile b/drivers/infiniband/hw/cxgb3/Makefile index 621619c794e5..2761364185af 100644 --- a/drivers/infiniband/hw/cxgb3/Makefile +++ b/drivers/infiniband/hw/cxgb3/Makefile @@ -1,4 +1,4 @@ -ccflags-y := -Idrivers/net/cxgb3 +ccflags-y := -Idrivers/net/ethernet/chelsio/cxgb3 obj-$(CONFIG_INFINIBAND_CXGB3) += iw_cxgb3.o diff --git a/drivers/infiniband/hw/cxgb4/Makefile b/drivers/infiniband/hw/cxgb4/Makefile index cd20b1342aec..46b878ca2c3b 100644 --- a/drivers/infiniband/hw/cxgb4/Makefile +++ b/drivers/infiniband/hw/cxgb4/Makefile @@ -1,4 +1,4 @@ -ccflags-y := -Idrivers/net/cxgb4 +ccflags-y := -Idrivers/net/ethernet/chelsio/cxgb4 obj-$(CONFIG_INFINIBAND_CXGB4) += iw_cxgb4.o diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 2f9f208472de..77ab2e189475 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1942,92 +1942,6 @@ if NETDEV_10000 config MDIO tristate -config CHELSIO_T1 - tristate "Chelsio 10Gb Ethernet support" - depends on PCI - select CRC32 - select MDIO - help - This driver supports Chelsio gigabit and 10-gigabit - Ethernet cards. More information about adapter features and - performance tuning is in . - - For general information about Chelsio and our products, visit - our website at . - - For customer support, please visit our customer support page at - . - - Please send feedback to . - - To compile this driver as a module, choose M here: the module - will be called cxgb. - -config CHELSIO_T1_1G - bool "Chelsio gigabit Ethernet support" - depends on CHELSIO_T1 - help - Enables support for Chelsio's gigabit Ethernet PCI cards. If you - are using only 10G cards say 'N' here. - -config CHELSIO_T3 - tristate "Chelsio Communications T3 10Gb Ethernet support" - depends on PCI && INET - select FW_LOADER - select MDIO - help - This driver supports Chelsio T3-based gigabit and 10Gb Ethernet - adapters. - - For general information about Chelsio and our products, visit - our website at . - - For customer support, please visit our customer support page at - . - - Please send feedback to . - - To compile this driver as a module, choose M here: the module - will be called cxgb3. - -config CHELSIO_T4 - tristate "Chelsio Communications T4 Ethernet support" - depends on PCI - select FW_LOADER - select MDIO - help - This driver supports Chelsio T4-based gigabit and 10Gb Ethernet - adapters. - - For general information about Chelsio and our products, visit - our website at . - - For customer support, please visit our customer support page at - . - - Please send feedback to . - - To compile this driver as a module choose M here; the module - will be called cxgb4. - -config CHELSIO_T4VF - tristate "Chelsio Communications T4 Virtual Function Ethernet support" - depends on PCI - help - This driver supports Chelsio T4-based gigabit and 10Gb Ethernet - adapters with PCI-E SR-IOV Virtual Functions. - - For general information about Chelsio and our products, visit - our website at . - - For customer support, please visit our customer support page at - . - - Please send feedback to . - - To compile this driver as a module choose M here; the module - will be called cxgb4vf. - config EHEA tristate "eHEA Ethernet support" depends on IBMEBUS && INET && SPARSEMEM diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 4cc2dcd3e0bd..a987d46bf67b 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -19,10 +19,6 @@ obj-$(CONFIG_IXGBE) += ixgbe/ obj-$(CONFIG_IXGBEVF) += ixgbevf/ obj-$(CONFIG_IXGB) += ixgb/ obj-$(CONFIG_IP1000) += ipg.o -obj-$(CONFIG_CHELSIO_T1) += chelsio/ -obj-$(CONFIG_CHELSIO_T3) += cxgb3/ -obj-$(CONFIG_CHELSIO_T4) += cxgb4/ -obj-$(CONFIG_CHELSIO_T4VF) += cxgb4vf/ obj-$(CONFIG_EHEA) += ehea/ obj-$(CONFIG_CAN) += can/ obj-$(CONFIG_BONDING) += bonding/ diff --git a/drivers/net/chelsio/Makefile b/drivers/net/chelsio/Makefile deleted file mode 100644 index 57a4b262fd3f..000000000000 --- a/drivers/net/chelsio/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Chelsio T1 driver -# - -obj-$(CONFIG_CHELSIO_T1) += cxgb.o - -cxgb-$(CONFIG_CHELSIO_T1_1G) += mv88e1xxx.o vsc7326.o -cxgb-objs := cxgb2.o espi.o tp.o pm3393.o sge.o subr.o \ - mv88x201x.o my3126.o $(cxgb-y) diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h deleted file mode 100644 index 5ccbed1784d2..000000000000 --- a/drivers/net/chelsio/common.h +++ /dev/null @@ -1,353 +0,0 @@ -/***************************************************************************** - * * - * File: common.h * - * $Revision: 1.21 $ * - * $Date: 2005/06/22 00:43:25 $ * - * Description: * - * part of the Chelsio 10Gb Ethernet Driver. * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * * - * http://www.chelsio.com * - * * - * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * - * All rights reserved. * - * * - * Maintainers: maintainers@chelsio.com * - * * - * Authors: Dimitrios Michailidis * - * Tina Yang * - * Felix Marti * - * Scott Bardone * - * Kurt Ottaway * - * Frank DiMambro * - * * - * History: * - * * - ****************************************************************************/ - -#define pr_fmt(fmt) "cxgb: " fmt - -#ifndef _CXGB_COMMON_H_ -#define _CXGB_COMMON_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRV_DESCRIPTION "Chelsio 10Gb Ethernet Driver" -#define DRV_NAME "cxgb" -#define DRV_VERSION "2.2" - -#define CH_DEVICE(devid, ssid, idx) \ - { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, ssid, 0, 0, idx } - -#define SUPPORTED_PAUSE (1 << 13) -#define SUPPORTED_LOOPBACK (1 << 15) - -#define ADVERTISED_PAUSE (1 << 13) -#define ADVERTISED_ASYM_PAUSE (1 << 14) - -typedef struct adapter adapter_t; - -struct t1_rx_mode { - struct net_device *dev; -}; - -#define t1_rx_mode_promisc(rm) (rm->dev->flags & IFF_PROMISC) -#define t1_rx_mode_allmulti(rm) (rm->dev->flags & IFF_ALLMULTI) -#define t1_rx_mode_mc_cnt(rm) (netdev_mc_count(rm->dev)) -#define t1_get_netdev(rm) (rm->dev) - -#define MAX_NPORTS 4 -#define PORT_MASK ((1 << MAX_NPORTS) - 1) -#define NMTUS 8 -#define TCB_SIZE 128 - -#define SPEED_INVALID 0xffff -#define DUPLEX_INVALID 0xff - -enum { - CHBT_BOARD_N110, - CHBT_BOARD_N210, - CHBT_BOARD_7500, - CHBT_BOARD_8000, - CHBT_BOARD_CHT101, - CHBT_BOARD_CHT110, - CHBT_BOARD_CHT210, - CHBT_BOARD_CHT204, - CHBT_BOARD_CHT204V, - CHBT_BOARD_CHT204E, - CHBT_BOARD_CHN204, - CHBT_BOARD_COUGAR, - CHBT_BOARD_6800, - CHBT_BOARD_SIMUL, -}; - -enum { - CHBT_TERM_FPGA, - CHBT_TERM_T1, - CHBT_TERM_T2, - CHBT_TERM_T3 -}; - -enum { - CHBT_MAC_CHELSIO_A, - CHBT_MAC_IXF1010, - CHBT_MAC_PM3393, - CHBT_MAC_VSC7321, - CHBT_MAC_DUMMY -}; - -enum { - CHBT_PHY_88E1041, - CHBT_PHY_88E1111, - CHBT_PHY_88X2010, - CHBT_PHY_XPAK, - CHBT_PHY_MY3126, - CHBT_PHY_8244, - CHBT_PHY_DUMMY -}; - -enum { - PAUSE_RX = 1 << 0, - PAUSE_TX = 1 << 1, - PAUSE_AUTONEG = 1 << 2 -}; - -/* Revisions of T1 chip */ -enum { - TERM_T1A = 0, - TERM_T1B = 1, - TERM_T2 = 3 -}; - -struct sge_params { - unsigned int cmdQ_size[2]; - unsigned int freelQ_size[2]; - unsigned int large_buf_capacity; - unsigned int rx_coalesce_usecs; - unsigned int last_rx_coalesce_raw; - unsigned int default_rx_coalesce_usecs; - unsigned int sample_interval_usecs; - unsigned int coalesce_enable; - unsigned int polling; -}; - -struct chelsio_pci_params { - unsigned short speed; - unsigned char width; - unsigned char is_pcix; -}; - -struct tp_params { - unsigned int pm_size; - unsigned int cm_size; - unsigned int pm_rx_base; - unsigned int pm_tx_base; - unsigned int pm_rx_pg_size; - unsigned int pm_tx_pg_size; - unsigned int pm_rx_num_pgs; - unsigned int pm_tx_num_pgs; - unsigned int rx_coalescing_size; - unsigned int use_5tuple_mode; -}; - -struct mc5_params { - unsigned int mode; /* selects MC5 width */ - unsigned int nservers; /* size of server region */ - unsigned int nroutes; /* size of routing region */ -}; - -/* Default MC5 region sizes */ -#define DEFAULT_SERVER_REGION_LEN 256 -#define DEFAULT_RT_REGION_LEN 1024 - -struct adapter_params { - struct sge_params sge; - struct mc5_params mc5; - struct tp_params tp; - struct chelsio_pci_params pci; - - const struct board_info *brd_info; - - unsigned short mtus[NMTUS]; - unsigned int nports; /* # of ethernet ports */ - unsigned int stats_update_period; - unsigned short chip_revision; - unsigned char chip_version; - unsigned char is_asic; - unsigned char has_msi; -}; - -struct link_config { - unsigned int supported; /* link capabilities */ - unsigned int advertising; /* advertised capabilities */ - unsigned short requested_speed; /* speed user has requested */ - unsigned short speed; /* actual link speed */ - unsigned char requested_duplex; /* duplex user has requested */ - unsigned char duplex; /* actual link duplex */ - unsigned char requested_fc; /* flow control user has requested */ - unsigned char fc; /* actual link flow control */ - unsigned char autoneg; /* autonegotiating? */ -}; - -struct cmac; -struct cphy; - -struct port_info { - struct net_device *dev; - struct cmac *mac; - struct cphy *phy; - struct link_config link_config; - struct net_device_stats netstats; -}; - -struct sge; -struct peespi; - -struct adapter { - u8 __iomem *regs; - struct pci_dev *pdev; - unsigned long registered_device_map; - unsigned long open_device_map; - unsigned long flags; - - const char *name; - int msg_enable; - u32 mmio_len; - - struct work_struct ext_intr_handler_task; - struct adapter_params params; - - /* Terminator modules. */ - struct sge *sge; - struct peespi *espi; - struct petp *tp; - - struct napi_struct napi; - struct port_info port[MAX_NPORTS]; - struct delayed_work stats_update_task; - struct timer_list stats_update_timer; - - spinlock_t tpi_lock; - spinlock_t work_lock; - spinlock_t mac_lock; - - /* guards async operations */ - spinlock_t async_lock ____cacheline_aligned; - u32 slow_intr_mask; - int t1powersave; -}; - -enum { /* adapter flags */ - FULL_INIT_DONE = 1 << 0, -}; - -struct mdio_ops; -struct gmac; -struct gphy; - -struct board_info { - unsigned char board; - unsigned char port_number; - unsigned long caps; - unsigned char chip_term; - unsigned char chip_mac; - unsigned char chip_phy; - unsigned int clock_core; - unsigned int clock_mc3; - unsigned int clock_mc4; - unsigned int espi_nports; - unsigned int clock_elmer0; - unsigned char mdio_mdien; - unsigned char mdio_mdiinv; - unsigned char mdio_mdc; - unsigned char mdio_phybaseaddr; - const struct gmac *gmac; - const struct gphy *gphy; - const struct mdio_ops *mdio_ops; - const char *desc; -}; - -static inline int t1_is_asic(const adapter_t *adapter) -{ - return adapter->params.is_asic; -} - -extern const struct pci_device_id t1_pci_tbl[]; - -static inline int adapter_matches_type(const adapter_t *adapter, - int version, int revision) -{ - return adapter->params.chip_version == version && - adapter->params.chip_revision == revision; -} - -#define t1_is_T1B(adap) adapter_matches_type(adap, CHBT_TERM_T1, TERM_T1B) -#define is_T2(adap) adapter_matches_type(adap, CHBT_TERM_T2, TERM_T2) - -/* Returns true if an adapter supports VLAN acceleration and TSO */ -static inline int vlan_tso_capable(const adapter_t *adapter) -{ - return !t1_is_T1B(adapter); -} - -#define for_each_port(adapter, iter) \ - for (iter = 0; iter < (adapter)->params.nports; ++iter) - -#define board_info(adapter) ((adapter)->params.brd_info) -#define is_10G(adapter) (board_info(adapter)->caps & SUPPORTED_10000baseT_Full) - -static inline unsigned int core_ticks_per_usec(const adapter_t *adap) -{ - return board_info(adap)->clock_core / 1000000; -} - -extern int __t1_tpi_read(adapter_t *adapter, u32 addr, u32 *valp); -extern int __t1_tpi_write(adapter_t *adapter, u32 addr, u32 value); -extern int t1_tpi_write(adapter_t *adapter, u32 addr, u32 value); -extern int t1_tpi_read(adapter_t *adapter, u32 addr, u32 *value); - -extern void t1_interrupts_enable(adapter_t *adapter); -extern void t1_interrupts_disable(adapter_t *adapter); -extern void t1_interrupts_clear(adapter_t *adapter); -extern int t1_elmer0_ext_intr_handler(adapter_t *adapter); -extern void t1_elmer0_ext_intr(adapter_t *adapter); -extern int t1_slow_intr_handler(adapter_t *adapter); - -extern int t1_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc); -extern const struct board_info *t1_get_board_info(unsigned int board_id); -extern const struct board_info *t1_get_board_info_from_ids(unsigned int devid, - unsigned short ssid); -extern int t1_seeprom_read(adapter_t *adapter, u32 addr, __le32 *data); -extern int t1_get_board_rev(adapter_t *adapter, const struct board_info *bi, - struct adapter_params *p); -extern int t1_init_hw_modules(adapter_t *adapter); -extern int t1_init_sw_modules(adapter_t *adapter, const struct board_info *bi); -extern void t1_free_sw_modules(adapter_t *adapter); -extern void t1_fatal_err(adapter_t *adapter); -extern void t1_link_changed(adapter_t *adapter, int port_id); -extern void t1_link_negotiated(adapter_t *adapter, int port_id, int link_stat, - int speed, int duplex, int pause); -#endif /* _CXGB_COMMON_H_ */ diff --git a/drivers/net/chelsio/cphy.h b/drivers/net/chelsio/cphy.h deleted file mode 100644 index 1f095a9fc739..000000000000 --- a/drivers/net/chelsio/cphy.h +++ /dev/null @@ -1,175 +0,0 @@ -/***************************************************************************** - * * - * File: cphy.h * - * $Revision: 1.7 $ * - * $Date: 2005/06/21 18:29:47 $ * - * Description: * - * part of the Chelsio 10Gb Ethernet Driver. * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * * - * http://www.chelsio.com * - * * - * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * - * All rights reserved. * - * * - * Maintainers: maintainers@chelsio.com * - * * - * Authors: Dimitrios Michailidis * - * Tina Yang * - * Felix Marti * - * Scott Bardone * - * Kurt Ottaway * - * Frank DiMambro * - * * - * History: * - * * - ****************************************************************************/ - -#ifndef _CXGB_CPHY_H_ -#define _CXGB_CPHY_H_ - -#include "common.h" - -struct mdio_ops { - void (*init)(adapter_t *adapter, const struct board_info *bi); - int (*read)(struct net_device *dev, int phy_addr, int mmd_addr, - u16 reg_addr); - int (*write)(struct net_device *dev, int phy_addr, int mmd_addr, - u16 reg_addr, u16 val); - unsigned mode_support; -}; - -/* PHY interrupt types */ -enum { - cphy_cause_link_change = 0x1, - cphy_cause_error = 0x2, - cphy_cause_fifo_error = 0x3 -}; - -enum { - PHY_LINK_UP = 0x1, - PHY_AUTONEG_RDY = 0x2, - PHY_AUTONEG_EN = 0x4 -}; - -struct cphy; - -/* PHY operations */ -struct cphy_ops { - void (*destroy)(struct cphy *); - int (*reset)(struct cphy *, int wait); - - int (*interrupt_enable)(struct cphy *); - int (*interrupt_disable)(struct cphy *); - int (*interrupt_clear)(struct cphy *); - int (*interrupt_handler)(struct cphy *); - - int (*autoneg_enable)(struct cphy *); - int (*autoneg_disable)(struct cphy *); - int (*autoneg_restart)(struct cphy *); - - int (*advertise)(struct cphy *phy, unsigned int advertise_map); - int (*set_loopback)(struct cphy *, int on); - int (*set_speed_duplex)(struct cphy *phy, int speed, int duplex); - int (*get_link_status)(struct cphy *phy, int *link_ok, int *speed, - int *duplex, int *fc); - - u32 mmds; -}; - -/* A PHY instance */ -struct cphy { - int state; /* Link status state machine */ - adapter_t *adapter; /* associated adapter */ - - struct delayed_work phy_update; - - u16 bmsr; - int count; - int act_count; - int act_on; - - u32 elmer_gpo; - - const struct cphy_ops *ops; /* PHY operations */ - struct mdio_if_info mdio; - struct cphy_instance *instance; -}; - -/* Convenience MDIO read/write wrappers */ -static inline int cphy_mdio_read(struct cphy *cphy, int mmd, int reg, - unsigned int *valp) -{ - int rc = cphy->mdio.mdio_read(cphy->mdio.dev, cphy->mdio.prtad, mmd, - reg); - *valp = (rc >= 0) ? rc : -1; - return (rc >= 0) ? 0 : rc; -} - -static inline int cphy_mdio_write(struct cphy *cphy, int mmd, int reg, - unsigned int val) -{ - return cphy->mdio.mdio_write(cphy->mdio.dev, cphy->mdio.prtad, mmd, - reg, val); -} - -static inline int simple_mdio_read(struct cphy *cphy, int reg, - unsigned int *valp) -{ - return cphy_mdio_read(cphy, MDIO_DEVAD_NONE, reg, valp); -} - -static inline int simple_mdio_write(struct cphy *cphy, int reg, - unsigned int val) -{ - return cphy_mdio_write(cphy, MDIO_DEVAD_NONE, reg, val); -} - -/* Convenience initializer */ -static inline void cphy_init(struct cphy *phy, struct net_device *dev, - int phy_addr, struct cphy_ops *phy_ops, - const struct mdio_ops *mdio_ops) -{ - struct adapter *adapter = netdev_priv(dev); - phy->adapter = adapter; - phy->ops = phy_ops; - if (mdio_ops) { - phy->mdio.prtad = phy_addr; - phy->mdio.mmds = phy_ops->mmds; - phy->mdio.mode_support = mdio_ops->mode_support; - phy->mdio.mdio_read = mdio_ops->read; - phy->mdio.mdio_write = mdio_ops->write; - } - phy->mdio.dev = dev; -} - -/* Operations of the PHY-instance factory */ -struct gphy { - /* Construct a PHY instance with the given PHY address */ - struct cphy *(*create)(struct net_device *dev, int phy_addr, - const struct mdio_ops *mdio_ops); - - /* - * Reset the PHY chip. This resets the whole PHY chip, not individual - * ports. - */ - int (*reset)(adapter_t *adapter); -}; - -extern const struct gphy t1_my3126_ops; -extern const struct gphy t1_mv88e1xxx_ops; -extern const struct gphy t1_vsc8244_ops; -extern const struct gphy t1_mv88x201x_ops; - -#endif /* _CXGB_CPHY_H_ */ diff --git a/drivers/net/chelsio/cpl5_cmd.h b/drivers/net/chelsio/cpl5_cmd.h deleted file mode 100644 index e36d45b78cc7..000000000000 --- a/drivers/net/chelsio/cpl5_cmd.h +++ /dev/null @@ -1,639 +0,0 @@ -/***************************************************************************** - * * - * File: cpl5_cmd.h * - * $Revision: 1.6 $ * - * $Date: 2005/06/21 18:29:47 $ * - * Description: * - * part of the Chelsio 10Gb Ethernet Driver. * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * * - * http://www.chelsio.com * - * * - * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * - * All rights reserved. * - * * - * Maintainers: maintainers@chelsio.com * - * * - * Authors: Dimitrios Michailidis * - * Tina Yang * - * Felix Marti * - * Scott Bardone * - * Kurt Ottaway * - * Frank DiMambro * - * * - * History: * - * * - ****************************************************************************/ - -#ifndef _CXGB_CPL5_CMD_H_ -#define _CXGB_CPL5_CMD_H_ - -#include - -#if !defined(__LITTLE_ENDIAN_BITFIELD) && !defined(__BIG_ENDIAN_BITFIELD) -#error "Adjust your defines" -#endif - -enum CPL_opcode { - CPL_PASS_OPEN_REQ = 0x1, - CPL_PASS_OPEN_RPL = 0x2, - CPL_PASS_ESTABLISH = 0x3, - CPL_PASS_ACCEPT_REQ = 0xE, - CPL_PASS_ACCEPT_RPL = 0x4, - CPL_ACT_OPEN_REQ = 0x5, - CPL_ACT_OPEN_RPL = 0x6, - CPL_CLOSE_CON_REQ = 0x7, - CPL_CLOSE_CON_RPL = 0x8, - CPL_CLOSE_LISTSRV_REQ = 0x9, - CPL_CLOSE_LISTSRV_RPL = 0xA, - CPL_ABORT_REQ = 0xB, - CPL_ABORT_RPL = 0xC, - CPL_PEER_CLOSE = 0xD, - CPL_ACT_ESTABLISH = 0x17, - - CPL_GET_TCB = 0x24, - CPL_GET_TCB_RPL = 0x25, - CPL_SET_TCB = 0x26, - CPL_SET_TCB_FIELD = 0x27, - CPL_SET_TCB_RPL = 0x28, - CPL_PCMD = 0x29, - - CPL_PCMD_READ = 0x31, - CPL_PCMD_READ_RPL = 0x32, - - - CPL_RX_DATA = 0xA0, - CPL_RX_DATA_DDP = 0xA1, - CPL_RX_DATA_ACK = 0xA3, - CPL_RX_PKT = 0xAD, - CPL_RX_ISCSI_HDR = 0xAF, - CPL_TX_DATA_ACK = 0xB0, - CPL_TX_DATA = 0xB1, - CPL_TX_PKT = 0xB2, - CPL_TX_PKT_LSO = 0xB6, - - CPL_RTE_DELETE_REQ = 0xC0, - CPL_RTE_DELETE_RPL = 0xC1, - CPL_RTE_WRITE_REQ = 0xC2, - CPL_RTE_WRITE_RPL = 0xD3, - CPL_RTE_READ_REQ = 0xC3, - CPL_RTE_READ_RPL = 0xC4, - CPL_L2T_WRITE_REQ = 0xC5, - CPL_L2T_WRITE_RPL = 0xD4, - CPL_L2T_READ_REQ = 0xC6, - CPL_L2T_READ_RPL = 0xC7, - CPL_SMT_WRITE_REQ = 0xC8, - CPL_SMT_WRITE_RPL = 0xD5, - CPL_SMT_READ_REQ = 0xC9, - CPL_SMT_READ_RPL = 0xCA, - CPL_ARP_MISS_REQ = 0xCD, - CPL_ARP_MISS_RPL = 0xCE, - CPL_MIGRATE_C2T_REQ = 0xDC, - CPL_MIGRATE_C2T_RPL = 0xDD, - CPL_ERROR = 0xD7, - - /* internal: driver -> TOM */ - CPL_MSS_CHANGE = 0xE1 -}; - -#define NUM_CPL_CMDS 256 - -enum CPL_error { - CPL_ERR_NONE = 0, - CPL_ERR_TCAM_PARITY = 1, - CPL_ERR_TCAM_FULL = 3, - CPL_ERR_CONN_RESET = 20, - CPL_ERR_CONN_EXIST = 22, - CPL_ERR_ARP_MISS = 23, - CPL_ERR_BAD_SYN = 24, - CPL_ERR_CONN_TIMEDOUT = 30, - CPL_ERR_XMIT_TIMEDOUT = 31, - CPL_ERR_PERSIST_TIMEDOUT = 32, - CPL_ERR_FINWAIT2_TIMEDOUT = 33, - CPL_ERR_KEEPALIVE_TIMEDOUT = 34, - CPL_ERR_ABORT_FAILED = 42, - CPL_ERR_GENERAL = 99 -}; - -enum { - CPL_CONN_POLICY_AUTO = 0, - CPL_CONN_POLICY_ASK = 1, - CPL_CONN_POLICY_DENY = 3 -}; - -enum { - ULP_MODE_NONE = 0, - ULP_MODE_TCPDDP = 1, - ULP_MODE_ISCSI = 2, - ULP_MODE_IWARP = 3, - ULP_MODE_SSL = 4 -}; - -enum { - CPL_PASS_OPEN_ACCEPT, - CPL_PASS_OPEN_REJECT -}; - -enum { - CPL_ABORT_SEND_RST = 0, - CPL_ABORT_NO_RST, - CPL_ABORT_POST_CLOSE_REQ = 2 -}; - -enum { // TX_PKT_LSO ethernet types - CPL_ETH_II, - CPL_ETH_II_VLAN, - CPL_ETH_802_3, - CPL_ETH_802_3_VLAN -}; - -union opcode_tid { - u32 opcode_tid; - u8 opcode; -}; - -#define S_OPCODE 24 -#define V_OPCODE(x) ((x) << S_OPCODE) -#define G_OPCODE(x) (((x) >> S_OPCODE) & 0xFF) -#define G_TID(x) ((x) & 0xFFFFFF) - -/* tid is assumed to be 24-bits */ -#define MK_OPCODE_TID(opcode, tid) (V_OPCODE(opcode) | (tid)) - -#define OPCODE_TID(cmd) ((cmd)->ot.opcode_tid) - -/* extract the TID from a CPL command */ -#define GET_TID(cmd) (G_TID(ntohl(OPCODE_TID(cmd)))) - -struct tcp_options { - u16 mss; - u8 wsf; -#if defined(__LITTLE_ENDIAN_BITFIELD) - u8 rsvd:4; - u8 ecn:1; - u8 sack:1; - u8 tstamp:1; -#else - u8 tstamp:1; - u8 sack:1; - u8 ecn:1; - u8 rsvd:4; -#endif -}; - -struct cpl_pass_open_req { - union opcode_tid ot; - u16 local_port; - u16 peer_port; - u32 local_ip; - u32 peer_ip; - u32 opt0h; - u32 opt0l; - u32 peer_netmask; - u32 opt1; -}; - -struct cpl_pass_open_rpl { - union opcode_tid ot; - u16 local_port; - u16 peer_port; - u32 local_ip; - u32 peer_ip; - u8 resvd[7]; - u8 status; -}; - -struct cpl_pass_establish { - union opcode_tid ot; - u16 local_port; - u16 peer_port; - u32 local_ip; - u32 peer_ip; - u32 tos_tid; - u8 l2t_idx; - u8 rsvd[3]; - u32 snd_isn; - u32 rcv_isn; -}; - -struct cpl_pass_accept_req { - union opcode_tid ot; - u16 local_port; - u16 peer_port; - u32 local_ip; - u32 peer_ip; - u32 tos_tid; - struct tcp_options tcp_options; - u8 dst_mac[6]; - u16 vlan_tag; - u8 src_mac[6]; - u8 rsvd[2]; - u32 rcv_isn; - u32 unknown_tcp_options; -}; - -struct cpl_pass_accept_rpl { - union opcode_tid ot; - u32 rsvd0; - u32 rsvd1; - u32 peer_ip; - u32 opt0h; - union { - u32 opt0l; - struct { - u8 rsvd[3]; - u8 status; - }; - }; -}; - -struct cpl_act_open_req { - union opcode_tid ot; - u16 local_port; - u16 peer_port; - u32 local_ip; - u32 peer_ip; - u32 opt0h; - u32 opt0l; - u32 iff_vlantag; - u32 rsvd; -}; - -struct cpl_act_open_rpl { - union opcode_tid ot; - u16 local_port; - u16 peer_port; - u32 local_ip; - u32 peer_ip; - u32 new_tid; - u8 rsvd[3]; - u8 status; -}; - -struct cpl_act_establish { - union opcode_tid ot; - u16 local_port; - u16 peer_port; - u32 local_ip; - u32 peer_ip; - u32 tos_tid; - u32 rsvd; - u32 snd_isn; - u32 rcv_isn; -}; - -struct cpl_get_tcb { - union opcode_tid ot; - u32 rsvd; -}; - -struct cpl_get_tcb_rpl { - union opcode_tid ot; - u16 len; - u8 rsvd; - u8 status; -}; - -struct cpl_set_tcb { - union opcode_tid ot; - u16 len; - u16 rsvd; -}; - -struct cpl_set_tcb_field { - union opcode_tid ot; - u8 rsvd[3]; - u8 offset; - u32 mask; - u32 val; -}; - -struct cpl_set_tcb_rpl { - union opcode_tid ot; - u8 rsvd[3]; - u8 status; -}; - -struct cpl_pcmd { - union opcode_tid ot; - u16 dlen_in; - u16 dlen_out; - u32 pcmd_parm[2]; -}; - -struct cpl_pcmd_read { - union opcode_tid ot; - u32 rsvd1; - u16 rsvd2; - u32 addr; - u16 len; -}; - -struct cpl_pcmd_read_rpl { - union opcode_tid ot; - u16 len; -}; - -struct cpl_close_con_req { - union opcode_tid ot; - u32 rsvd; -}; - -struct cpl_close_con_rpl { - union opcode_tid ot; - u8 rsvd[3]; - u8 status; - u32 snd_nxt; - u32 rcv_nxt; -}; - -struct cpl_close_listserv_req { - union opcode_tid ot; - u32 rsvd; -}; - -struct cpl_close_listserv_rpl { - union opcode_tid ot; - u8 rsvd[3]; - u8 status; -}; - -struct cpl_abort_req { - union opcode_tid ot; - u32 rsvd0; - u8 rsvd1; - u8 cmd; - u8 rsvd2[6]; -}; - -struct cpl_abort_rpl { - union opcode_tid ot; - u32 rsvd0; - u8 rsvd1; - u8 status; - u8 rsvd2[6]; -}; - -struct cpl_peer_close { - union opcode_tid ot; - u32 rsvd; -}; - -struct cpl_tx_data { - union opcode_tid ot; - u32 len; - u32 rsvd0; - u16 urg; - u16 flags; -}; - -struct cpl_tx_data_ack { - union opcode_tid ot; - u32 ack_seq; -}; - -struct cpl_rx_data { - union opcode_tid ot; - u32 len; - u32 seq; - u16 urg; - u8 rsvd; - u8 status; -}; - -struct cpl_rx_data_ack { - union opcode_tid ot; - u32 credit; -}; - -struct cpl_rx_data_ddp { - union opcode_tid ot; - u32 len; - u32 seq; - u32 nxt_seq; - u32 ulp_crc; - u16 ddp_status; - u8 rsvd; - u8 status; -}; - -/* - * We want this header's alignment to be no more stringent than 2-byte aligned. - * All fields are u8 or u16 except for the length. However that field is not - * used so we break it into 2 16-bit parts to easily meet our alignment needs. - */ -struct cpl_tx_pkt { - u8 opcode; -#if defined(__LITTLE_ENDIAN_BITFIELD) - u8 iff:4; - u8 ip_csum_dis:1; - u8 l4_csum_dis:1; - u8 vlan_valid:1; - u8 rsvd:1; -#else - u8 rsvd:1; - u8 vlan_valid:1; - u8 l4_csum_dis:1; - u8 ip_csum_dis:1; - u8 iff:4; -#endif - u16 vlan; - u16 len_hi; - u16 len_lo; -}; - -struct cpl_tx_pkt_lso { - u8 opcode; -#if defined(__LITTLE_ENDIAN_BITFIELD) - u8 iff:4; - u8 ip_csum_dis:1; - u8 l4_csum_dis:1; - u8 vlan_valid:1; - u8 :1; -#else - u8 :1; - u8 vlan_valid:1; - u8 l4_csum_dis:1; - u8 ip_csum_dis:1; - u8 iff:4; -#endif - u16 vlan; - __be32 len; - - u8 rsvd[5]; -#if defined(__LITTLE_ENDIAN_BITFIELD) - u8 tcp_hdr_words:4; - u8 ip_hdr_words:4; -#else - u8 ip_hdr_words:4; - u8 tcp_hdr_words:4; -#endif - __be16 eth_type_mss; -}; - -struct cpl_rx_pkt { - u8 opcode; -#if defined(__LITTLE_ENDIAN_BITFIELD) - u8 iff:4; - u8 csum_valid:1; - u8 bad_pkt:1; - u8 vlan_valid:1; - u8 rsvd:1; -#else - u8 rsvd:1; - u8 vlan_valid:1; - u8 bad_pkt:1; - u8 csum_valid:1; - u8 iff:4; -#endif - u16 csum; - u16 vlan; - u16 len; -}; - -struct cpl_l2t_write_req { - union opcode_tid ot; - u32 params; - u8 rsvd1[2]; - u8 dst_mac[6]; -}; - -struct cpl_l2t_write_rpl { - union opcode_tid ot; - u8 status; - u8 rsvd[3]; -}; - -struct cpl_l2t_read_req { - union opcode_tid ot; - u8 rsvd[3]; - u8 l2t_idx; -}; - -struct cpl_l2t_read_rpl { - union opcode_tid ot; - u32 params; - u8 rsvd1[2]; - u8 dst_mac[6]; -}; - -struct cpl_smt_write_req { - union opcode_tid ot; - u8 rsvd0; -#if defined(__LITTLE_ENDIAN_BITFIELD) - u8 rsvd1:1; - u8 mtu_idx:3; - u8 iff:4; -#else - u8 iff:4; - u8 mtu_idx:3; - u8 rsvd1:1; -#endif - u16 rsvd2; - u16 rsvd3; - u8 src_mac1[6]; - u16 rsvd4; - u8 src_mac0[6]; -}; - -struct cpl_smt_write_rpl { - union opcode_tid ot; - u8 status; - u8 rsvd[3]; -}; - -struct cpl_smt_read_req { - union opcode_tid ot; - u8 rsvd0; -#if defined(__LITTLE_ENDIAN_BITFIELD) - u8 rsvd1:4; - u8 iff:4; -#else - u8 iff:4; - u8 rsvd1:4; -#endif - u16 rsvd2; -}; - -struct cpl_smt_read_rpl { - union opcode_tid ot; - u8 status; -#if defined(__LITTLE_ENDIAN_BITFIELD) - u8 rsvd1:1; - u8 mtu_idx:3; - u8 rsvd0:4; -#else - u8 rsvd0:4; - u8 mtu_idx:3; - u8 rsvd1:1; -#endif - u16 rsvd2; - u16 rsvd3; - u8 src_mac1[6]; - u16 rsvd4; - u8 src_mac0[6]; -}; - -struct cpl_rte_delete_req { - union opcode_tid ot; - u32 params; -}; - -struct cpl_rte_delete_rpl { - union opcode_tid ot; - u8 status; - u8 rsvd[3]; -}; - -struct cpl_rte_write_req { - union opcode_tid ot; - u32 params; - u32 netmask; - u32 faddr; -}; - -struct cpl_rte_write_rpl { - union opcode_tid ot; - u8 status; - u8 rsvd[3]; -}; - -struct cpl_rte_read_req { - union opcode_tid ot; - u32 params; -}; - -struct cpl_rte_read_rpl { - union opcode_tid ot; - u8 status; - u8 rsvd0[2]; - u8 l2t_idx; -#if defined(__LITTLE_ENDIAN_BITFIELD) - u8 rsvd1:7; - u8 select:1; -#else - u8 select:1; - u8 rsvd1:7; -#endif - u8 rsvd2[3]; - u32 addr; -}; - -struct cpl_mss_change { - union opcode_tid ot; - u32 mss; -}; - -#endif /* _CXGB_CPL5_CMD_H_ */ - diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c deleted file mode 100644 index 3edbbc4c5112..000000000000 --- a/drivers/net/chelsio/cxgb2.c +++ /dev/null @@ -1,1379 +0,0 @@ -/***************************************************************************** - * * - * File: cxgb2.c * - * $Revision: 1.25 $ * - * $Date: 2005/06/22 00:43:25 $ * - * Description: * - * Chelsio 10Gb Ethernet Driver. * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * * - * http://www.chelsio.com * - * * - * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * - * All rights reserved. * - * * - * Maintainers: maintainers@chelsio.com * - * * - * Authors: Dimitrios Michailidis * - * Tina Yang * - * Felix Marti * - * Scott Bardone * - * Kurt Ottaway * - * Frank DiMambro * - * * - * History: * - * * - ****************************************************************************/ - -#include "common.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cpl5_cmd.h" -#include "regs.h" -#include "gmac.h" -#include "cphy.h" -#include "sge.h" -#include "tp.h" -#include "espi.h" -#include "elmer0.h" - -#include - -static inline void schedule_mac_stats_update(struct adapter *ap, int secs) -{ - schedule_delayed_work(&ap->stats_update_task, secs * HZ); -} - -static inline void cancel_mac_stats_update(struct adapter *ap) -{ - cancel_delayed_work(&ap->stats_update_task); -} - -#define MAX_CMDQ_ENTRIES 16384 -#define MAX_CMDQ1_ENTRIES 1024 -#define MAX_RX_BUFFERS 16384 -#define MAX_RX_JUMBO_BUFFERS 16384 -#define MAX_TX_BUFFERS_HIGH 16384U -#define MAX_TX_BUFFERS_LOW 1536U -#define MAX_TX_BUFFERS 1460U -#define MIN_FL_ENTRIES 32 - -#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \ - NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\ - NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) - -/* - * The EEPROM is actually bigger but only the first few bytes are used so we - * only report those. - */ -#define EEPROM_SIZE 32 - -MODULE_DESCRIPTION(DRV_DESCRIPTION); -MODULE_AUTHOR("Chelsio Communications"); -MODULE_LICENSE("GPL"); - -static int dflt_msg_enable = DFLT_MSG_ENABLE; - -module_param(dflt_msg_enable, int, 0); -MODULE_PARM_DESC(dflt_msg_enable, "Chelsio T1 default message enable bitmap"); - -#define HCLOCK 0x0 -#define LCLOCK 0x1 - -/* T1 cards powersave mode */ -static int t1_clock(struct adapter *adapter, int mode); -static int t1powersave = 1; /* HW default is powersave mode. */ - -module_param(t1powersave, int, 0); -MODULE_PARM_DESC(t1powersave, "Enable/Disable T1 powersaving mode"); - -static int disable_msi = 0; -module_param(disable_msi, int, 0); -MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)"); - -static const char pci_speed[][4] = { - "33", "66", "100", "133" -}; - -/* - * Setup MAC to receive the types of packets we want. - */ -static void t1_set_rxmode(struct net_device *dev) -{ - struct adapter *adapter = dev->ml_priv; - struct cmac *mac = adapter->port[dev->if_port].mac; - struct t1_rx_mode rm; - - rm.dev = dev; - mac->ops->set_rx_mode(mac, &rm); -} - -static void link_report(struct port_info *p) -{ - if (!netif_carrier_ok(p->dev)) - printk(KERN_INFO "%s: link down\n", p->dev->name); - else { - const char *s = "10Mbps"; - - switch (p->link_config.speed) { - case SPEED_10000: s = "10Gbps"; break; - case SPEED_1000: s = "1000Mbps"; break; - case SPEED_100: s = "100Mbps"; break; - } - - printk(KERN_INFO "%s: link up, %s, %s-duplex\n", - p->dev->name, s, - p->link_config.duplex == DUPLEX_FULL ? "full" : "half"); - } -} - -void t1_link_negotiated(struct adapter *adapter, int port_id, int link_stat, - int speed, int duplex, int pause) -{ - struct port_info *p = &adapter->port[port_id]; - - if (link_stat != netif_carrier_ok(p->dev)) { - if (link_stat) - netif_carrier_on(p->dev); - else - netif_carrier_off(p->dev); - link_report(p); - - /* multi-ports: inform toe */ - if ((speed > 0) && (adapter->params.nports > 1)) { - unsigned int sched_speed = 10; - switch (speed) { - case SPEED_1000: - sched_speed = 1000; - break; - case SPEED_100: - sched_speed = 100; - break; - case SPEED_10: - sched_speed = 10; - break; - } - t1_sched_update_parms(adapter->sge, port_id, 0, sched_speed); - } - } -} - -static void link_start(struct port_info *p) -{ - struct cmac *mac = p->mac; - - mac->ops->reset(mac); - if (mac->ops->macaddress_set) - mac->ops->macaddress_set(mac, p->dev->dev_addr); - t1_set_rxmode(p->dev); - t1_link_start(p->phy, mac, &p->link_config); - mac->ops->enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); -} - -static void enable_hw_csum(struct adapter *adapter) -{ - if (adapter->port[0].dev->hw_features & NETIF_F_TSO) - t1_tp_set_ip_checksum_offload(adapter->tp, 1); /* for TSO only */ - t1_tp_set_tcp_checksum_offload(adapter->tp, 1); -} - -/* - * Things to do upon first use of a card. - * This must run with the rtnl lock held. - */ -static int cxgb_up(struct adapter *adapter) -{ - int err = 0; - - if (!(adapter->flags & FULL_INIT_DONE)) { - err = t1_init_hw_modules(adapter); - if (err) - goto out_err; - - enable_hw_csum(adapter); - adapter->flags |= FULL_INIT_DONE; - } - - t1_interrupts_clear(adapter); - - adapter->params.has_msi = !disable_msi && !pci_enable_msi(adapter->pdev); - err = request_irq(adapter->pdev->irq, t1_interrupt, - adapter->params.has_msi ? 0 : IRQF_SHARED, - adapter->name, adapter); - if (err) { - if (adapter->params.has_msi) - pci_disable_msi(adapter->pdev); - - goto out_err; - } - - t1_sge_start(adapter->sge); - t1_interrupts_enable(adapter); -out_err: - return err; -} - -/* - * Release resources when all the ports have been stopped. - */ -static void cxgb_down(struct adapter *adapter) -{ - t1_sge_stop(adapter->sge); - t1_interrupts_disable(adapter); - free_irq(adapter->pdev->irq, adapter); - if (adapter->params.has_msi) - pci_disable_msi(adapter->pdev); -} - -static int cxgb_open(struct net_device *dev) -{ - int err; - struct adapter *adapter = dev->ml_priv; - int other_ports = adapter->open_device_map & PORT_MASK; - - napi_enable(&adapter->napi); - if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0) { - napi_disable(&adapter->napi); - return err; - } - - __set_bit(dev->if_port, &adapter->open_device_map); - link_start(&adapter->port[dev->if_port]); - netif_start_queue(dev); - if (!other_ports && adapter->params.stats_update_period) - schedule_mac_stats_update(adapter, - adapter->params.stats_update_period); - - t1_vlan_mode(adapter, dev->features); - return 0; -} - -static int cxgb_close(struct net_device *dev) -{ - struct adapter *adapter = dev->ml_priv; - struct port_info *p = &adapter->port[dev->if_port]; - struct cmac *mac = p->mac; - - netif_stop_queue(dev); - napi_disable(&adapter->napi); - mac->ops->disable(mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX); - netif_carrier_off(dev); - - clear_bit(dev->if_port, &adapter->open_device_map); - if (adapter->params.stats_update_period && - !(adapter->open_device_map & PORT_MASK)) { - /* Stop statistics accumulation. */ - smp_mb__after_clear_bit(); - spin_lock(&adapter->work_lock); /* sync with update task */ - spin_unlock(&adapter->work_lock); - cancel_mac_stats_update(adapter); - } - - if (!adapter->open_device_map) - cxgb_down(adapter); - return 0; -} - -static struct net_device_stats *t1_get_stats(struct net_device *dev) -{ - struct adapter *adapter = dev->ml_priv; - struct port_info *p = &adapter->port[dev->if_port]; - struct net_device_stats *ns = &p->netstats; - const struct cmac_statistics *pstats; - - /* Do a full update of the MAC stats */ - pstats = p->mac->ops->statistics_update(p->mac, - MAC_STATS_UPDATE_FULL); - - ns->tx_packets = pstats->TxUnicastFramesOK + - pstats->TxMulticastFramesOK + pstats->TxBroadcastFramesOK; - - ns->rx_packets = pstats->RxUnicastFramesOK + - pstats->RxMulticastFramesOK + pstats->RxBroadcastFramesOK; - - ns->tx_bytes = pstats->TxOctetsOK; - ns->rx_bytes = pstats->RxOctetsOK; - - ns->tx_errors = pstats->TxLateCollisions + pstats->TxLengthErrors + - pstats->TxUnderrun + pstats->TxFramesAbortedDueToXSCollisions; - ns->rx_errors = pstats->RxDataErrors + pstats->RxJabberErrors + - pstats->RxFCSErrors + pstats->RxAlignErrors + - pstats->RxSequenceErrors + pstats->RxFrameTooLongErrors + - pstats->RxSymbolErrors + pstats->RxRuntErrors; - - ns->multicast = pstats->RxMulticastFramesOK; - ns->collisions = pstats->TxTotalCollisions; - - /* detailed rx_errors */ - ns->rx_length_errors = pstats->RxFrameTooLongErrors + - pstats->RxJabberErrors; - ns->rx_over_errors = 0; - ns->rx_crc_errors = pstats->RxFCSErrors; - ns->rx_frame_errors = pstats->RxAlignErrors; - ns->rx_fifo_errors = 0; - ns->rx_missed_errors = 0; - - /* detailed tx_errors */ - ns->tx_aborted_errors = pstats->TxFramesAbortedDueToXSCollisions; - ns->tx_carrier_errors = 0; - ns->tx_fifo_errors = pstats->TxUnderrun; - ns->tx_heartbeat_errors = 0; - ns->tx_window_errors = pstats->TxLateCollisions; - return ns; -} - -static u32 get_msglevel(struct net_device *dev) -{ - struct adapter *adapter = dev->ml_priv; - - return adapter->msg_enable; -} - -static void set_msglevel(struct net_device *dev, u32 val) -{ - struct adapter *adapter = dev->ml_priv; - - adapter->msg_enable = val; -} - -static char stats_strings[][ETH_GSTRING_LEN] = { - "TxOctetsOK", - "TxOctetsBad", - "TxUnicastFramesOK", - "TxMulticastFramesOK", - "TxBroadcastFramesOK", - "TxPauseFrames", - "TxFramesWithDeferredXmissions", - "TxLateCollisions", - "TxTotalCollisions", - "TxFramesAbortedDueToXSCollisions", - "TxUnderrun", - "TxLengthErrors", - "TxInternalMACXmitError", - "TxFramesWithExcessiveDeferral", - "TxFCSErrors", - "TxJumboFramesOk", - "TxJumboOctetsOk", - - "RxOctetsOK", - "RxOctetsBad", - "RxUnicastFramesOK", - "RxMulticastFramesOK", - "RxBroadcastFramesOK", - "RxPauseFrames", - "RxFCSErrors", - "RxAlignErrors", - "RxSymbolErrors", - "RxDataErrors", - "RxSequenceErrors", - "RxRuntErrors", - "RxJabberErrors", - "RxInternalMACRcvError", - "RxInRangeLengthErrors", - "RxOutOfRangeLengthField", - "RxFrameTooLongErrors", - "RxJumboFramesOk", - "RxJumboOctetsOk", - - /* Port stats */ - "RxCsumGood", - "TxCsumOffload", - "TxTso", - "RxVlan", - "TxVlan", - "TxNeedHeadroom", - - /* Interrupt stats */ - "rx drops", - "pure_rsps", - "unhandled irqs", - "respQ_empty", - "respQ_overflow", - "freelistQ_empty", - "pkt_too_big", - "pkt_mismatch", - "cmdQ_full0", - "cmdQ_full1", - - "espi_DIP2ParityErr", - "espi_DIP4Err", - "espi_RxDrops", - "espi_TxDrops", - "espi_RxOvfl", - "espi_ParityErr" -}; - -#define T2_REGMAP_SIZE (3 * 1024) - -static int get_regs_len(struct net_device *dev) -{ - return T2_REGMAP_SIZE; -} - -static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - struct adapter *adapter = dev->ml_priv; - - strcpy(info->driver, DRV_NAME); - strcpy(info->version, DRV_VERSION); - strcpy(info->fw_version, "N/A"); - strcpy(info->bus_info, pci_name(adapter->pdev)); -} - -static int get_sset_count(struct net_device *dev, int sset) -{ - switch (sset) { - case ETH_SS_STATS: - return ARRAY_SIZE(stats_strings); - default: - return -EOPNOTSUPP; - } -} - -static void get_strings(struct net_device *dev, u32 stringset, u8 *data) -{ - if (stringset == ETH_SS_STATS) - memcpy(data, stats_strings, sizeof(stats_strings)); -} - -static void get_stats(struct net_device *dev, struct ethtool_stats *stats, - u64 *data) -{ - struct adapter *adapter = dev->ml_priv; - struct cmac *mac = adapter->port[dev->if_port].mac; - const struct cmac_statistics *s; - const struct sge_intr_counts *t; - struct sge_port_stats ss; - - s = mac->ops->statistics_update(mac, MAC_STATS_UPDATE_FULL); - t = t1_sge_get_intr_counts(adapter->sge); - t1_sge_get_port_stats(adapter->sge, dev->if_port, &ss); - - *data++ = s->TxOctetsOK; - *data++ = s->TxOctetsBad; - *data++ = s->TxUnicastFramesOK; - *data++ = s->TxMulticastFramesOK; - *data++ = s->TxBroadcastFramesOK; - *data++ = s->TxPauseFrames; - *data++ = s->TxFramesWithDeferredXmissions; - *data++ = s->TxLateCollisions; - *data++ = s->TxTotalCollisions; - *data++ = s->TxFramesAbortedDueToXSCollisions; - *data++ = s->TxUnderrun; - *data++ = s->TxLengthErrors; - *data++ = s->TxInternalMACXmitError; - *data++ = s->TxFramesWithExcessiveDeferral; - *data++ = s->TxFCSErrors; - *data++ = s->TxJumboFramesOK; - *data++ = s->TxJumboOctetsOK; - - *data++ = s->RxOctetsOK; - *data++ = s->RxOctetsBad; - *data++ = s->RxUnicastFramesOK; - *data++ = s->RxMulticastFramesOK; - *data++ = s->RxBroadcastFramesOK; - *data++ = s->RxPauseFrames; - *data++ = s->RxFCSErrors; - *data++ = s->RxAlignErrors; - *data++ = s->RxSymbolErrors; - *data++ = s->RxDataErrors; - *data++ = s->RxSequenceErrors; - *data++ = s->RxRuntErrors; - *data++ = s->RxJabberErrors; - *data++ = s->RxInternalMACRcvError; - *data++ = s->RxInRangeLengthErrors; - *data++ = s->RxOutOfRangeLengthField; - *data++ = s->RxFrameTooLongErrors; - *data++ = s->RxJumboFramesOK; - *data++ = s->RxJumboOctetsOK; - - *data++ = ss.rx_cso_good; - *data++ = ss.tx_cso; - *data++ = ss.tx_tso; - *data++ = ss.vlan_xtract; - *data++ = ss.vlan_insert; - *data++ = ss.tx_need_hdrroom; - - *data++ = t->rx_drops; - *data++ = t->pure_rsps; - *data++ = t->unhandled_irqs; - *data++ = t->respQ_empty; - *data++ = t->respQ_overflow; - *data++ = t->freelistQ_empty; - *data++ = t->pkt_too_big; - *data++ = t->pkt_mismatch; - *data++ = t->cmdQ_full[0]; - *data++ = t->cmdQ_full[1]; - - if (adapter->espi) { - const struct espi_intr_counts *e; - - e = t1_espi_get_intr_counts(adapter->espi); - *data++ = e->DIP2_parity_err; - *data++ = e->DIP4_err; - *data++ = e->rx_drops; - *data++ = e->tx_drops; - *data++ = e->rx_ovflw; - *data++ = e->parity_err; - } -} - -static inline void reg_block_dump(struct adapter *ap, void *buf, - unsigned int start, unsigned int end) -{ - u32 *p = buf + start; - - for ( ; start <= end; start += sizeof(u32)) - *p++ = readl(ap->regs + start); -} - -static void get_regs(struct net_device *dev, struct ethtool_regs *regs, - void *buf) -{ - struct adapter *ap = dev->ml_priv; - - /* - * Version scheme: bits 0..9: chip version, bits 10..15: chip revision - */ - regs->version = 2; - - memset(buf, 0, T2_REGMAP_SIZE); - reg_block_dump(ap, buf, 0, A_SG_RESPACCUTIMER); - reg_block_dump(ap, buf, A_MC3_CFG, A_MC4_INT_CAUSE); - reg_block_dump(ap, buf, A_TPI_ADDR, A_TPI_PAR); - reg_block_dump(ap, buf, A_TP_IN_CONFIG, A_TP_TX_DROP_COUNT); - reg_block_dump(ap, buf, A_RAT_ROUTE_CONTROL, A_RAT_INTR_CAUSE); - reg_block_dump(ap, buf, A_CSPI_RX_AE_WM, A_CSPI_INTR_ENABLE); - reg_block_dump(ap, buf, A_ESPI_SCH_TOKEN0, A_ESPI_GOSTAT); - reg_block_dump(ap, buf, A_ULP_ULIMIT, A_ULP_PIO_CTRL); - reg_block_dump(ap, buf, A_PL_ENABLE, A_PL_CAUSE); - reg_block_dump(ap, buf, A_MC5_CONFIG, A_MC5_MASK_WRITE_CMD); -} - -static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct adapter *adapter = dev->ml_priv; - struct port_info *p = &adapter->port[dev->if_port]; - - cmd->supported = p->link_config.supported; - cmd->advertising = p->link_config.advertising; - - if (netif_carrier_ok(dev)) { - ethtool_cmd_speed_set(cmd, p->link_config.speed); - cmd->duplex = p->link_config.duplex; - } else { - ethtool_cmd_speed_set(cmd, -1); - cmd->duplex = -1; - } - - cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE; - cmd->phy_address = p->phy->mdio.prtad; - cmd->transceiver = XCVR_EXTERNAL; - cmd->autoneg = p->link_config.autoneg; - cmd->maxtxpkt = 0; - cmd->maxrxpkt = 0; - return 0; -} - -static int speed_duplex_to_caps(int speed, int duplex) -{ - int cap = 0; - - switch (speed) { - case SPEED_10: - if (duplex == DUPLEX_FULL) - cap = SUPPORTED_10baseT_Full; - else - cap = SUPPORTED_10baseT_Half; - break; - case SPEED_100: - if (duplex == DUPLEX_FULL) - cap = SUPPORTED_100baseT_Full; - else - cap = SUPPORTED_100baseT_Half; - break; - case SPEED_1000: - if (duplex == DUPLEX_FULL) - cap = SUPPORTED_1000baseT_Full; - else - cap = SUPPORTED_1000baseT_Half; - break; - case SPEED_10000: - if (duplex == DUPLEX_FULL) - cap = SUPPORTED_10000baseT_Full; - } - return cap; -} - -#define ADVERTISED_MASK (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \ - ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \ - ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | \ - ADVERTISED_10000baseT_Full) - -static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct adapter *adapter = dev->ml_priv; - struct port_info *p = &adapter->port[dev->if_port]; - struct link_config *lc = &p->link_config; - - if (!(lc->supported & SUPPORTED_Autoneg)) - return -EOPNOTSUPP; /* can't change speed/duplex */ - - if (cmd->autoneg == AUTONEG_DISABLE) { - u32 speed = ethtool_cmd_speed(cmd); - int cap = speed_duplex_to_caps(speed, cmd->duplex); - - if (!(lc->supported & cap) || (speed == SPEED_1000)) - return -EINVAL; - lc->requested_speed = speed; - lc->requested_duplex = cmd->duplex; - lc->advertising = 0; - } else { - cmd->advertising &= ADVERTISED_MASK; - if (cmd->advertising & (cmd->advertising - 1)) - cmd->advertising = lc->supported; - cmd->advertising &= lc->supported; - if (!cmd->advertising) - return -EINVAL; - lc->requested_speed = SPEED_INVALID; - lc->requested_duplex = DUPLEX_INVALID; - lc->advertising = cmd->advertising | ADVERTISED_Autoneg; - } - lc->autoneg = cmd->autoneg; - if (netif_running(dev)) - t1_link_start(p->phy, p->mac, lc); - return 0; -} - -static void get_pauseparam(struct net_device *dev, - struct ethtool_pauseparam *epause) -{ - struct adapter *adapter = dev->ml_priv; - struct port_info *p = &adapter->port[dev->if_port]; - - epause->autoneg = (p->link_config.requested_fc & PAUSE_AUTONEG) != 0; - epause->rx_pause = (p->link_config.fc & PAUSE_RX) != 0; - epause->tx_pause = (p->link_config.fc & PAUSE_TX) != 0; -} - -static int set_pauseparam(struct net_device *dev, - struct ethtool_pauseparam *epause) -{ - struct adapter *adapter = dev->ml_priv; - struct port_info *p = &adapter->port[dev->if_port]; - struct link_config *lc = &p->link_config; - - if (epause->autoneg == AUTONEG_DISABLE) - lc->requested_fc = 0; - else if (lc->supported & SUPPORTED_Autoneg) - lc->requested_fc = PAUSE_AUTONEG; - else - return -EINVAL; - - if (epause->rx_pause) - lc->requested_fc |= PAUSE_RX; - if (epause->tx_pause) - lc->requested_fc |= PAUSE_TX; - if (lc->autoneg == AUTONEG_ENABLE) { - if (netif_running(dev)) - t1_link_start(p->phy, p->mac, lc); - } else { - lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); - if (netif_running(dev)) - p->mac->ops->set_speed_duplex_fc(p->mac, -1, -1, - lc->fc); - } - return 0; -} - -static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) -{ - struct adapter *adapter = dev->ml_priv; - int jumbo_fl = t1_is_T1B(adapter) ? 1 : 0; - - e->rx_max_pending = MAX_RX_BUFFERS; - e->rx_mini_max_pending = 0; - e->rx_jumbo_max_pending = MAX_RX_JUMBO_BUFFERS; - e->tx_max_pending = MAX_CMDQ_ENTRIES; - - e->rx_pending = adapter->params.sge.freelQ_size[!jumbo_fl]; - e->rx_mini_pending = 0; - e->rx_jumbo_pending = adapter->params.sge.freelQ_size[jumbo_fl]; - e->tx_pending = adapter->params.sge.cmdQ_size[0]; -} - -static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e) -{ - struct adapter *adapter = dev->ml_priv; - int jumbo_fl = t1_is_T1B(adapter) ? 1 : 0; - - if (e->rx_pending > MAX_RX_BUFFERS || e->rx_mini_pending || - e->rx_jumbo_pending > MAX_RX_JUMBO_BUFFERS || - e->tx_pending > MAX_CMDQ_ENTRIES || - e->rx_pending < MIN_FL_ENTRIES || - e->rx_jumbo_pending < MIN_FL_ENTRIES || - e->tx_pending < (adapter->params.nports + 1) * (MAX_SKB_FRAGS + 1)) - return -EINVAL; - - if (adapter->flags & FULL_INIT_DONE) - return -EBUSY; - - adapter->params.sge.freelQ_size[!jumbo_fl] = e->rx_pending; - adapter->params.sge.freelQ_size[jumbo_fl] = e->rx_jumbo_pending; - adapter->params.sge.cmdQ_size[0] = e->tx_pending; - adapter->params.sge.cmdQ_size[1] = e->tx_pending > MAX_CMDQ1_ENTRIES ? - MAX_CMDQ1_ENTRIES : e->tx_pending; - return 0; -} - -static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c) -{ - struct adapter *adapter = dev->ml_priv; - - adapter->params.sge.rx_coalesce_usecs = c->rx_coalesce_usecs; - adapter->params.sge.coalesce_enable = c->use_adaptive_rx_coalesce; - adapter->params.sge.sample_interval_usecs = c->rate_sample_interval; - t1_sge_set_coalesce_params(adapter->sge, &adapter->params.sge); - return 0; -} - -static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c) -{ - struct adapter *adapter = dev->ml_priv; - - c->rx_coalesce_usecs = adapter->params.sge.rx_coalesce_usecs; - c->rate_sample_interval = adapter->params.sge.sample_interval_usecs; - c->use_adaptive_rx_coalesce = adapter->params.sge.coalesce_enable; - return 0; -} - -static int get_eeprom_len(struct net_device *dev) -{ - struct adapter *adapter = dev->ml_priv; - - return t1_is_asic(adapter) ? EEPROM_SIZE : 0; -} - -#define EEPROM_MAGIC(ap) \ - (PCI_VENDOR_ID_CHELSIO | ((ap)->params.chip_version << 16)) - -static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e, - u8 *data) -{ - int i; - u8 buf[EEPROM_SIZE] __attribute__((aligned(4))); - struct adapter *adapter = dev->ml_priv; - - e->magic = EEPROM_MAGIC(adapter); - for (i = e->offset & ~3; i < e->offset + e->len; i += sizeof(u32)) - t1_seeprom_read(adapter, i, (__le32 *)&buf[i]); - memcpy(data, buf + e->offset, e->len); - return 0; -} - -static const struct ethtool_ops t1_ethtool_ops = { - .get_settings = get_settings, - .set_settings = set_settings, - .get_drvinfo = get_drvinfo, - .get_msglevel = get_msglevel, - .set_msglevel = set_msglevel, - .get_ringparam = get_sge_param, - .set_ringparam = set_sge_param, - .get_coalesce = get_coalesce, - .set_coalesce = set_coalesce, - .get_eeprom_len = get_eeprom_len, - .get_eeprom = get_eeprom, - .get_pauseparam = get_pauseparam, - .set_pauseparam = set_pauseparam, - .get_link = ethtool_op_get_link, - .get_strings = get_strings, - .get_sset_count = get_sset_count, - .get_ethtool_stats = get_stats, - .get_regs_len = get_regs_len, - .get_regs = get_regs, -}; - -static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd) -{ - struct adapter *adapter = dev->ml_priv; - struct mdio_if_info *mdio = &adapter->port[dev->if_port].phy->mdio; - - return mdio_mii_ioctl(mdio, if_mii(req), cmd); -} - -static int t1_change_mtu(struct net_device *dev, int new_mtu) -{ - int ret; - struct adapter *adapter = dev->ml_priv; - struct cmac *mac = adapter->port[dev->if_port].mac; - - if (!mac->ops->set_mtu) - return -EOPNOTSUPP; - if (new_mtu < 68) - return -EINVAL; - if ((ret = mac->ops->set_mtu(mac, new_mtu))) - return ret; - dev->mtu = new_mtu; - return 0; -} - -static int t1_set_mac_addr(struct net_device *dev, void *p) -{ - struct adapter *adapter = dev->ml_priv; - struct cmac *mac = adapter->port[dev->if_port].mac; - struct sockaddr *addr = p; - - if (!mac->ops->macaddress_set) - return -EOPNOTSUPP; - - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - mac->ops->macaddress_set(mac, dev->dev_addr); - return 0; -} - -static u32 t1_fix_features(struct net_device *dev, u32 features) -{ - /* - * Since there is no support for separate rx/tx vlan accel - * enable/disable make sure tx flag is always in same state as rx. - */ - if (features & NETIF_F_HW_VLAN_RX) - features |= NETIF_F_HW_VLAN_TX; - else - features &= ~NETIF_F_HW_VLAN_TX; - - return features; -} - -static int t1_set_features(struct net_device *dev, u32 features) -{ - u32 changed = dev->features ^ features; - struct adapter *adapter = dev->ml_priv; - - if (changed & NETIF_F_HW_VLAN_RX) - t1_vlan_mode(adapter, features); - - return 0; -} -#ifdef CONFIG_NET_POLL_CONTROLLER -static void t1_netpoll(struct net_device *dev) -{ - unsigned long flags; - struct adapter *adapter = dev->ml_priv; - - local_irq_save(flags); - t1_interrupt(adapter->pdev->irq, adapter); - local_irq_restore(flags); -} -#endif - -/* - * Periodic accumulation of MAC statistics. This is used only if the MAC - * does not have any other way to prevent stats counter overflow. - */ -static void mac_stats_task(struct work_struct *work) -{ - int i; - struct adapter *adapter = - container_of(work, struct adapter, stats_update_task.work); - - for_each_port(adapter, i) { - struct port_info *p = &adapter->port[i]; - - if (netif_running(p->dev)) - p->mac->ops->statistics_update(p->mac, - MAC_STATS_UPDATE_FAST); - } - - /* Schedule the next statistics update if any port is active. */ - spin_lock(&adapter->work_lock); - if (adapter->open_device_map & PORT_MASK) - schedule_mac_stats_update(adapter, - adapter->params.stats_update_period); - spin_unlock(&adapter->work_lock); -} - -/* - * Processes elmer0 external interrupts in process context. - */ -static void ext_intr_task(struct work_struct *work) -{ - struct adapter *adapter = - container_of(work, struct adapter, ext_intr_handler_task); - - t1_elmer0_ext_intr_handler(adapter); - - /* Now reenable external interrupts */ - spin_lock_irq(&adapter->async_lock); - adapter->slow_intr_mask |= F_PL_INTR_EXT; - writel(F_PL_INTR_EXT, adapter->regs + A_PL_CAUSE); - writel(adapter->slow_intr_mask | F_PL_INTR_SGE_DATA, - adapter->regs + A_PL_ENABLE); - spin_unlock_irq(&adapter->async_lock); -} - -/* - * Interrupt-context handler for elmer0 external interrupts. - */ -void t1_elmer0_ext_intr(struct adapter *adapter) -{ - /* - * Schedule a task to handle external interrupts as we require - * a process context. We disable EXT interrupts in the interim - * and let the task reenable them when it's done. - */ - adapter->slow_intr_mask &= ~F_PL_INTR_EXT; - writel(adapter->slow_intr_mask | F_PL_INTR_SGE_DATA, - adapter->regs + A_PL_ENABLE); - schedule_work(&adapter->ext_intr_handler_task); -} - -void t1_fatal_err(struct adapter *adapter) -{ - if (adapter->flags & FULL_INIT_DONE) { - t1_sge_stop(adapter->sge); - t1_interrupts_disable(adapter); - } - pr_alert("%s: encountered fatal error, operation suspended\n", - adapter->name); -} - -static const struct net_device_ops cxgb_netdev_ops = { - .ndo_open = cxgb_open, - .ndo_stop = cxgb_close, - .ndo_start_xmit = t1_start_xmit, - .ndo_get_stats = t1_get_stats, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_multicast_list = t1_set_rxmode, - .ndo_do_ioctl = t1_ioctl, - .ndo_change_mtu = t1_change_mtu, - .ndo_set_mac_address = t1_set_mac_addr, - .ndo_fix_features = t1_fix_features, - .ndo_set_features = t1_set_features, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = t1_netpoll, -#endif -}; - -static int __devinit init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - static int version_printed; - - int i, err, pci_using_dac = 0; - unsigned long mmio_start, mmio_len; - const struct board_info *bi; - struct adapter *adapter = NULL; - struct port_info *pi; - - if (!version_printed) { - printk(KERN_INFO "%s - version %s\n", DRV_DESCRIPTION, - DRV_VERSION); - ++version_printed; - } - - err = pci_enable_device(pdev); - if (err) - return err; - - if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { - pr_err("%s: cannot find PCI device memory base address\n", - pci_name(pdev)); - err = -ENODEV; - goto out_disable_pdev; - } - - if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { - pci_using_dac = 1; - - if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) { - pr_err("%s: unable to obtain 64-bit DMA for " - "consistent allocations\n", pci_name(pdev)); - err = -ENODEV; - goto out_disable_pdev; - } - - } else if ((err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) != 0) { - pr_err("%s: no usable DMA configuration\n", pci_name(pdev)); - goto out_disable_pdev; - } - - err = pci_request_regions(pdev, DRV_NAME); - if (err) { - pr_err("%s: cannot obtain PCI resources\n", pci_name(pdev)); - goto out_disable_pdev; - } - - pci_set_master(pdev); - - mmio_start = pci_resource_start(pdev, 0); - mmio_len = pci_resource_len(pdev, 0); - bi = t1_get_board_info(ent->driver_data); - - for (i = 0; i < bi->port_number; ++i) { - struct net_device *netdev; - - netdev = alloc_etherdev(adapter ? 0 : sizeof(*adapter)); - if (!netdev) { - err = -ENOMEM; - goto out_free_dev; - } - - SET_NETDEV_DEV(netdev, &pdev->dev); - - if (!adapter) { - adapter = netdev_priv(netdev); - adapter->pdev = pdev; - adapter->port[0].dev = netdev; /* so we don't leak it */ - - adapter->regs = ioremap(mmio_start, mmio_len); - if (!adapter->regs) { - pr_err("%s: cannot map device registers\n", - pci_name(pdev)); - err = -ENOMEM; - goto out_free_dev; - } - - if (t1_get_board_rev(adapter, bi, &adapter->params)) { - err = -ENODEV; /* Can't handle this chip rev */ - goto out_free_dev; - } - - adapter->name = pci_name(pdev); - adapter->msg_enable = dflt_msg_enable; - adapter->mmio_len = mmio_len; - - spin_lock_init(&adapter->tpi_lock); - spin_lock_init(&adapter->work_lock); - spin_lock_init(&adapter->async_lock); - spin_lock_init(&adapter->mac_lock); - - INIT_WORK(&adapter->ext_intr_handler_task, - ext_intr_task); - INIT_DELAYED_WORK(&adapter->stats_update_task, - mac_stats_task); - - pci_set_drvdata(pdev, netdev); - } - - pi = &adapter->port[i]; - pi->dev = netdev; - netif_carrier_off(netdev); - netdev->irq = pdev->irq; - netdev->if_port = i; - netdev->mem_start = mmio_start; - netdev->mem_end = mmio_start + mmio_len - 1; - netdev->ml_priv = adapter; - netdev->hw_features |= NETIF_F_SG | NETIF_F_IP_CSUM | - NETIF_F_RXCSUM; - netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | - NETIF_F_RXCSUM | NETIF_F_LLTX; - - if (pci_using_dac) - netdev->features |= NETIF_F_HIGHDMA; - if (vlan_tso_capable(adapter)) { - netdev->features |= - NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - netdev->hw_features |= NETIF_F_HW_VLAN_RX; - - /* T204: disable TSO */ - if (!(is_T2(adapter)) || bi->port_number != 4) { - netdev->hw_features |= NETIF_F_TSO; - netdev->features |= NETIF_F_TSO; - } - } - - netdev->netdev_ops = &cxgb_netdev_ops; - netdev->hard_header_len += (netdev->hw_features & NETIF_F_TSO) ? - sizeof(struct cpl_tx_pkt_lso) : sizeof(struct cpl_tx_pkt); - - netif_napi_add(netdev, &adapter->napi, t1_poll, 64); - - SET_ETHTOOL_OPS(netdev, &t1_ethtool_ops); - } - - if (t1_init_sw_modules(adapter, bi) < 0) { - err = -ENODEV; - goto out_free_dev; - } - - /* - * The card is now ready to go. If any errors occur during device - * registration we do not fail the whole card but rather proceed only - * with the ports we manage to register successfully. However we must - * register at least one net device. - */ - for (i = 0; i < bi->port_number; ++i) { - err = register_netdev(adapter->port[i].dev); - if (err) - pr_warning("%s: cannot register net device %s, skipping\n", - pci_name(pdev), adapter->port[i].dev->name); - else { - /* - * Change the name we use for messages to the name of - * the first successfully registered interface. - */ - if (!adapter->registered_device_map) - adapter->name = adapter->port[i].dev->name; - - __set_bit(i, &adapter->registered_device_map); - } - } - if (!adapter->registered_device_map) { - pr_err("%s: could not register any net devices\n", - pci_name(pdev)); - goto out_release_adapter_res; - } - - printk(KERN_INFO "%s: %s (rev %d), %s %dMHz/%d-bit\n", adapter->name, - bi->desc, adapter->params.chip_revision, - adapter->params.pci.is_pcix ? "PCIX" : "PCI", - adapter->params.pci.speed, adapter->params.pci.width); - - /* - * Set the T1B ASIC and memory clocks. - */ - if (t1powersave) - adapter->t1powersave = LCLOCK; /* HW default is powersave mode. */ - else - adapter->t1powersave = HCLOCK; - if (t1_is_T1B(adapter)) - t1_clock(adapter, t1powersave); - - return 0; - -out_release_adapter_res: - t1_free_sw_modules(adapter); -out_free_dev: - if (adapter) { - if (adapter->regs) - iounmap(adapter->regs); - for (i = bi->port_number - 1; i >= 0; --i) - if (adapter->port[i].dev) - free_netdev(adapter->port[i].dev); - } - pci_release_regions(pdev); -out_disable_pdev: - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - return err; -} - -static void bit_bang(struct adapter *adapter, int bitdata, int nbits) -{ - int data; - int i; - u32 val; - - enum { - S_CLOCK = 1 << 3, - S_DATA = 1 << 4 - }; - - for (i = (nbits - 1); i > -1; i--) { - - udelay(50); - - data = ((bitdata >> i) & 0x1); - __t1_tpi_read(adapter, A_ELMER0_GPO, &val); - - if (data) - val |= S_DATA; - else - val &= ~S_DATA; - - udelay(50); - - /* Set SCLOCK low */ - val &= ~S_CLOCK; - __t1_tpi_write(adapter, A_ELMER0_GPO, val); - - udelay(50); - - /* Write SCLOCK high */ - val |= S_CLOCK; - __t1_tpi_write(adapter, A_ELMER0_GPO, val); - - } -} - -static int t1_clock(struct adapter *adapter, int mode) -{ - u32 val; - int M_CORE_VAL; - int M_MEM_VAL; - - enum { - M_CORE_BITS = 9, - T_CORE_VAL = 0, - T_CORE_BITS = 2, - N_CORE_VAL = 0, - N_CORE_BITS = 2, - M_MEM_BITS = 9, - T_MEM_VAL = 0, - T_MEM_BITS = 2, - N_MEM_VAL = 0, - N_MEM_BITS = 2, - NP_LOAD = 1 << 17, - S_LOAD_MEM = 1 << 5, - S_LOAD_CORE = 1 << 6, - S_CLOCK = 1 << 3 - }; - - if (!t1_is_T1B(adapter)) - return -ENODEV; /* Can't re-clock this chip. */ - - if (mode & 2) - return 0; /* show current mode. */ - - if ((adapter->t1powersave & 1) == (mode & 1)) - return -EALREADY; /* ASIC already running in mode. */ - - if ((mode & 1) == HCLOCK) { - M_CORE_VAL = 0x14; - M_MEM_VAL = 0x18; - adapter->t1powersave = HCLOCK; /* overclock */ - } else { - M_CORE_VAL = 0xe; - M_MEM_VAL = 0x10; - adapter->t1powersave = LCLOCK; /* underclock */ - } - - /* Don't interrupt this serial stream! */ - spin_lock(&adapter->tpi_lock); - - /* Initialize for ASIC core */ - __t1_tpi_read(adapter, A_ELMER0_GPO, &val); - val |= NP_LOAD; - udelay(50); - __t1_tpi_write(adapter, A_ELMER0_GPO, val); - udelay(50); - __t1_tpi_read(adapter, A_ELMER0_GPO, &val); - val &= ~S_LOAD_CORE; - val &= ~S_CLOCK; - __t1_tpi_write(adapter, A_ELMER0_GPO, val); - udelay(50); - - /* Serial program the ASIC clock synthesizer */ - bit_bang(adapter, T_CORE_VAL, T_CORE_BITS); - bit_bang(adapter, N_CORE_VAL, N_CORE_BITS); - bit_bang(adapter, M_CORE_VAL, M_CORE_BITS); - udelay(50); - - /* Finish ASIC core */ - __t1_tpi_read(adapter, A_ELMER0_GPO, &val); - val |= S_LOAD_CORE; - udelay(50); - __t1_tpi_write(adapter, A_ELMER0_GPO, val); - udelay(50); - __t1_tpi_read(adapter, A_ELMER0_GPO, &val); - val &= ~S_LOAD_CORE; - udelay(50); - __t1_tpi_write(adapter, A_ELMER0_GPO, val); - udelay(50); - - /* Initialize for memory */ - __t1_tpi_read(adapter, A_ELMER0_GPO, &val); - val |= NP_LOAD; - udelay(50); - __t1_tpi_write(adapter, A_ELMER0_GPO, val); - udelay(50); - __t1_tpi_read(adapter, A_ELMER0_GPO, &val); - val &= ~S_LOAD_MEM; - val &= ~S_CLOCK; - udelay(50); - __t1_tpi_write(adapter, A_ELMER0_GPO, val); - udelay(50); - - /* Serial program the memory clock synthesizer */ - bit_bang(adapter, T_MEM_VAL, T_MEM_BITS); - bit_bang(adapter, N_MEM_VAL, N_MEM_BITS); - bit_bang(adapter, M_MEM_VAL, M_MEM_BITS); - udelay(50); - - /* Finish memory */ - __t1_tpi_read(adapter, A_ELMER0_GPO, &val); - val |= S_LOAD_MEM; - udelay(50); - __t1_tpi_write(adapter, A_ELMER0_GPO, val); - udelay(50); - __t1_tpi_read(adapter, A_ELMER0_GPO, &val); - val &= ~S_LOAD_MEM; - udelay(50); - __t1_tpi_write(adapter, A_ELMER0_GPO, val); - - spin_unlock(&adapter->tpi_lock); - - return 0; -} - -static inline void t1_sw_reset(struct pci_dev *pdev) -{ - pci_write_config_dword(pdev, A_PCICFG_PM_CSR, 3); - pci_write_config_dword(pdev, A_PCICFG_PM_CSR, 0); -} - -static void __devexit remove_one(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct adapter *adapter = dev->ml_priv; - int i; - - for_each_port(adapter, i) { - if (test_bit(i, &adapter->registered_device_map)) - unregister_netdev(adapter->port[i].dev); - } - - t1_free_sw_modules(adapter); - iounmap(adapter->regs); - - while (--i >= 0) { - if (adapter->port[i].dev) - free_netdev(adapter->port[i].dev); - } - - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - t1_sw_reset(pdev); -} - -static struct pci_driver driver = { - .name = DRV_NAME, - .id_table = t1_pci_tbl, - .probe = init_one, - .remove = __devexit_p(remove_one), -}; - -static int __init t1_init_module(void) -{ - return pci_register_driver(&driver); -} - -static void __exit t1_cleanup_module(void) -{ - pci_unregister_driver(&driver); -} - -module_init(t1_init_module); -module_exit(t1_cleanup_module); diff --git a/drivers/net/chelsio/elmer0.h b/drivers/net/chelsio/elmer0.h deleted file mode 100644 index eef655c827d9..000000000000 --- a/drivers/net/chelsio/elmer0.h +++ /dev/null @@ -1,158 +0,0 @@ -/***************************************************************************** - * * - * File: elmer0.h * - * $Revision: 1.6 $ * - * $Date: 2005/06/21 22:49:43 $ * - * Description: * - * part of the Chelsio 10Gb Ethernet Driver. * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * * - * http://www.chelsio.com * - * * - * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * - * All rights reserved. * - * * - * Maintainers: maintainers@chelsio.com * - * * - * Authors: Dimitrios Michailidis * - * Tina Yang * - * Felix Marti * - * Scott Bardone * - * Kurt Ottaway * - * Frank DiMambro * - * * - * History: * - * * - ****************************************************************************/ - -#ifndef _CXGB_ELMER0_H_ -#define _CXGB_ELMER0_H_ - -/* ELMER0 flavors */ -enum { - ELMER0_XC2S300E_6FT256_C, - ELMER0_XC2S100E_6TQ144_C -}; - -/* ELMER0 registers */ -#define A_ELMER0_VERSION 0x100000 -#define A_ELMER0_PHY_CFG 0x100004 -#define A_ELMER0_INT_ENABLE 0x100008 -#define A_ELMER0_INT_CAUSE 0x10000c -#define A_ELMER0_GPI_CFG 0x100010 -#define A_ELMER0_GPI_STAT 0x100014 -#define A_ELMER0_GPO 0x100018 -#define A_ELMER0_PORT0_MI1_CFG 0x400000 - -#define S_MI1_MDI_ENABLE 0 -#define V_MI1_MDI_ENABLE(x) ((x) << S_MI1_MDI_ENABLE) -#define F_MI1_MDI_ENABLE V_MI1_MDI_ENABLE(1U) - -#define S_MI1_MDI_INVERT 1 -#define V_MI1_MDI_INVERT(x) ((x) << S_MI1_MDI_INVERT) -#define F_MI1_MDI_INVERT V_MI1_MDI_INVERT(1U) - -#define S_MI1_PREAMBLE_ENABLE 2 -#define V_MI1_PREAMBLE_ENABLE(x) ((x) << S_MI1_PREAMBLE_ENABLE) -#define F_MI1_PREAMBLE_ENABLE V_MI1_PREAMBLE_ENABLE(1U) - -#define S_MI1_SOF 3 -#define M_MI1_SOF 0x3 -#define V_MI1_SOF(x) ((x) << S_MI1_SOF) -#define G_MI1_SOF(x) (((x) >> S_MI1_SOF) & M_MI1_SOF) - -#define S_MI1_CLK_DIV 5 -#define M_MI1_CLK_DIV 0xff -#define V_MI1_CLK_DIV(x) ((x) << S_MI1_CLK_DIV) -#define G_MI1_CLK_DIV(x) (((x) >> S_MI1_CLK_DIV) & M_MI1_CLK_DIV) - -#define A_ELMER0_PORT0_MI1_ADDR 0x400004 - -#define S_MI1_REG_ADDR 0 -#define M_MI1_REG_ADDR 0x1f -#define V_MI1_REG_ADDR(x) ((x) << S_MI1_REG_ADDR) -#define G_MI1_REG_ADDR(x) (((x) >> S_MI1_REG_ADDR) & M_MI1_REG_ADDR) - -#define S_MI1_PHY_ADDR 5 -#define M_MI1_PHY_ADDR 0x1f -#define V_MI1_PHY_ADDR(x) ((x) << S_MI1_PHY_ADDR) -#define G_MI1_PHY_ADDR(x) (((x) >> S_MI1_PHY_ADDR) & M_MI1_PHY_ADDR) - -#define A_ELMER0_PORT0_MI1_DATA 0x400008 - -#define S_MI1_DATA 0 -#define M_MI1_DATA 0xffff -#define V_MI1_DATA(x) ((x) << S_MI1_DATA) -#define G_MI1_DATA(x) (((x) >> S_MI1_DATA) & M_MI1_DATA) - -#define A_ELMER0_PORT0_MI1_OP 0x40000c - -#define S_MI1_OP 0 -#define M_MI1_OP 0x3 -#define V_MI1_OP(x) ((x) << S_MI1_OP) -#define G_MI1_OP(x) (((x) >> S_MI1_OP) & M_MI1_OP) - -#define S_MI1_ADDR_AUTOINC 2 -#define V_MI1_ADDR_AUTOINC(x) ((x) << S_MI1_ADDR_AUTOINC) -#define F_MI1_ADDR_AUTOINC V_MI1_ADDR_AUTOINC(1U) - -#define S_MI1_OP_BUSY 31 -#define V_MI1_OP_BUSY(x) ((x) << S_MI1_OP_BUSY) -#define F_MI1_OP_BUSY V_MI1_OP_BUSY(1U) - -#define A_ELMER0_PORT1_MI1_CFG 0x500000 -#define A_ELMER0_PORT1_MI1_ADDR 0x500004 -#define A_ELMER0_PORT1_MI1_DATA 0x500008 -#define A_ELMER0_PORT1_MI1_OP 0x50000c -#define A_ELMER0_PORT2_MI1_CFG 0x600000 -#define A_ELMER0_PORT2_MI1_ADDR 0x600004 -#define A_ELMER0_PORT2_MI1_DATA 0x600008 -#define A_ELMER0_PORT2_MI1_OP 0x60000c -#define A_ELMER0_PORT3_MI1_CFG 0x700000 -#define A_ELMER0_PORT3_MI1_ADDR 0x700004 -#define A_ELMER0_PORT3_MI1_DATA 0x700008 -#define A_ELMER0_PORT3_MI1_OP 0x70000c - -/* Simple bit definition for GPI and GP0 registers. */ -#define ELMER0_GP_BIT0 0x0001 -#define ELMER0_GP_BIT1 0x0002 -#define ELMER0_GP_BIT2 0x0004 -#define ELMER0_GP_BIT3 0x0008 -#define ELMER0_GP_BIT4 0x0010 -#define ELMER0_GP_BIT5 0x0020 -#define ELMER0_GP_BIT6 0x0040 -#define ELMER0_GP_BIT7 0x0080 -#define ELMER0_GP_BIT8 0x0100 -#define ELMER0_GP_BIT9 0x0200 -#define ELMER0_GP_BIT10 0x0400 -#define ELMER0_GP_BIT11 0x0800 -#define ELMER0_GP_BIT12 0x1000 -#define ELMER0_GP_BIT13 0x2000 -#define ELMER0_GP_BIT14 0x4000 -#define ELMER0_GP_BIT15 0x8000 -#define ELMER0_GP_BIT16 0x10000 -#define ELMER0_GP_BIT17 0x20000 -#define ELMER0_GP_BIT18 0x40000 -#define ELMER0_GP_BIT19 0x80000 - -#define MI1_OP_DIRECT_WRITE 1 -#define MI1_OP_DIRECT_READ 2 - -#define MI1_OP_INDIRECT_ADDRESS 0 -#define MI1_OP_INDIRECT_WRITE 1 -#define MI1_OP_INDIRECT_READ_INC 2 -#define MI1_OP_INDIRECT_READ 3 - -#endif /* _CXGB_ELMER0_H_ */ - diff --git a/drivers/net/chelsio/espi.c b/drivers/net/chelsio/espi.c deleted file mode 100644 index 639ff1955739..000000000000 --- a/drivers/net/chelsio/espi.c +++ /dev/null @@ -1,373 +0,0 @@ -/***************************************************************************** - * * - * File: espi.c * - * $Revision: 1.14 $ * - * $Date: 2005/05/14 00:59:32 $ * - * Description: * - * Ethernet SPI functionality. * - * part of the Chelsio 10Gb Ethernet Driver. * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * * - * http://www.chelsio.com * - * * - * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * - * All rights reserved. * - * * - * Maintainers: maintainers@chelsio.com * - * * - * Authors: Dimitrios Michailidis * - * Tina Yang * - * Felix Marti * - * Scott Bardone * - * Kurt Ottaway * - * Frank DiMambro * - * * - * History: * - * * - ****************************************************************************/ - -#include "common.h" -#include "regs.h" -#include "espi.h" - -struct peespi { - adapter_t *adapter; - struct espi_intr_counts intr_cnt; - u32 misc_ctrl; - spinlock_t lock; -}; - -#define ESPI_INTR_MASK (F_DIP4ERR | F_RXDROP | F_TXDROP | F_RXOVERFLOW | \ - F_RAMPARITYERR | F_DIP2PARITYERR) -#define MON_MASK (V_MONITORED_PORT_NUM(3) | F_MONITORED_DIRECTION \ - | F_MONITORED_INTERFACE) - -#define TRICN_CNFG 14 -#define TRICN_CMD_READ 0x11 -#define TRICN_CMD_WRITE 0x21 -#define TRICN_CMD_ATTEMPTS 10 - -static int tricn_write(adapter_t *adapter, int bundle_addr, int module_addr, - int ch_addr, int reg_offset, u32 wr_data) -{ - int busy, attempts = TRICN_CMD_ATTEMPTS; - - writel(V_WRITE_DATA(wr_data) | - V_REGISTER_OFFSET(reg_offset) | - V_CHANNEL_ADDR(ch_addr) | V_MODULE_ADDR(module_addr) | - V_BUNDLE_ADDR(bundle_addr) | - V_SPI4_COMMAND(TRICN_CMD_WRITE), - adapter->regs + A_ESPI_CMD_ADDR); - writel(0, adapter->regs + A_ESPI_GOSTAT); - - do { - busy = readl(adapter->regs + A_ESPI_GOSTAT) & F_ESPI_CMD_BUSY; - } while (busy && --attempts); - - if (busy) - pr_err("%s: TRICN write timed out\n", adapter->name); - - return busy; -} - -static int tricn_init(adapter_t *adapter) -{ - int i, sme = 1; - - if (!(readl(adapter->regs + A_ESPI_RX_RESET) & F_RX_CLK_STATUS)) { - pr_err("%s: ESPI clock not ready\n", adapter->name); - return -1; - } - - writel(F_ESPI_RX_CORE_RST, adapter->regs + A_ESPI_RX_RESET); - - if (sme) { - tricn_write(adapter, 0, 0, 0, TRICN_CNFG, 0x81); - tricn_write(adapter, 0, 1, 0, TRICN_CNFG, 0x81); - tricn_write(adapter, 0, 2, 0, TRICN_CNFG, 0x81); - } - for (i = 1; i <= 8; i++) - tricn_write(adapter, 0, 0, i, TRICN_CNFG, 0xf1); - for (i = 1; i <= 2; i++) - tricn_write(adapter, 0, 1, i, TRICN_CNFG, 0xf1); - for (i = 1; i <= 3; i++) - tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xe1); - tricn_write(adapter, 0, 2, 4, TRICN_CNFG, 0xf1); - tricn_write(adapter, 0, 2, 5, TRICN_CNFG, 0xe1); - tricn_write(adapter, 0, 2, 6, TRICN_CNFG, 0xf1); - tricn_write(adapter, 0, 2, 7, TRICN_CNFG, 0x80); - tricn_write(adapter, 0, 2, 8, TRICN_CNFG, 0xf1); - - writel(F_ESPI_RX_CORE_RST | F_ESPI_RX_LNK_RST, - adapter->regs + A_ESPI_RX_RESET); - - return 0; -} - -void t1_espi_intr_enable(struct peespi *espi) -{ - u32 enable, pl_intr = readl(espi->adapter->regs + A_PL_ENABLE); - - /* - * Cannot enable ESPI interrupts on T1B because HW asserts the - * interrupt incorrectly, namely the driver gets ESPI interrupts - * but no data is actually dropped (can verify this reading the ESPI - * drop registers). Also, once the ESPI interrupt is asserted it - * cannot be cleared (HW bug). - */ - enable = t1_is_T1B(espi->adapter) ? 0 : ESPI_INTR_MASK; - writel(enable, espi->adapter->regs + A_ESPI_INTR_ENABLE); - writel(pl_intr | F_PL_INTR_ESPI, espi->adapter->regs + A_PL_ENABLE); -} - -void t1_espi_intr_clear(struct peespi *espi) -{ - readl(espi->adapter->regs + A_ESPI_DIP2_ERR_COUNT); - writel(0xffffffff, espi->adapter->regs + A_ESPI_INTR_STATUS); - writel(F_PL_INTR_ESPI, espi->adapter->regs + A_PL_CAUSE); -} - -void t1_espi_intr_disable(struct peespi *espi) -{ - u32 pl_intr = readl(espi->adapter->regs + A_PL_ENABLE); - - writel(0, espi->adapter->regs + A_ESPI_INTR_ENABLE); - writel(pl_intr & ~F_PL_INTR_ESPI, espi->adapter->regs + A_PL_ENABLE); -} - -int t1_espi_intr_handler(struct peespi *espi) -{ - u32 status = readl(espi->adapter->regs + A_ESPI_INTR_STATUS); - - if (status & F_DIP4ERR) - espi->intr_cnt.DIP4_err++; - if (status & F_RXDROP) - espi->intr_cnt.rx_drops++; - if (status & F_TXDROP) - espi->intr_cnt.tx_drops++; - if (status & F_RXOVERFLOW) - espi->intr_cnt.rx_ovflw++; - if (status & F_RAMPARITYERR) - espi->intr_cnt.parity_err++; - if (status & F_DIP2PARITYERR) { - espi->intr_cnt.DIP2_parity_err++; - - /* - * Must read the error count to clear the interrupt - * that it causes. - */ - readl(espi->adapter->regs + A_ESPI_DIP2_ERR_COUNT); - } - - /* - * For T1B we need to write 1 to clear ESPI interrupts. For T2+ we - * write the status as is. - */ - if (status && t1_is_T1B(espi->adapter)) - status = 1; - writel(status, espi->adapter->regs + A_ESPI_INTR_STATUS); - return 0; -} - -const struct espi_intr_counts *t1_espi_get_intr_counts(struct peespi *espi) -{ - return &espi->intr_cnt; -} - -static void espi_setup_for_pm3393(adapter_t *adapter) -{ - u32 wmark = t1_is_T1B(adapter) ? 0x4000 : 0x3200; - - writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0); - writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN1); - writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2); - writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN3); - writel(0x100, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK); - writel(wmark, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK); - writel(3, adapter->regs + A_ESPI_CALENDAR_LENGTH); - writel(0x08000008, adapter->regs + A_ESPI_TRAIN); - writel(V_RX_NPORTS(1) | V_TX_NPORTS(1), adapter->regs + A_PORT_CONFIG); -} - -static void espi_setup_for_vsc7321(adapter_t *adapter) -{ - writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0); - writel(0x1f401f4, adapter->regs + A_ESPI_SCH_TOKEN1); - writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2); - writel(0xa00, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK); - writel(0x1ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK); - writel(1, adapter->regs + A_ESPI_CALENDAR_LENGTH); - writel(V_RX_NPORTS(4) | V_TX_NPORTS(4), adapter->regs + A_PORT_CONFIG); - - writel(0x08000008, adapter->regs + A_ESPI_TRAIN); -} - -/* - * Note that T1B requires at least 2 ports for IXF1010 due to a HW bug. - */ -static void espi_setup_for_ixf1010(adapter_t *adapter, int nports) -{ - writel(1, adapter->regs + A_ESPI_CALENDAR_LENGTH); - if (nports == 4) { - if (is_T2(adapter)) { - writel(0xf00, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK); - writel(0x3c0, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK); - } else { - writel(0x7ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK); - writel(0x1ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK); - } - } else { - writel(0x1fff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK); - writel(0x7ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK); - } - writel(V_RX_NPORTS(nports) | V_TX_NPORTS(nports), adapter->regs + A_PORT_CONFIG); - -} - -int t1_espi_init(struct peespi *espi, int mac_type, int nports) -{ - u32 status_enable_extra = 0; - adapter_t *adapter = espi->adapter; - - /* Disable ESPI training. MACs that can handle it enable it below. */ - writel(0, adapter->regs + A_ESPI_TRAIN); - - if (is_T2(adapter)) { - writel(V_OUT_OF_SYNC_COUNT(4) | - V_DIP2_PARITY_ERR_THRES(3) | - V_DIP4_THRES(1), adapter->regs + A_ESPI_MISC_CONTROL); - writel(nports == 4 ? 0x200040 : 0x1000080, - adapter->regs + A_ESPI_MAXBURST1_MAXBURST2); - } else - writel(0x800100, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2); - - if (mac_type == CHBT_MAC_PM3393) - espi_setup_for_pm3393(adapter); - else if (mac_type == CHBT_MAC_VSC7321) - espi_setup_for_vsc7321(adapter); - else if (mac_type == CHBT_MAC_IXF1010) { - status_enable_extra = F_INTEL1010MODE; - espi_setup_for_ixf1010(adapter, nports); - } else - return -1; - - writel(status_enable_extra | F_RXSTATUSENABLE, - adapter->regs + A_ESPI_FIFO_STATUS_ENABLE); - - if (is_T2(adapter)) { - tricn_init(adapter); - /* - * Always position the control at the 1st port egress IN - * (sop,eop) counter to reduce PIOs for T/N210 workaround. - */ - espi->misc_ctrl = readl(adapter->regs + A_ESPI_MISC_CONTROL); - espi->misc_ctrl &= ~MON_MASK; - espi->misc_ctrl |= F_MONITORED_DIRECTION; - if (adapter->params.nports == 1) - espi->misc_ctrl |= F_MONITORED_INTERFACE; - writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); - spin_lock_init(&espi->lock); - } - - return 0; -} - -void t1_espi_destroy(struct peespi *espi) -{ - kfree(espi); -} - -struct peespi *t1_espi_create(adapter_t *adapter) -{ - struct peespi *espi = kzalloc(sizeof(*espi), GFP_KERNEL); - - if (espi) - espi->adapter = adapter; - return espi; -} - -#if 0 -void t1_espi_set_misc_ctrl(adapter_t *adapter, u32 val) -{ - struct peespi *espi = adapter->espi; - - if (!is_T2(adapter)) - return; - spin_lock(&espi->lock); - espi->misc_ctrl = (val & ~MON_MASK) | - (espi->misc_ctrl & MON_MASK); - writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); - spin_unlock(&espi->lock); -} -#endif /* 0 */ - -u32 t1_espi_get_mon(adapter_t *adapter, u32 addr, u8 wait) -{ - struct peespi *espi = adapter->espi; - u32 sel; - - if (!is_T2(adapter)) - return 0; - - sel = V_MONITORED_PORT_NUM((addr & 0x3c) >> 2); - if (!wait) { - if (!spin_trylock(&espi->lock)) - return 0; - } else - spin_lock(&espi->lock); - - if ((sel != (espi->misc_ctrl & MON_MASK))) { - writel(((espi->misc_ctrl & ~MON_MASK) | sel), - adapter->regs + A_ESPI_MISC_CONTROL); - sel = readl(adapter->regs + A_ESPI_SCH_TOKEN3); - writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); - } else - sel = readl(adapter->regs + A_ESPI_SCH_TOKEN3); - spin_unlock(&espi->lock); - return sel; -} - -/* - * This function is for T204 only. - * compare with t1_espi_get_mon(), it reads espiInTxSop[0 ~ 3] in - * one shot, since there is no per port counter on the out side. - */ -int t1_espi_get_mon_t204(adapter_t *adapter, u32 *valp, u8 wait) -{ - struct peespi *espi = adapter->espi; - u8 i, nport = (u8)adapter->params.nports; - - if (!wait) { - if (!spin_trylock(&espi->lock)) - return -1; - } else - spin_lock(&espi->lock); - - if ((espi->misc_ctrl & MON_MASK) != F_MONITORED_DIRECTION) { - espi->misc_ctrl = (espi->misc_ctrl & ~MON_MASK) | - F_MONITORED_DIRECTION; - writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); - } - for (i = 0 ; i < nport; i++, valp++) { - if (i) { - writel(espi->misc_ctrl | V_MONITORED_PORT_NUM(i), - adapter->regs + A_ESPI_MISC_CONTROL); - } - *valp = readl(adapter->regs + A_ESPI_SCH_TOKEN3); - } - - writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); - spin_unlock(&espi->lock); - return 0; -} diff --git a/drivers/net/chelsio/espi.h b/drivers/net/chelsio/espi.h deleted file mode 100644 index 5694aad4fbc0..000000000000 --- a/drivers/net/chelsio/espi.h +++ /dev/null @@ -1,68 +0,0 @@ -/***************************************************************************** - * * - * File: espi.h * - * $Revision: 1.7 $ * - * $Date: 2005/06/21 18:29:47 $ * - * Description: * - * part of the Chelsio 10Gb Ethernet Driver. * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * * - * http://www.chelsio.com * - * * - * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * - * All rights reserved. * - * * - * Maintainers: maintainers@chelsio.com * - * * - * Authors: Dimitrios Michailidis * - * Tina Yang * - * Felix Marti * - * Scott Bardone * - * Kurt Ottaway * - * Frank DiMambro * - * * - * History: * - * * - ****************************************************************************/ - -#ifndef _CXGB_ESPI_H_ -#define _CXGB_ESPI_H_ - -#include "common.h" - -struct espi_intr_counts { - unsigned int DIP4_err; - unsigned int rx_drops; - unsigned int tx_drops; - unsigned int rx_ovflw; - unsigned int parity_err; - unsigned int DIP2_parity_err; -}; - -struct peespi; - -struct peespi *t1_espi_create(adapter_t *adapter); -void t1_espi_destroy(struct peespi *espi); -int t1_espi_init(struct peespi *espi, int mac_type, int nports); - -void t1_espi_intr_enable(struct peespi *); -void t1_espi_intr_clear(struct peespi *); -void t1_espi_intr_disable(struct peespi *); -int t1_espi_intr_handler(struct peespi *); -const struct espi_intr_counts *t1_espi_get_intr_counts(struct peespi *espi); - -u32 t1_espi_get_mon(adapter_t *adapter, u32 addr, u8 wait); -int t1_espi_get_mon_t204(adapter_t *, u32 *, u8); - -#endif /* _CXGB_ESPI_H_ */ diff --git a/drivers/net/chelsio/fpga_defs.h b/drivers/net/chelsio/fpga_defs.h deleted file mode 100644 index ccdb2bc9ae98..000000000000 --- a/drivers/net/chelsio/fpga_defs.h +++ /dev/null @@ -1,232 +0,0 @@ -/* $Date: 2005/03/07 23:59:05 $ $RCSfile: fpga_defs.h,v $ $Revision: 1.4 $ */ - -/* - * FPGA specific definitions - */ - -#ifndef __CHELSIO_FPGA_DEFS_H__ -#define __CHELSIO_FPGA_DEFS_H__ - -#define FPGA_PCIX_ADDR_VERSION 0xA08 -#define FPGA_PCIX_ADDR_STAT 0xA0C - -/* FPGA master interrupt Cause/Enable bits */ -#define FPGA_PCIX_INTERRUPT_SGE_ERROR 0x1 -#define FPGA_PCIX_INTERRUPT_SGE_DATA 0x2 -#define FPGA_PCIX_INTERRUPT_TP 0x4 -#define FPGA_PCIX_INTERRUPT_MC3 0x8 -#define FPGA_PCIX_INTERRUPT_GMAC 0x10 -#define FPGA_PCIX_INTERRUPT_PCIX 0x20 - -/* TP interrupt register addresses */ -#define FPGA_TP_ADDR_INTERRUPT_ENABLE 0xA10 -#define FPGA_TP_ADDR_INTERRUPT_CAUSE 0xA14 -#define FPGA_TP_ADDR_VERSION 0xA18 - -/* TP interrupt Cause/Enable bits */ -#define FPGA_TP_INTERRUPT_MC4 0x1 -#define FPGA_TP_INTERRUPT_MC5 0x2 - -/* - * PM interrupt register addresses - */ -#define FPGA_MC3_REG_INTRENABLE 0xA20 -#define FPGA_MC3_REG_INTRCAUSE 0xA24 -#define FPGA_MC3_REG_VERSION 0xA28 - -/* - * GMAC interrupt register addresses - */ -#define FPGA_GMAC_ADDR_INTERRUPT_ENABLE 0xA30 -#define FPGA_GMAC_ADDR_INTERRUPT_CAUSE 0xA34 -#define FPGA_GMAC_ADDR_VERSION 0xA38 - -/* GMAC Cause/Enable bits */ -#define FPGA_GMAC_INTERRUPT_PORT0 0x1 -#define FPGA_GMAC_INTERRUPT_PORT1 0x2 -#define FPGA_GMAC_INTERRUPT_PORT2 0x4 -#define FPGA_GMAC_INTERRUPT_PORT3 0x8 - -/* MI0 registers */ -#define A_MI0_CLK 0xb00 - -#define S_MI0_CLK_DIV 0 -#define M_MI0_CLK_DIV 0xff -#define V_MI0_CLK_DIV(x) ((x) << S_MI0_CLK_DIV) -#define G_MI0_CLK_DIV(x) (((x) >> S_MI0_CLK_DIV) & M_MI0_CLK_DIV) - -#define S_MI0_CLK_CNT 8 -#define M_MI0_CLK_CNT 0xff -#define V_MI0_CLK_CNT(x) ((x) << S_MI0_CLK_CNT) -#define G_MI0_CLK_CNT(x) (((x) >> S_MI0_CLK_CNT) & M_MI0_CLK_CNT) - -#define A_MI0_CSR 0xb04 - -#define S_MI0_CSR_POLL 0 -#define V_MI0_CSR_POLL(x) ((x) << S_MI0_CSR_POLL) -#define F_MI0_CSR_POLL V_MI0_CSR_POLL(1U) - -#define S_MI0_PREAMBLE 1 -#define V_MI0_PREAMBLE(x) ((x) << S_MI0_PREAMBLE) -#define F_MI0_PREAMBLE V_MI0_PREAMBLE(1U) - -#define S_MI0_INTR_ENABLE 2 -#define V_MI0_INTR_ENABLE(x) ((x) << S_MI0_INTR_ENABLE) -#define F_MI0_INTR_ENABLE V_MI0_INTR_ENABLE(1U) - -#define S_MI0_BUSY 3 -#define V_MI0_BUSY(x) ((x) << S_MI0_BUSY) -#define F_MI0_BUSY V_MI0_BUSY(1U) - -#define S_MI0_MDIO 4 -#define V_MI0_MDIO(x) ((x) << S_MI0_MDIO) -#define F_MI0_MDIO V_MI0_MDIO(1U) - -#define A_MI0_ADDR 0xb08 - -#define S_MI0_PHY_REG_ADDR 0 -#define M_MI0_PHY_REG_ADDR 0x1f -#define V_MI0_PHY_REG_ADDR(x) ((x) << S_MI0_PHY_REG_ADDR) -#define G_MI0_PHY_REG_ADDR(x) (((x) >> S_MI0_PHY_REG_ADDR) & M_MI0_PHY_REG_ADDR) - -#define S_MI0_PHY_ADDR 5 -#define M_MI0_PHY_ADDR 0x1f -#define V_MI0_PHY_ADDR(x) ((x) << S_MI0_PHY_ADDR) -#define G_MI0_PHY_ADDR(x) (((x) >> S_MI0_PHY_ADDR) & M_MI0_PHY_ADDR) - -#define A_MI0_DATA_EXT 0xb0c -#define A_MI0_DATA_INT 0xb10 - -/* GMAC registers */ -#define A_GMAC_MACID_LO 0x28 -#define A_GMAC_MACID_HI 0x2c -#define A_GMAC_CSR 0x30 - -#define S_INTERFACE 0 -#define M_INTERFACE 0x3 -#define V_INTERFACE(x) ((x) << S_INTERFACE) -#define G_INTERFACE(x) (((x) >> S_INTERFACE) & M_INTERFACE) - -#define S_MAC_TX_ENABLE 2 -#define V_MAC_TX_ENABLE(x) ((x) << S_MAC_TX_ENABLE) -#define F_MAC_TX_ENABLE V_MAC_TX_ENABLE(1U) - -#define S_MAC_RX_ENABLE 3 -#define V_MAC_RX_ENABLE(x) ((x) << S_MAC_RX_ENABLE) -#define F_MAC_RX_ENABLE V_MAC_RX_ENABLE(1U) - -#define S_MAC_LB_ENABLE 4 -#define V_MAC_LB_ENABLE(x) ((x) << S_MAC_LB_ENABLE) -#define F_MAC_LB_ENABLE V_MAC_LB_ENABLE(1U) - -#define S_MAC_SPEED 5 -#define M_MAC_SPEED 0x3 -#define V_MAC_SPEED(x) ((x) << S_MAC_SPEED) -#define G_MAC_SPEED(x) (((x) >> S_MAC_SPEED) & M_MAC_SPEED) - -#define S_MAC_HD_FC_ENABLE 7 -#define V_MAC_HD_FC_ENABLE(x) ((x) << S_MAC_HD_FC_ENABLE) -#define F_MAC_HD_FC_ENABLE V_MAC_HD_FC_ENABLE(1U) - -#define S_MAC_HALF_DUPLEX 8 -#define V_MAC_HALF_DUPLEX(x) ((x) << S_MAC_HALF_DUPLEX) -#define F_MAC_HALF_DUPLEX V_MAC_HALF_DUPLEX(1U) - -#define S_MAC_PROMISC 9 -#define V_MAC_PROMISC(x) ((x) << S_MAC_PROMISC) -#define F_MAC_PROMISC V_MAC_PROMISC(1U) - -#define S_MAC_MC_ENABLE 10 -#define V_MAC_MC_ENABLE(x) ((x) << S_MAC_MC_ENABLE) -#define F_MAC_MC_ENABLE V_MAC_MC_ENABLE(1U) - -#define S_MAC_RESET 11 -#define V_MAC_RESET(x) ((x) << S_MAC_RESET) -#define F_MAC_RESET V_MAC_RESET(1U) - -#define S_MAC_RX_PAUSE_ENABLE 12 -#define V_MAC_RX_PAUSE_ENABLE(x) ((x) << S_MAC_RX_PAUSE_ENABLE) -#define F_MAC_RX_PAUSE_ENABLE V_MAC_RX_PAUSE_ENABLE(1U) - -#define S_MAC_TX_PAUSE_ENABLE 13 -#define V_MAC_TX_PAUSE_ENABLE(x) ((x) << S_MAC_TX_PAUSE_ENABLE) -#define F_MAC_TX_PAUSE_ENABLE V_MAC_TX_PAUSE_ENABLE(1U) - -#define S_MAC_LWM_ENABLE 14 -#define V_MAC_LWM_ENABLE(x) ((x) << S_MAC_LWM_ENABLE) -#define F_MAC_LWM_ENABLE V_MAC_LWM_ENABLE(1U) - -#define S_MAC_MAGIC_PKT_ENABLE 15 -#define V_MAC_MAGIC_PKT_ENABLE(x) ((x) << S_MAC_MAGIC_PKT_ENABLE) -#define F_MAC_MAGIC_PKT_ENABLE V_MAC_MAGIC_PKT_ENABLE(1U) - -#define S_MAC_ISL_ENABLE 16 -#define V_MAC_ISL_ENABLE(x) ((x) << S_MAC_ISL_ENABLE) -#define F_MAC_ISL_ENABLE V_MAC_ISL_ENABLE(1U) - -#define S_MAC_JUMBO_ENABLE 17 -#define V_MAC_JUMBO_ENABLE(x) ((x) << S_MAC_JUMBO_ENABLE) -#define F_MAC_JUMBO_ENABLE V_MAC_JUMBO_ENABLE(1U) - -#define S_MAC_RX_PAD_ENABLE 18 -#define V_MAC_RX_PAD_ENABLE(x) ((x) << S_MAC_RX_PAD_ENABLE) -#define F_MAC_RX_PAD_ENABLE V_MAC_RX_PAD_ENABLE(1U) - -#define S_MAC_RX_CRC_ENABLE 19 -#define V_MAC_RX_CRC_ENABLE(x) ((x) << S_MAC_RX_CRC_ENABLE) -#define F_MAC_RX_CRC_ENABLE V_MAC_RX_CRC_ENABLE(1U) - -#define A_GMAC_IFS 0x34 - -#define S_MAC_IFS2 0 -#define M_MAC_IFS2 0x3f -#define V_MAC_IFS2(x) ((x) << S_MAC_IFS2) -#define G_MAC_IFS2(x) (((x) >> S_MAC_IFS2) & M_MAC_IFS2) - -#define S_MAC_IFS1 8 -#define M_MAC_IFS1 0x7f -#define V_MAC_IFS1(x) ((x) << S_MAC_IFS1) -#define G_MAC_IFS1(x) (((x) >> S_MAC_IFS1) & M_MAC_IFS1) - -#define A_GMAC_JUMBO_FRAME_LEN 0x38 -#define A_GMAC_LNK_DLY 0x3c -#define A_GMAC_PAUSETIME 0x40 -#define A_GMAC_MCAST_LO 0x44 -#define A_GMAC_MCAST_HI 0x48 -#define A_GMAC_MCAST_MASK_LO 0x4c -#define A_GMAC_MCAST_MASK_HI 0x50 -#define A_GMAC_RMT_CNT 0x54 -#define A_GMAC_RMT_DATA 0x58 -#define A_GMAC_BACKOFF_SEED 0x5c -#define A_GMAC_TXF_THRES 0x60 - -#define S_TXF_READ_THRESHOLD 0 -#define M_TXF_READ_THRESHOLD 0xff -#define V_TXF_READ_THRESHOLD(x) ((x) << S_TXF_READ_THRESHOLD) -#define G_TXF_READ_THRESHOLD(x) (((x) >> S_TXF_READ_THRESHOLD) & M_TXF_READ_THRESHOLD) - -#define S_TXF_WRITE_THRESHOLD 16 -#define M_TXF_WRITE_THRESHOLD 0xff -#define V_TXF_WRITE_THRESHOLD(x) ((x) << S_TXF_WRITE_THRESHOLD) -#define G_TXF_WRITE_THRESHOLD(x) (((x) >> S_TXF_WRITE_THRESHOLD) & M_TXF_WRITE_THRESHOLD) - -#define MAC_REG_BASE 0x600 -#define MAC_REG_ADDR(idx, reg) (MAC_REG_BASE + (idx) * 128 + (reg)) - -#define MAC_REG_IDLO(idx) MAC_REG_ADDR(idx, A_GMAC_MACID_LO) -#define MAC_REG_IDHI(idx) MAC_REG_ADDR(idx, A_GMAC_MACID_HI) -#define MAC_REG_CSR(idx) MAC_REG_ADDR(idx, A_GMAC_CSR) -#define MAC_REG_IFS(idx) MAC_REG_ADDR(idx, A_GMAC_IFS) -#define MAC_REG_LARGEFRAMELENGTH(idx) MAC_REG_ADDR(idx, A_GMAC_JUMBO_FRAME_LEN) -#define MAC_REG_LINKDLY(idx) MAC_REG_ADDR(idx, A_GMAC_LNK_DLY) -#define MAC_REG_PAUSETIME(idx) MAC_REG_ADDR(idx, A_GMAC_PAUSETIME) -#define MAC_REG_CASTLO(idx) MAC_REG_ADDR(idx, A_GMAC_MCAST_LO) -#define MAC_REG_MCASTHI(idx) MAC_REG_ADDR(idx, A_GMAC_MCAST_HI) -#define MAC_REG_CASTMASKLO(idx) MAC_REG_ADDR(idx, A_GMAC_MCAST_MASK_LO) -#define MAC_REG_MCASTMASKHI(idx) MAC_REG_ADDR(idx, A_GMAC_MCAST_MASK_HI) -#define MAC_REG_RMCNT(idx) MAC_REG_ADDR(idx, A_GMAC_RMT_CNT) -#define MAC_REG_RMDATA(idx) MAC_REG_ADDR(idx, A_GMAC_RMT_DATA) -#define MAC_REG_GMRANDBACKOFFSEED(idx) MAC_REG_ADDR(idx, A_GMAC_BACKOFF_SEED) -#define MAC_REG_TXFTHRESHOLDS(idx) MAC_REG_ADDR(idx, A_GMAC_TXF_THRES) - -#endif diff --git a/drivers/net/chelsio/gmac.h b/drivers/net/chelsio/gmac.h deleted file mode 100644 index d42337457cf7..000000000000 --- a/drivers/net/chelsio/gmac.h +++ /dev/null @@ -1,142 +0,0 @@ -/***************************************************************************** - * * - * File: gmac.h * - * $Revision: 1.6 $ * - * $Date: 2005/06/21 18:29:47 $ * - * Description: * - * Generic MAC functionality. * - * part of the Chelsio 10Gb Ethernet Driver. * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * * - * http://www.chelsio.com * - * * - * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * - * All rights reserved. * - * * - * Maintainers: maintainers@chelsio.com * - * * - * Authors: Dimitrios Michailidis * - * Tina Yang * - * Felix Marti * - * Scott Bardone * - * Kurt Ottaway * - * Frank DiMambro * - * * - * History: * - * * - ****************************************************************************/ - -#ifndef _CXGB_GMAC_H_ -#define _CXGB_GMAC_H_ - -#include "common.h" - -enum { - MAC_STATS_UPDATE_FAST, - MAC_STATS_UPDATE_FULL -}; - -enum { - MAC_DIRECTION_RX = 1, - MAC_DIRECTION_TX = 2 -}; - -struct cmac_statistics { - /* Transmit */ - u64 TxOctetsOK; - u64 TxOctetsBad; - u64 TxUnicastFramesOK; - u64 TxMulticastFramesOK; - u64 TxBroadcastFramesOK; - u64 TxPauseFrames; - u64 TxFramesWithDeferredXmissions; - u64 TxLateCollisions; - u64 TxTotalCollisions; - u64 TxFramesAbortedDueToXSCollisions; - u64 TxUnderrun; - u64 TxLengthErrors; - u64 TxInternalMACXmitError; - u64 TxFramesWithExcessiveDeferral; - u64 TxFCSErrors; - u64 TxJumboFramesOK; - u64 TxJumboOctetsOK; - - /* Receive */ - u64 RxOctetsOK; - u64 RxOctetsBad; - u64 RxUnicastFramesOK; - u64 RxMulticastFramesOK; - u64 RxBroadcastFramesOK; - u64 RxPauseFrames; - u64 RxFCSErrors; - u64 RxAlignErrors; - u64 RxSymbolErrors; - u64 RxDataErrors; - u64 RxSequenceErrors; - u64 RxRuntErrors; - u64 RxJabberErrors; - u64 RxInternalMACRcvError; - u64 RxInRangeLengthErrors; - u64 RxOutOfRangeLengthField; - u64 RxFrameTooLongErrors; - u64 RxJumboFramesOK; - u64 RxJumboOctetsOK; -}; - -struct cmac_ops { - void (*destroy)(struct cmac *); - int (*reset)(struct cmac *); - int (*interrupt_enable)(struct cmac *); - int (*interrupt_disable)(struct cmac *); - int (*interrupt_clear)(struct cmac *); - int (*interrupt_handler)(struct cmac *); - - int (*enable)(struct cmac *, int); - int (*disable)(struct cmac *, int); - - int (*loopback_enable)(struct cmac *); - int (*loopback_disable)(struct cmac *); - - int (*set_mtu)(struct cmac *, int mtu); - int (*set_rx_mode)(struct cmac *, struct t1_rx_mode *rm); - - int (*set_speed_duplex_fc)(struct cmac *, int speed, int duplex, int fc); - int (*get_speed_duplex_fc)(struct cmac *, int *speed, int *duplex, - int *fc); - - const struct cmac_statistics *(*statistics_update)(struct cmac *, int); - - int (*macaddress_get)(struct cmac *, u8 mac_addr[6]); - int (*macaddress_set)(struct cmac *, u8 mac_addr[6]); -}; - -typedef struct _cmac_instance cmac_instance; - -struct cmac { - struct cmac_statistics stats; - adapter_t *adapter; - const struct cmac_ops *ops; - cmac_instance *instance; -}; - -struct gmac { - unsigned int stats_update_period; - struct cmac *(*create)(adapter_t *adapter, int index); - int (*reset)(adapter_t *); -}; - -extern const struct gmac t1_pm3393_ops; -extern const struct gmac t1_vsc7326_ops; - -#endif /* _CXGB_GMAC_H_ */ diff --git a/drivers/net/chelsio/mv88e1xxx.c b/drivers/net/chelsio/mv88e1xxx.c deleted file mode 100644 index 71018a4fdf15..000000000000 --- a/drivers/net/chelsio/mv88e1xxx.c +++ /dev/null @@ -1,397 +0,0 @@ -/* $Date: 2005/10/24 23:18:13 $ $RCSfile: mv88e1xxx.c,v $ $Revision: 1.49 $ */ -#include "common.h" -#include "mv88e1xxx.h" -#include "cphy.h" -#include "elmer0.h" - -/* MV88E1XXX MDI crossover register values */ -#define CROSSOVER_MDI 0 -#define CROSSOVER_MDIX 1 -#define CROSSOVER_AUTO 3 - -#define INTR_ENABLE_MASK 0x6CA0 - -/* - * Set the bits given by 'bitval' in PHY register 'reg'. - */ -static void mdio_set_bit(struct cphy *cphy, int reg, u32 bitval) -{ - u32 val; - - (void) simple_mdio_read(cphy, reg, &val); - (void) simple_mdio_write(cphy, reg, val | bitval); -} - -/* - * Clear the bits given by 'bitval' in PHY register 'reg'. - */ -static void mdio_clear_bit(struct cphy *cphy, int reg, u32 bitval) -{ - u32 val; - - (void) simple_mdio_read(cphy, reg, &val); - (void) simple_mdio_write(cphy, reg, val & ~bitval); -} - -/* - * NAME: phy_reset - * - * DESC: Reset the given PHY's port. NOTE: This is not a global - * chip reset. - * - * PARAMS: cphy - Pointer to PHY instance data. - * - * RETURN: 0 - Successful reset. - * -1 - Timeout. - */ -static int mv88e1xxx_reset(struct cphy *cphy, int wait) -{ - u32 ctl; - int time_out = 1000; - - mdio_set_bit(cphy, MII_BMCR, BMCR_RESET); - - do { - (void) simple_mdio_read(cphy, MII_BMCR, &ctl); - ctl &= BMCR_RESET; - if (ctl) - udelay(1); - } while (ctl && --time_out); - - return ctl ? -1 : 0; -} - -static int mv88e1xxx_interrupt_enable(struct cphy *cphy) -{ - /* Enable PHY interrupts. */ - (void) simple_mdio_write(cphy, MV88E1XXX_INTERRUPT_ENABLE_REGISTER, - INTR_ENABLE_MASK); - - /* Enable Marvell interrupts through Elmer0. */ - if (t1_is_asic(cphy->adapter)) { - u32 elmer; - - t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer); - elmer |= ELMER0_GP_BIT1; - if (is_T2(cphy->adapter)) - elmer |= ELMER0_GP_BIT2 | ELMER0_GP_BIT3 | ELMER0_GP_BIT4; - t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer); - } - return 0; -} - -static int mv88e1xxx_interrupt_disable(struct cphy *cphy) -{ - /* Disable all phy interrupts. */ - (void) simple_mdio_write(cphy, MV88E1XXX_INTERRUPT_ENABLE_REGISTER, 0); - - /* Disable Marvell interrupts through Elmer0. */ - if (t1_is_asic(cphy->adapter)) { - u32 elmer; - - t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer); - elmer &= ~ELMER0_GP_BIT1; - if (is_T2(cphy->adapter)) - elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4); - t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer); - } - return 0; -} - -static int mv88e1xxx_interrupt_clear(struct cphy *cphy) -{ - u32 elmer; - - /* Clear PHY interrupts by reading the register. */ - (void) simple_mdio_read(cphy, - MV88E1XXX_INTERRUPT_STATUS_REGISTER, &elmer); - - /* Clear Marvell interrupts through Elmer0. */ - if (t1_is_asic(cphy->adapter)) { - t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer); - elmer |= ELMER0_GP_BIT1; - if (is_T2(cphy->adapter)) - elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4; - t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer); - } - return 0; -} - -/* - * Set the PHY speed and duplex. This also disables auto-negotiation, except - * for 1Gb/s, where auto-negotiation is mandatory. - */ -static int mv88e1xxx_set_speed_duplex(struct cphy *phy, int speed, int duplex) -{ - u32 ctl; - - (void) simple_mdio_read(phy, MII_BMCR, &ctl); - if (speed >= 0) { - ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); - if (speed == SPEED_100) - ctl |= BMCR_SPEED100; - else if (speed == SPEED_1000) - ctl |= BMCR_SPEED1000; - } - if (duplex >= 0) { - ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE); - if (duplex == DUPLEX_FULL) - ctl |= BMCR_FULLDPLX; - } - if (ctl & BMCR_SPEED1000) /* auto-negotiation required for 1Gb/s */ - ctl |= BMCR_ANENABLE; - (void) simple_mdio_write(phy, MII_BMCR, ctl); - return 0; -} - -static int mv88e1xxx_crossover_set(struct cphy *cphy, int crossover) -{ - u32 data32; - - (void) simple_mdio_read(cphy, - MV88E1XXX_SPECIFIC_CNTRL_REGISTER, &data32); - data32 &= ~V_PSCR_MDI_XOVER_MODE(M_PSCR_MDI_XOVER_MODE); - data32 |= V_PSCR_MDI_XOVER_MODE(crossover); - (void) simple_mdio_write(cphy, - MV88E1XXX_SPECIFIC_CNTRL_REGISTER, data32); - return 0; -} - -static int mv88e1xxx_autoneg_enable(struct cphy *cphy) -{ - u32 ctl; - - (void) mv88e1xxx_crossover_set(cphy, CROSSOVER_AUTO); - - (void) simple_mdio_read(cphy, MII_BMCR, &ctl); - /* restart autoneg for change to take effect */ - ctl |= BMCR_ANENABLE | BMCR_ANRESTART; - (void) simple_mdio_write(cphy, MII_BMCR, ctl); - return 0; -} - -static int mv88e1xxx_autoneg_disable(struct cphy *cphy) -{ - u32 ctl; - - /* - * Crossover *must* be set to manual in order to disable auto-neg. - * The Alaska FAQs document highlights this point. - */ - (void) mv88e1xxx_crossover_set(cphy, CROSSOVER_MDI); - - /* - * Must include autoneg reset when disabling auto-neg. This - * is described in the Alaska FAQ document. - */ - (void) simple_mdio_read(cphy, MII_BMCR, &ctl); - ctl &= ~BMCR_ANENABLE; - (void) simple_mdio_write(cphy, MII_BMCR, ctl | BMCR_ANRESTART); - return 0; -} - -static int mv88e1xxx_autoneg_restart(struct cphy *cphy) -{ - mdio_set_bit(cphy, MII_BMCR, BMCR_ANRESTART); - return 0; -} - -static int mv88e1xxx_advertise(struct cphy *phy, unsigned int advertise_map) -{ - u32 val = 0; - - if (advertise_map & - (ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) { - (void) simple_mdio_read(phy, MII_GBCR, &val); - val &= ~(GBCR_ADV_1000HALF | GBCR_ADV_1000FULL); - if (advertise_map & ADVERTISED_1000baseT_Half) - val |= GBCR_ADV_1000HALF; - if (advertise_map & ADVERTISED_1000baseT_Full) - val |= GBCR_ADV_1000FULL; - } - (void) simple_mdio_write(phy, MII_GBCR, val); - - val = 1; - if (advertise_map & ADVERTISED_10baseT_Half) - val |= ADVERTISE_10HALF; - if (advertise_map & ADVERTISED_10baseT_Full) - val |= ADVERTISE_10FULL; - if (advertise_map & ADVERTISED_100baseT_Half) - val |= ADVERTISE_100HALF; - if (advertise_map & ADVERTISED_100baseT_Full) - val |= ADVERTISE_100FULL; - if (advertise_map & ADVERTISED_PAUSE) - val |= ADVERTISE_PAUSE; - if (advertise_map & ADVERTISED_ASYM_PAUSE) - val |= ADVERTISE_PAUSE_ASYM; - (void) simple_mdio_write(phy, MII_ADVERTISE, val); - return 0; -} - -static int mv88e1xxx_set_loopback(struct cphy *cphy, int on) -{ - if (on) - mdio_set_bit(cphy, MII_BMCR, BMCR_LOOPBACK); - else - mdio_clear_bit(cphy, MII_BMCR, BMCR_LOOPBACK); - return 0; -} - -static int mv88e1xxx_get_link_status(struct cphy *cphy, int *link_ok, - int *speed, int *duplex, int *fc) -{ - u32 status; - int sp = -1, dplx = -1, pause = 0; - - (void) simple_mdio_read(cphy, - MV88E1XXX_SPECIFIC_STATUS_REGISTER, &status); - if ((status & V_PSSR_STATUS_RESOLVED) != 0) { - if (status & V_PSSR_RX_PAUSE) - pause |= PAUSE_RX; - if (status & V_PSSR_TX_PAUSE) - pause |= PAUSE_TX; - dplx = (status & V_PSSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF; - sp = G_PSSR_SPEED(status); - if (sp == 0) - sp = SPEED_10; - else if (sp == 1) - sp = SPEED_100; - else - sp = SPEED_1000; - } - if (link_ok) - *link_ok = (status & V_PSSR_LINK) != 0; - if (speed) - *speed = sp; - if (duplex) - *duplex = dplx; - if (fc) - *fc = pause; - return 0; -} - -static int mv88e1xxx_downshift_set(struct cphy *cphy, int downshift_enable) -{ - u32 val; - - (void) simple_mdio_read(cphy, - MV88E1XXX_EXT_PHY_SPECIFIC_CNTRL_REGISTER, &val); - - /* - * Set the downshift counter to 2 so we try to establish Gb link - * twice before downshifting. - */ - val &= ~(V_DOWNSHIFT_ENABLE | V_DOWNSHIFT_CNT(M_DOWNSHIFT_CNT)); - - if (downshift_enable) - val |= V_DOWNSHIFT_ENABLE | V_DOWNSHIFT_CNT(2); - (void) simple_mdio_write(cphy, - MV88E1XXX_EXT_PHY_SPECIFIC_CNTRL_REGISTER, val); - return 0; -} - -static int mv88e1xxx_interrupt_handler(struct cphy *cphy) -{ - int cphy_cause = 0; - u32 status; - - /* - * Loop until cause reads zero. Need to handle bouncing interrupts. - */ - while (1) { - u32 cause; - - (void) simple_mdio_read(cphy, - MV88E1XXX_INTERRUPT_STATUS_REGISTER, - &cause); - cause &= INTR_ENABLE_MASK; - if (!cause) - break; - - if (cause & MV88E1XXX_INTR_LINK_CHNG) { - (void) simple_mdio_read(cphy, - MV88E1XXX_SPECIFIC_STATUS_REGISTER, &status); - - if (status & MV88E1XXX_INTR_LINK_CHNG) - cphy->state |= PHY_LINK_UP; - else { - cphy->state &= ~PHY_LINK_UP; - if (cphy->state & PHY_AUTONEG_EN) - cphy->state &= ~PHY_AUTONEG_RDY; - cphy_cause |= cphy_cause_link_change; - } - } - - if (cause & MV88E1XXX_INTR_AUTONEG_DONE) - cphy->state |= PHY_AUTONEG_RDY; - - if ((cphy->state & (PHY_LINK_UP | PHY_AUTONEG_RDY)) == - (PHY_LINK_UP | PHY_AUTONEG_RDY)) - cphy_cause |= cphy_cause_link_change; - } - return cphy_cause; -} - -static void mv88e1xxx_destroy(struct cphy *cphy) -{ - kfree(cphy); -} - -static struct cphy_ops mv88e1xxx_ops = { - .destroy = mv88e1xxx_destroy, - .reset = mv88e1xxx_reset, - .interrupt_enable = mv88e1xxx_interrupt_enable, - .interrupt_disable = mv88e1xxx_interrupt_disable, - .interrupt_clear = mv88e1xxx_interrupt_clear, - .interrupt_handler = mv88e1xxx_interrupt_handler, - .autoneg_enable = mv88e1xxx_autoneg_enable, - .autoneg_disable = mv88e1xxx_autoneg_disable, - .autoneg_restart = mv88e1xxx_autoneg_restart, - .advertise = mv88e1xxx_advertise, - .set_loopback = mv88e1xxx_set_loopback, - .set_speed_duplex = mv88e1xxx_set_speed_duplex, - .get_link_status = mv88e1xxx_get_link_status, -}; - -static struct cphy *mv88e1xxx_phy_create(struct net_device *dev, int phy_addr, - const struct mdio_ops *mdio_ops) -{ - struct adapter *adapter = netdev_priv(dev); - struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL); - - if (!cphy) - return NULL; - - cphy_init(cphy, dev, phy_addr, &mv88e1xxx_ops, mdio_ops); - - /* Configure particular PHY's to run in a different mode. */ - if ((board_info(adapter)->caps & SUPPORTED_TP) && - board_info(adapter)->chip_phy == CHBT_PHY_88E1111) { - /* - * Configure the PHY transmitter as class A to reduce EMI. - */ - (void) simple_mdio_write(cphy, - MV88E1XXX_EXTENDED_ADDR_REGISTER, 0xB); - (void) simple_mdio_write(cphy, - MV88E1XXX_EXTENDED_REGISTER, 0x8004); - } - (void) mv88e1xxx_downshift_set(cphy, 1); /* Enable downshift */ - - /* LED */ - if (is_T2(adapter)) { - (void) simple_mdio_write(cphy, - MV88E1XXX_LED_CONTROL_REGISTER, 0x1); - } - - return cphy; -} - -static int mv88e1xxx_phy_reset(adapter_t* adapter) -{ - return 0; -} - -const struct gphy t1_mv88e1xxx_ops = { - .create = mv88e1xxx_phy_create, - .reset = mv88e1xxx_phy_reset -}; diff --git a/drivers/net/chelsio/mv88e1xxx.h b/drivers/net/chelsio/mv88e1xxx.h deleted file mode 100644 index 967cc4286359..000000000000 --- a/drivers/net/chelsio/mv88e1xxx.h +++ /dev/null @@ -1,127 +0,0 @@ -/* $Date: 2005/03/07 23:59:05 $ $RCSfile: mv88e1xxx.h,v $ $Revision: 1.13 $ */ -#ifndef CHELSIO_MV8E1XXX_H -#define CHELSIO_MV8E1XXX_H - -#ifndef BMCR_SPEED1000 -# define BMCR_SPEED1000 0x40 -#endif - -#ifndef ADVERTISE_PAUSE -# define ADVERTISE_PAUSE 0x400 -#endif -#ifndef ADVERTISE_PAUSE_ASYM -# define ADVERTISE_PAUSE_ASYM 0x800 -#endif - -/* Gigabit MII registers */ -#define MII_GBCR 9 /* 1000Base-T control register */ -#define MII_GBSR 10 /* 1000Base-T status register */ - -/* 1000Base-T control register fields */ -#define GBCR_ADV_1000HALF 0x100 -#define GBCR_ADV_1000FULL 0x200 -#define GBCR_PREFER_MASTER 0x400 -#define GBCR_MANUAL_AS_MASTER 0x800 -#define GBCR_MANUAL_CONFIG_ENABLE 0x1000 - -/* 1000Base-T status register fields */ -#define GBSR_LP_1000HALF 0x400 -#define GBSR_LP_1000FULL 0x800 -#define GBSR_REMOTE_OK 0x1000 -#define GBSR_LOCAL_OK 0x2000 -#define GBSR_LOCAL_MASTER 0x4000 -#define GBSR_MASTER_FAULT 0x8000 - -/* Marvell PHY interrupt status bits. */ -#define MV88E1XXX_INTR_JABBER 0x0001 -#define MV88E1XXX_INTR_POLARITY_CHNG 0x0002 -#define MV88E1XXX_INTR_ENG_DETECT_CHNG 0x0010 -#define MV88E1XXX_INTR_DOWNSHIFT 0x0020 -#define MV88E1XXX_INTR_MDI_XOVER_CHNG 0x0040 -#define MV88E1XXX_INTR_FIFO_OVER_UNDER 0x0080 -#define MV88E1XXX_INTR_FALSE_CARRIER 0x0100 -#define MV88E1XXX_INTR_SYMBOL_ERROR 0x0200 -#define MV88E1XXX_INTR_LINK_CHNG 0x0400 -#define MV88E1XXX_INTR_AUTONEG_DONE 0x0800 -#define MV88E1XXX_INTR_PAGE_RECV 0x1000 -#define MV88E1XXX_INTR_DUPLEX_CHNG 0x2000 -#define MV88E1XXX_INTR_SPEED_CHNG 0x4000 -#define MV88E1XXX_INTR_AUTONEG_ERR 0x8000 - -/* Marvell PHY specific registers. */ -#define MV88E1XXX_SPECIFIC_CNTRL_REGISTER 16 -#define MV88E1XXX_SPECIFIC_STATUS_REGISTER 17 -#define MV88E1XXX_INTERRUPT_ENABLE_REGISTER 18 -#define MV88E1XXX_INTERRUPT_STATUS_REGISTER 19 -#define MV88E1XXX_EXT_PHY_SPECIFIC_CNTRL_REGISTER 20 -#define MV88E1XXX_RECV_ERR_CNTR_REGISTER 21 -#define MV88E1XXX_RES_REGISTER 22 -#define MV88E1XXX_GLOBAL_STATUS_REGISTER 23 -#define MV88E1XXX_LED_CONTROL_REGISTER 24 -#define MV88E1XXX_MANUAL_LED_OVERRIDE_REGISTER 25 -#define MV88E1XXX_EXT_PHY_SPECIFIC_CNTRL_2_REGISTER 26 -#define MV88E1XXX_EXT_PHY_SPECIFIC_STATUS_REGISTER 27 -#define MV88E1XXX_VIRTUAL_CABLE_TESTER_REGISTER 28 -#define MV88E1XXX_EXTENDED_ADDR_REGISTER 29 -#define MV88E1XXX_EXTENDED_REGISTER 30 - -/* PHY specific control register fields */ -#define S_PSCR_MDI_XOVER_MODE 5 -#define M_PSCR_MDI_XOVER_MODE 0x3 -#define V_PSCR_MDI_XOVER_MODE(x) ((x) << S_PSCR_MDI_XOVER_MODE) -#define G_PSCR_MDI_XOVER_MODE(x) (((x) >> S_PSCR_MDI_XOVER_MODE) & M_PSCR_MDI_XOVER_MODE) - -/* Extended PHY specific control register fields */ -#define S_DOWNSHIFT_ENABLE 8 -#define V_DOWNSHIFT_ENABLE (1 << S_DOWNSHIFT_ENABLE) - -#define S_DOWNSHIFT_CNT 9 -#define M_DOWNSHIFT_CNT 0x7 -#define V_DOWNSHIFT_CNT(x) ((x) << S_DOWNSHIFT_CNT) -#define G_DOWNSHIFT_CNT(x) (((x) >> S_DOWNSHIFT_CNT) & M_DOWNSHIFT_CNT) - -/* PHY specific status register fields */ -#define S_PSSR_JABBER 0 -#define V_PSSR_JABBER (1 << S_PSSR_JABBER) - -#define S_PSSR_POLARITY 1 -#define V_PSSR_POLARITY (1 << S_PSSR_POLARITY) - -#define S_PSSR_RX_PAUSE 2 -#define V_PSSR_RX_PAUSE (1 << S_PSSR_RX_PAUSE) - -#define S_PSSR_TX_PAUSE 3 -#define V_PSSR_TX_PAUSE (1 << S_PSSR_TX_PAUSE) - -#define S_PSSR_ENERGY_DETECT 4 -#define V_PSSR_ENERGY_DETECT (1 << S_PSSR_ENERGY_DETECT) - -#define S_PSSR_DOWNSHIFT_STATUS 5 -#define V_PSSR_DOWNSHIFT_STATUS (1 << S_PSSR_DOWNSHIFT_STATUS) - -#define S_PSSR_MDI 6 -#define V_PSSR_MDI (1 << S_PSSR_MDI) - -#define S_PSSR_CABLE_LEN 7 -#define M_PSSR_CABLE_LEN 0x7 -#define V_PSSR_CABLE_LEN(x) ((x) << S_PSSR_CABLE_LEN) -#define G_PSSR_CABLE_LEN(x) (((x) >> S_PSSR_CABLE_LEN) & M_PSSR_CABLE_LEN) - -#define S_PSSR_LINK 10 -#define V_PSSR_LINK (1 << S_PSSR_LINK) - -#define S_PSSR_STATUS_RESOLVED 11 -#define V_PSSR_STATUS_RESOLVED (1 << S_PSSR_STATUS_RESOLVED) - -#define S_PSSR_PAGE_RECEIVED 12 -#define V_PSSR_PAGE_RECEIVED (1 << S_PSSR_PAGE_RECEIVED) - -#define S_PSSR_DUPLEX 13 -#define V_PSSR_DUPLEX (1 << S_PSSR_DUPLEX) - -#define S_PSSR_SPEED 14 -#define M_PSSR_SPEED 0x3 -#define V_PSSR_SPEED(x) ((x) << S_PSSR_SPEED) -#define G_PSSR_SPEED(x) (((x) >> S_PSSR_SPEED) & M_PSSR_SPEED) - -#endif diff --git a/drivers/net/chelsio/mv88x201x.c b/drivers/net/chelsio/mv88x201x.c deleted file mode 100644 index f7136b2fd1e5..000000000000 --- a/drivers/net/chelsio/mv88x201x.c +++ /dev/null @@ -1,260 +0,0 @@ -/***************************************************************************** - * * - * File: mv88x201x.c * - * $Revision: 1.12 $ * - * $Date: 2005/04/15 19:27:14 $ * - * Description: * - * Marvell PHY (mv88x201x) functionality. * - * part of the Chelsio 10Gb Ethernet Driver. * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * * - * http://www.chelsio.com * - * * - * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * - * All rights reserved. * - * * - * Maintainers: maintainers@chelsio.com * - * * - * Authors: Dimitrios Michailidis * - * Tina Yang * - * Felix Marti * - * Scott Bardone * - * Kurt Ottaway * - * Frank DiMambro * - * * - * History: * - * * - ****************************************************************************/ - -#include "cphy.h" -#include "elmer0.h" - -/* - * The 88x2010 Rev C. requires some link status registers * to be read - * twice in order to get the right values. Future * revisions will fix - * this problem and then this macro * can disappear. - */ -#define MV88x2010_LINK_STATUS_BUGS 1 - -static int led_init(struct cphy *cphy) -{ - /* Setup the LED registers so we can turn on/off. - * Writing these bits maps control to another - * register. mmd(0x1) addr(0x7) - */ - cphy_mdio_write(cphy, MDIO_MMD_PCS, 0x8304, 0xdddd); - return 0; -} - -static int led_link(struct cphy *cphy, u32 do_enable) -{ - u32 led = 0; -#define LINK_ENABLE_BIT 0x1 - - cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_CTRL2, &led); - - if (do_enable & LINK_ENABLE_BIT) { - led |= LINK_ENABLE_BIT; - cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, MDIO_CTRL2, led); - } else { - led &= ~LINK_ENABLE_BIT; - cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, MDIO_CTRL2, led); - } - return 0; -} - -/* Port Reset */ -static int mv88x201x_reset(struct cphy *cphy, int wait) -{ - /* This can be done through registers. It is not required since - * a full chip reset is used. - */ - return 0; -} - -static int mv88x201x_interrupt_enable(struct cphy *cphy) -{ - /* Enable PHY LASI interrupts. */ - cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, - MDIO_PMA_LASI_LSALARM); - - /* Enable Marvell interrupts through Elmer0. */ - if (t1_is_asic(cphy->adapter)) { - u32 elmer; - - t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer); - elmer |= ELMER0_GP_BIT6; - t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer); - } - return 0; -} - -static int mv88x201x_interrupt_disable(struct cphy *cphy) -{ - /* Disable PHY LASI interrupts. */ - cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, 0x0); - - /* Disable Marvell interrupts through Elmer0. */ - if (t1_is_asic(cphy->adapter)) { - u32 elmer; - - t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer); - elmer &= ~ELMER0_GP_BIT6; - t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer); - } - return 0; -} - -static int mv88x201x_interrupt_clear(struct cphy *cphy) -{ - u32 elmer; - u32 val; - -#ifdef MV88x2010_LINK_STATUS_BUGS - /* Required to read twice before clear takes affect. */ - cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_RXSTAT, &val); - cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_TXSTAT, &val); - cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT, &val); - - /* Read this register after the others above it else - * the register doesn't clear correctly. - */ - cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val); -#endif - - /* Clear link status. */ - cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val); - /* Clear PHY LASI interrupts. */ - cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT, &val); - -#ifdef MV88x2010_LINK_STATUS_BUGS - /* Do it again. */ - cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_RXSTAT, &val); - cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_TXSTAT, &val); -#endif - - /* Clear Marvell interrupts through Elmer0. */ - if (t1_is_asic(cphy->adapter)) { - t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer); - elmer |= ELMER0_GP_BIT6; - t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer); - } - return 0; -} - -static int mv88x201x_interrupt_handler(struct cphy *cphy) -{ - /* Clear interrupts */ - mv88x201x_interrupt_clear(cphy); - - /* We have only enabled link change interrupts and so - * cphy_cause must be a link change interrupt. - */ - return cphy_cause_link_change; -} - -static int mv88x201x_set_loopback(struct cphy *cphy, int on) -{ - return 0; -} - -static int mv88x201x_get_link_status(struct cphy *cphy, int *link_ok, - int *speed, int *duplex, int *fc) -{ - u32 val = 0; - - if (link_ok) { - /* Read link status. */ - cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val); - val &= MDIO_STAT1_LSTATUS; - *link_ok = (val == MDIO_STAT1_LSTATUS); - /* Turn on/off Link LED */ - led_link(cphy, *link_ok); - } - if (speed) - *speed = SPEED_10000; - if (duplex) - *duplex = DUPLEX_FULL; - if (fc) - *fc = PAUSE_RX | PAUSE_TX; - return 0; -} - -static void mv88x201x_destroy(struct cphy *cphy) -{ - kfree(cphy); -} - -static struct cphy_ops mv88x201x_ops = { - .destroy = mv88x201x_destroy, - .reset = mv88x201x_reset, - .interrupt_enable = mv88x201x_interrupt_enable, - .interrupt_disable = mv88x201x_interrupt_disable, - .interrupt_clear = mv88x201x_interrupt_clear, - .interrupt_handler = mv88x201x_interrupt_handler, - .get_link_status = mv88x201x_get_link_status, - .set_loopback = mv88x201x_set_loopback, - .mmds = (MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | - MDIO_DEVS_PHYXS | MDIO_DEVS_WIS), -}; - -static struct cphy *mv88x201x_phy_create(struct net_device *dev, int phy_addr, - const struct mdio_ops *mdio_ops) -{ - u32 val; - struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL); - - if (!cphy) - return NULL; - - cphy_init(cphy, dev, phy_addr, &mv88x201x_ops, mdio_ops); - - /* Commands the PHY to enable XFP's clock. */ - cphy_mdio_read(cphy, MDIO_MMD_PCS, 0x8300, &val); - cphy_mdio_write(cphy, MDIO_MMD_PCS, 0x8300, val | 1); - - /* Clear link status. Required because of a bug in the PHY. */ - cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT2, &val); - cphy_mdio_read(cphy, MDIO_MMD_PCS, MDIO_STAT2, &val); - - /* Allows for Link,Ack LED turn on/off */ - led_init(cphy); - return cphy; -} - -/* Chip Reset */ -static int mv88x201x_phy_reset(adapter_t *adapter) -{ - u32 val; - - t1_tpi_read(adapter, A_ELMER0_GPO, &val); - val &= ~4; - t1_tpi_write(adapter, A_ELMER0_GPO, val); - msleep(100); - - t1_tpi_write(adapter, A_ELMER0_GPO, val | 4); - msleep(1000); - - /* Now lets enable the Laser. Delay 100us */ - t1_tpi_read(adapter, A_ELMER0_GPO, &val); - val |= 0x8000; - t1_tpi_write(adapter, A_ELMER0_GPO, val); - udelay(100); - return 0; -} - -const struct gphy t1_mv88x201x_ops = { - .create = mv88x201x_phy_create, - .reset = mv88x201x_phy_reset -}; diff --git a/drivers/net/chelsio/my3126.c b/drivers/net/chelsio/my3126.c deleted file mode 100644 index a683fd3bb624..000000000000 --- a/drivers/net/chelsio/my3126.c +++ /dev/null @@ -1,209 +0,0 @@ -/* $Date: 2005/11/12 02:13:49 $ $RCSfile: my3126.c,v $ $Revision: 1.15 $ */ -#include "cphy.h" -#include "elmer0.h" -#include "suni1x10gexp_regs.h" - -/* Port Reset */ -static int my3126_reset(struct cphy *cphy, int wait) -{ - /* - * This can be done through registers. It is not required since - * a full chip reset is used. - */ - return 0; -} - -static int my3126_interrupt_enable(struct cphy *cphy) -{ - schedule_delayed_work(&cphy->phy_update, HZ/30); - t1_tpi_read(cphy->adapter, A_ELMER0_GPO, &cphy->elmer_gpo); - return 0; -} - -static int my3126_interrupt_disable(struct cphy *cphy) -{ - cancel_delayed_work_sync(&cphy->phy_update); - return 0; -} - -static int my3126_interrupt_clear(struct cphy *cphy) -{ - return 0; -} - -#define OFFSET(REG_ADDR) (REG_ADDR << 2) - -static int my3126_interrupt_handler(struct cphy *cphy) -{ - u32 val; - u16 val16; - u16 status; - u32 act_count; - adapter_t *adapter; - adapter = cphy->adapter; - - if (cphy->count == 50) { - cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val); - val16 = (u16) val; - status = cphy->bmsr ^ val16; - - if (status & MDIO_STAT1_LSTATUS) - t1_link_changed(adapter, 0); - cphy->bmsr = val16; - - /* We have only enabled link change interrupts so it - must be that - */ - cphy->count = 0; - } - - t1_tpi_write(adapter, OFFSET(SUNI1x10GEXP_REG_MSTAT_CONTROL), - SUNI1x10GEXP_BITMSK_MSTAT_SNAP); - t1_tpi_read(adapter, - OFFSET(SUNI1x10GEXP_REG_MSTAT_COUNTER_1_LOW), &act_count); - t1_tpi_read(adapter, - OFFSET(SUNI1x10GEXP_REG_MSTAT_COUNTER_33_LOW), &val); - act_count += val; - - /* Populate elmer_gpo with the register value */ - t1_tpi_read(adapter, A_ELMER0_GPO, &val); - cphy->elmer_gpo = val; - - if ( (val & (1 << 8)) || (val & (1 << 19)) || - (cphy->act_count == act_count) || cphy->act_on ) { - if (is_T2(adapter)) - val |= (1 << 9); - else if (t1_is_T1B(adapter)) - val |= (1 << 20); - cphy->act_on = 0; - } else { - if (is_T2(adapter)) - val &= ~(1 << 9); - else if (t1_is_T1B(adapter)) - val &= ~(1 << 20); - cphy->act_on = 1; - } - - t1_tpi_write(adapter, A_ELMER0_GPO, val); - - cphy->elmer_gpo = val; - cphy->act_count = act_count; - cphy->count++; - - return cphy_cause_link_change; -} - -static void my3216_poll(struct work_struct *work) -{ - struct cphy *cphy = container_of(work, struct cphy, phy_update.work); - - my3126_interrupt_handler(cphy); -} - -static int my3126_set_loopback(struct cphy *cphy, int on) -{ - return 0; -} - -/* To check the activity LED */ -static int my3126_get_link_status(struct cphy *cphy, - int *link_ok, int *speed, int *duplex, int *fc) -{ - u32 val; - u16 val16; - adapter_t *adapter; - - adapter = cphy->adapter; - cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val); - val16 = (u16) val; - - /* Populate elmer_gpo with the register value */ - t1_tpi_read(adapter, A_ELMER0_GPO, &val); - cphy->elmer_gpo = val; - - *link_ok = (val16 & MDIO_STAT1_LSTATUS); - - if (*link_ok) { - /* Turn on the LED. */ - if (is_T2(adapter)) - val &= ~(1 << 8); - else if (t1_is_T1B(adapter)) - val &= ~(1 << 19); - } else { - /* Turn off the LED. */ - if (is_T2(adapter)) - val |= (1 << 8); - else if (t1_is_T1B(adapter)) - val |= (1 << 19); - } - - t1_tpi_write(adapter, A_ELMER0_GPO, val); - cphy->elmer_gpo = val; - *speed = SPEED_10000; - *duplex = DUPLEX_FULL; - - /* need to add flow control */ - if (fc) - *fc = PAUSE_RX | PAUSE_TX; - - return 0; -} - -static void my3126_destroy(struct cphy *cphy) -{ - kfree(cphy); -} - -static struct cphy_ops my3126_ops = { - .destroy = my3126_destroy, - .reset = my3126_reset, - .interrupt_enable = my3126_interrupt_enable, - .interrupt_disable = my3126_interrupt_disable, - .interrupt_clear = my3126_interrupt_clear, - .interrupt_handler = my3126_interrupt_handler, - .get_link_status = my3126_get_link_status, - .set_loopback = my3126_set_loopback, - .mmds = (MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | - MDIO_DEVS_PHYXS), -}; - -static struct cphy *my3126_phy_create(struct net_device *dev, - int phy_addr, const struct mdio_ops *mdio_ops) -{ - struct cphy *cphy = kzalloc(sizeof (*cphy), GFP_KERNEL); - - if (!cphy) - return NULL; - - cphy_init(cphy, dev, phy_addr, &my3126_ops, mdio_ops); - INIT_DELAYED_WORK(&cphy->phy_update, my3216_poll); - cphy->bmsr = 0; - - return cphy; -} - -/* Chip Reset */ -static int my3126_phy_reset(adapter_t * adapter) -{ - u32 val; - - t1_tpi_read(adapter, A_ELMER0_GPO, &val); - val &= ~4; - t1_tpi_write(adapter, A_ELMER0_GPO, val); - msleep(100); - - t1_tpi_write(adapter, A_ELMER0_GPO, val | 4); - msleep(1000); - - /* Now lets enable the Laser. Delay 100us */ - t1_tpi_read(adapter, A_ELMER0_GPO, &val); - val |= 0x8000; - t1_tpi_write(adapter, A_ELMER0_GPO, val); - udelay(100); - return 0; -} - -const struct gphy t1_my3126_ops = { - .create = my3126_phy_create, - .reset = my3126_phy_reset -}; diff --git a/drivers/net/chelsio/pm3393.c b/drivers/net/chelsio/pm3393.c deleted file mode 100644 index 40c7b93ababc..000000000000 --- a/drivers/net/chelsio/pm3393.c +++ /dev/null @@ -1,796 +0,0 @@ -/***************************************************************************** - * * - * File: pm3393.c * - * $Revision: 1.16 $ * - * $Date: 2005/05/14 00:59:32 $ * - * Description: * - * PMC/SIERRA (pm3393) MAC-PHY functionality. * - * part of the Chelsio 10Gb Ethernet Driver. * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * * - * http://www.chelsio.com * - * * - * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * - * All rights reserved. * - * * - * Maintainers: maintainers@chelsio.com * - * * - * Authors: Dimitrios Michailidis * - * Tina Yang * - * Felix Marti * - * Scott Bardone * - * Kurt Ottaway * - * Frank DiMambro * - * * - * History: * - * * - ****************************************************************************/ - -#include "common.h" -#include "regs.h" -#include "gmac.h" -#include "elmer0.h" -#include "suni1x10gexp_regs.h" - -#include -#include - -#define OFFSET(REG_ADDR) ((REG_ADDR) << 2) - -/* Max frame size PM3393 can handle. Includes Ethernet header and CRC. */ -#define MAX_FRAME_SIZE 9600 - -#define IPG 12 -#define TXXG_CONF1_VAL ((IPG << SUNI1x10GEXP_BITOFF_TXXG_IPGT) | \ - SUNI1x10GEXP_BITMSK_TXXG_32BIT_ALIGN | SUNI1x10GEXP_BITMSK_TXXG_CRCEN | \ - SUNI1x10GEXP_BITMSK_TXXG_PADEN) -#define RXXG_CONF1_VAL (SUNI1x10GEXP_BITMSK_RXXG_PUREP | 0x14 | \ - SUNI1x10GEXP_BITMSK_RXXG_FLCHK | SUNI1x10GEXP_BITMSK_RXXG_CRC_STRIP) - -/* Update statistics every 15 minutes */ -#define STATS_TICK_SECS (15 * 60) - -enum { /* RMON registers */ - RxOctetsReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_1_LOW, - RxUnicastFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_4_LOW, - RxMulticastFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_5_LOW, - RxBroadcastFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_6_LOW, - RxPAUSEMACCtrlFramesReceived = SUNI1x10GEXP_REG_MSTAT_COUNTER_8_LOW, - RxFrameCheckSequenceErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_10_LOW, - RxFramesLostDueToInternalMACErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_11_LOW, - RxSymbolErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_12_LOW, - RxInRangeLengthErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_13_LOW, - RxFramesTooLongErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_15_LOW, - RxJabbers = SUNI1x10GEXP_REG_MSTAT_COUNTER_16_LOW, - RxFragments = SUNI1x10GEXP_REG_MSTAT_COUNTER_17_LOW, - RxUndersizedFrames = SUNI1x10GEXP_REG_MSTAT_COUNTER_18_LOW, - RxJumboFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_25_LOW, - RxJumboOctetsReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_26_LOW, - - TxOctetsTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_33_LOW, - TxFramesLostDueToInternalMACTransmissionError = SUNI1x10GEXP_REG_MSTAT_COUNTER_35_LOW, - TxTransmitSystemError = SUNI1x10GEXP_REG_MSTAT_COUNTER_36_LOW, - TxUnicastFramesTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_38_LOW, - TxMulticastFramesTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_40_LOW, - TxBroadcastFramesTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_42_LOW, - TxPAUSEMACCtrlFramesTransmitted = SUNI1x10GEXP_REG_MSTAT_COUNTER_43_LOW, - TxJumboFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_51_LOW, - TxJumboOctetsReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_52_LOW -}; - -struct _cmac_instance { - u8 enabled; - u8 fc; - u8 mac_addr[6]; -}; - -static int pmread(struct cmac *cmac, u32 reg, u32 * data32) -{ - t1_tpi_read(cmac->adapter, OFFSET(reg), data32); - return 0; -} - -static int pmwrite(struct cmac *cmac, u32 reg, u32 data32) -{ - t1_tpi_write(cmac->adapter, OFFSET(reg), data32); - return 0; -} - -/* Port reset. */ -static int pm3393_reset(struct cmac *cmac) -{ - return 0; -} - -/* - * Enable interrupts for the PM3393 - * - * 1. Enable PM3393 BLOCK interrupts. - * 2. Enable PM3393 Master Interrupt bit(INTE) - * 3. Enable ELMER's PM3393 bit. - * 4. Enable Terminator external interrupt. - */ -static int pm3393_interrupt_enable(struct cmac *cmac) -{ - u32 pl_intr; - - /* PM3393 - Enabling all hardware block interrupts. - */ - pmwrite(cmac, SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_ENABLE, 0xffff); - pmwrite(cmac, SUNI1x10GEXP_REG_XRF_INTERRUPT_ENABLE, 0xffff); - pmwrite(cmac, SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_ENABLE, 0xffff); - pmwrite(cmac, SUNI1x10GEXP_REG_RXOAM_INTERRUPT_ENABLE, 0xffff); - - /* Don't interrupt on statistics overflow, we are polling */ - pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_0, 0); - pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_1, 0); - pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_2, 0); - pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_3, 0); - - pmwrite(cmac, SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_ENABLE, 0xffff); - pmwrite(cmac, SUNI1x10GEXP_REG_PL4ODP_INTERRUPT_MASK, 0xffff); - pmwrite(cmac, SUNI1x10GEXP_REG_XTEF_INTERRUPT_ENABLE, 0xffff); - pmwrite(cmac, SUNI1x10GEXP_REG_TXOAM_INTERRUPT_ENABLE, 0xffff); - pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_3, 0xffff); - pmwrite(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_MASK, 0xffff); - pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_3, 0xffff); - pmwrite(cmac, SUNI1x10GEXP_REG_PL4IDU_INTERRUPT_MASK, 0xffff); - pmwrite(cmac, SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_ENABLE, 0xffff); - - /* PM3393 - Global interrupt enable - */ - /* TBD XXX Disable for now until we figure out why error interrupts keep asserting. */ - pmwrite(cmac, SUNI1x10GEXP_REG_GLOBAL_INTERRUPT_ENABLE, - 0 /*SUNI1x10GEXP_BITMSK_TOP_INTE */ ); - - /* TERMINATOR - PL_INTERUPTS_EXT */ - pl_intr = readl(cmac->adapter->regs + A_PL_ENABLE); - pl_intr |= F_PL_INTR_EXT; - writel(pl_intr, cmac->adapter->regs + A_PL_ENABLE); - return 0; -} - -static int pm3393_interrupt_disable(struct cmac *cmac) -{ - u32 elmer; - - /* PM3393 - Enabling HW interrupt blocks. */ - pmwrite(cmac, SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_ENABLE, 0); - pmwrite(cmac, SUNI1x10GEXP_REG_XRF_INTERRUPT_ENABLE, 0); - pmwrite(cmac, SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_ENABLE, 0); - pmwrite(cmac, SUNI1x10GEXP_REG_RXOAM_INTERRUPT_ENABLE, 0); - pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_0, 0); - pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_1, 0); - pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_2, 0); - pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_3, 0); - pmwrite(cmac, SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_ENABLE, 0); - pmwrite(cmac, SUNI1x10GEXP_REG_PL4ODP_INTERRUPT_MASK, 0); - pmwrite(cmac, SUNI1x10GEXP_REG_XTEF_INTERRUPT_ENABLE, 0); - pmwrite(cmac, SUNI1x10GEXP_REG_TXOAM_INTERRUPT_ENABLE, 0); - pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_3, 0); - pmwrite(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_MASK, 0); - pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_3, 0); - pmwrite(cmac, SUNI1x10GEXP_REG_PL4IDU_INTERRUPT_MASK, 0); - pmwrite(cmac, SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_ENABLE, 0); - - /* PM3393 - Global interrupt enable */ - pmwrite(cmac, SUNI1x10GEXP_REG_GLOBAL_INTERRUPT_ENABLE, 0); - - /* ELMER - External chip interrupts. */ - t1_tpi_read(cmac->adapter, A_ELMER0_INT_ENABLE, &elmer); - elmer &= ~ELMER0_GP_BIT1; - t1_tpi_write(cmac->adapter, A_ELMER0_INT_ENABLE, elmer); - - /* TERMINATOR - PL_INTERUPTS_EXT */ - /* DO NOT DISABLE TERMINATOR's EXTERNAL INTERRUPTS. ANOTHER CHIP - * COULD WANT THEM ENABLED. We disable PM3393 at the ELMER level. - */ - - return 0; -} - -static int pm3393_interrupt_clear(struct cmac *cmac) -{ - u32 elmer; - u32 pl_intr; - u32 val32; - - /* PM3393 - Clearing HW interrupt blocks. Note, this assumes - * bit WCIMODE=0 for a clear-on-read. - */ - pmread(cmac, SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_STATUS, &val32); - pmread(cmac, SUNI1x10GEXP_REG_XRF_INTERRUPT_STATUS, &val32); - pmread(cmac, SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_STATUS, &val32); - pmread(cmac, SUNI1x10GEXP_REG_RXOAM_INTERRUPT_STATUS, &val32); - pmread(cmac, SUNI1x10GEXP_REG_PL4ODP_INTERRUPT, &val32); - pmread(cmac, SUNI1x10GEXP_REG_XTEF_INTERRUPT_STATUS, &val32); - pmread(cmac, SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_INTERRUPT, &val32); - pmread(cmac, SUNI1x10GEXP_REG_TXOAM_INTERRUPT_STATUS, &val32); - pmread(cmac, SUNI1x10GEXP_REG_RXXG_INTERRUPT, &val32); - pmread(cmac, SUNI1x10GEXP_REG_TXXG_INTERRUPT, &val32); - pmread(cmac, SUNI1x10GEXP_REG_PL4IDU_INTERRUPT, &val32); - pmread(cmac, SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_INDICATION, - &val32); - pmread(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_STATUS, &val32); - pmread(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_CHANGE, &val32); - - /* PM3393 - Global interrupt status - */ - pmread(cmac, SUNI1x10GEXP_REG_MASTER_INTERRUPT_STATUS, &val32); - - /* ELMER - External chip interrupts. - */ - t1_tpi_read(cmac->adapter, A_ELMER0_INT_CAUSE, &elmer); - elmer |= ELMER0_GP_BIT1; - t1_tpi_write(cmac->adapter, A_ELMER0_INT_CAUSE, elmer); - - /* TERMINATOR - PL_INTERUPTS_EXT - */ - pl_intr = readl(cmac->adapter->regs + A_PL_CAUSE); - pl_intr |= F_PL_INTR_EXT; - writel(pl_intr, cmac->adapter->regs + A_PL_CAUSE); - - return 0; -} - -/* Interrupt handler */ -static int pm3393_interrupt_handler(struct cmac *cmac) -{ - u32 master_intr_status; - - /* Read the master interrupt status register. */ - pmread(cmac, SUNI1x10GEXP_REG_MASTER_INTERRUPT_STATUS, - &master_intr_status); - if (netif_msg_intr(cmac->adapter)) - dev_dbg(&cmac->adapter->pdev->dev, "PM3393 intr cause 0x%x\n", - master_intr_status); - - /* TBD XXX Lets just clear everything for now */ - pm3393_interrupt_clear(cmac); - - return 0; -} - -static int pm3393_enable(struct cmac *cmac, int which) -{ - if (which & MAC_DIRECTION_RX) - pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_1, - (RXXG_CONF1_VAL | SUNI1x10GEXP_BITMSK_RXXG_RXEN)); - - if (which & MAC_DIRECTION_TX) { - u32 val = TXXG_CONF1_VAL | SUNI1x10GEXP_BITMSK_TXXG_TXEN0; - - if (cmac->instance->fc & PAUSE_RX) - val |= SUNI1x10GEXP_BITMSK_TXXG_FCRX; - if (cmac->instance->fc & PAUSE_TX) - val |= SUNI1x10GEXP_BITMSK_TXXG_FCTX; - pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_1, val); - } - - cmac->instance->enabled |= which; - return 0; -} - -static int pm3393_enable_port(struct cmac *cmac, int which) -{ - /* Clear port statistics */ - pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_CONTROL, - SUNI1x10GEXP_BITMSK_MSTAT_CLEAR); - udelay(2); - memset(&cmac->stats, 0, sizeof(struct cmac_statistics)); - - pm3393_enable(cmac, which); - - /* - * XXX This should be done by the PHY and preferably not at all. - * The PHY doesn't give us link status indication on its own so have - * the link management code query it instead. - */ - t1_link_changed(cmac->adapter, 0); - return 0; -} - -static int pm3393_disable(struct cmac *cmac, int which) -{ - if (which & MAC_DIRECTION_RX) - pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_1, RXXG_CONF1_VAL); - if (which & MAC_DIRECTION_TX) - pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_1, TXXG_CONF1_VAL); - - /* - * The disable is graceful. Give the PM3393 time. Can't wait very - * long here, we may be holding locks. - */ - udelay(20); - - cmac->instance->enabled &= ~which; - return 0; -} - -static int pm3393_loopback_enable(struct cmac *cmac) -{ - return 0; -} - -static int pm3393_loopback_disable(struct cmac *cmac) -{ - return 0; -} - -static int pm3393_set_mtu(struct cmac *cmac, int mtu) -{ - int enabled = cmac->instance->enabled; - - /* MAX_FRAME_SIZE includes header + FCS, mtu doesn't */ - mtu += 14 + 4; - if (mtu > MAX_FRAME_SIZE) - return -EINVAL; - - /* Disable Rx/Tx MAC before configuring it. */ - if (enabled) - pm3393_disable(cmac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); - - pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MAX_FRAME_LENGTH, mtu); - pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_MAX_FRAME_SIZE, mtu); - - if (enabled) - pm3393_enable(cmac, enabled); - return 0; -} - -static int pm3393_set_rx_mode(struct cmac *cmac, struct t1_rx_mode *rm) -{ - int enabled = cmac->instance->enabled & MAC_DIRECTION_RX; - u32 rx_mode; - - /* Disable MAC RX before reconfiguring it */ - if (enabled) - pm3393_disable(cmac, MAC_DIRECTION_RX); - - pmread(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_2, &rx_mode); - rx_mode &= ~(SUNI1x10GEXP_BITMSK_RXXG_PMODE | - SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN); - pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_2, - (u16)rx_mode); - - if (t1_rx_mode_promisc(rm)) { - /* Promiscuous mode. */ - rx_mode |= SUNI1x10GEXP_BITMSK_RXXG_PMODE; - } - if (t1_rx_mode_allmulti(rm)) { - /* Accept all multicast. */ - pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_LOW, 0xffff); - pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDLOW, 0xffff); - pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDHIGH, 0xffff); - pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_HIGH, 0xffff); - rx_mode |= SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN; - } else if (t1_rx_mode_mc_cnt(rm)) { - /* Accept one or more multicast(s). */ - struct netdev_hw_addr *ha; - int bit; - u16 mc_filter[4] = { 0, }; - - netdev_for_each_mc_addr(ha, t1_get_netdev(rm)) { - /* bit[23:28] */ - bit = (ether_crc(ETH_ALEN, ha->addr) >> 23) & 0x3f; - mc_filter[bit >> 4] |= 1 << (bit & 0xf); - } - pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_LOW, mc_filter[0]); - pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDLOW, mc_filter[1]); - pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDHIGH, mc_filter[2]); - pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_HIGH, mc_filter[3]); - rx_mode |= SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN; - } - - pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_2, (u16)rx_mode); - - if (enabled) - pm3393_enable(cmac, MAC_DIRECTION_RX); - - return 0; -} - -static int pm3393_get_speed_duplex_fc(struct cmac *cmac, int *speed, - int *duplex, int *fc) -{ - if (speed) - *speed = SPEED_10000; - if (duplex) - *duplex = DUPLEX_FULL; - if (fc) - *fc = cmac->instance->fc; - return 0; -} - -static int pm3393_set_speed_duplex_fc(struct cmac *cmac, int speed, int duplex, - int fc) -{ - if (speed >= 0 && speed != SPEED_10000) - return -1; - if (duplex >= 0 && duplex != DUPLEX_FULL) - return -1; - if (fc & ~(PAUSE_TX | PAUSE_RX)) - return -1; - - if (fc != cmac->instance->fc) { - cmac->instance->fc = (u8) fc; - if (cmac->instance->enabled & MAC_DIRECTION_TX) - pm3393_enable(cmac, MAC_DIRECTION_TX); - } - return 0; -} - -#define RMON_UPDATE(mac, name, stat_name) \ -{ \ - t1_tpi_read((mac)->adapter, OFFSET(name), &val0); \ - t1_tpi_read((mac)->adapter, OFFSET((name)+1), &val1); \ - t1_tpi_read((mac)->adapter, OFFSET((name)+2), &val2); \ - (mac)->stats.stat_name = (u64)(val0 & 0xffff) | \ - ((u64)(val1 & 0xffff) << 16) | \ - ((u64)(val2 & 0xff) << 32) | \ - ((mac)->stats.stat_name & \ - 0xffffff0000000000ULL); \ - if (ro & \ - (1ULL << ((name - SUNI1x10GEXP_REG_MSTAT_COUNTER_0_LOW) >> 2))) \ - (mac)->stats.stat_name += 1ULL << 40; \ -} - -static const struct cmac_statistics *pm3393_update_statistics(struct cmac *mac, - int flag) -{ - u64 ro; - u32 val0, val1, val2, val3; - - /* Snap the counters */ - pmwrite(mac, SUNI1x10GEXP_REG_MSTAT_CONTROL, - SUNI1x10GEXP_BITMSK_MSTAT_SNAP); - - /* Counter rollover, clear on read */ - pmread(mac, SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_0, &val0); - pmread(mac, SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_1, &val1); - pmread(mac, SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_2, &val2); - pmread(mac, SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_3, &val3); - ro = ((u64)val0 & 0xffff) | (((u64)val1 & 0xffff) << 16) | - (((u64)val2 & 0xffff) << 32) | (((u64)val3 & 0xffff) << 48); - - /* Rx stats */ - RMON_UPDATE(mac, RxOctetsReceivedOK, RxOctetsOK); - RMON_UPDATE(mac, RxUnicastFramesReceivedOK, RxUnicastFramesOK); - RMON_UPDATE(mac, RxMulticastFramesReceivedOK, RxMulticastFramesOK); - RMON_UPDATE(mac, RxBroadcastFramesReceivedOK, RxBroadcastFramesOK); - RMON_UPDATE(mac, RxPAUSEMACCtrlFramesReceived, RxPauseFrames); - RMON_UPDATE(mac, RxFrameCheckSequenceErrors, RxFCSErrors); - RMON_UPDATE(mac, RxFramesLostDueToInternalMACErrors, - RxInternalMACRcvError); - RMON_UPDATE(mac, RxSymbolErrors, RxSymbolErrors); - RMON_UPDATE(mac, RxInRangeLengthErrors, RxInRangeLengthErrors); - RMON_UPDATE(mac, RxFramesTooLongErrors , RxFrameTooLongErrors); - RMON_UPDATE(mac, RxJabbers, RxJabberErrors); - RMON_UPDATE(mac, RxFragments, RxRuntErrors); - RMON_UPDATE(mac, RxUndersizedFrames, RxRuntErrors); - RMON_UPDATE(mac, RxJumboFramesReceivedOK, RxJumboFramesOK); - RMON_UPDATE(mac, RxJumboOctetsReceivedOK, RxJumboOctetsOK); - - /* Tx stats */ - RMON_UPDATE(mac, TxOctetsTransmittedOK, TxOctetsOK); - RMON_UPDATE(mac, TxFramesLostDueToInternalMACTransmissionError, - TxInternalMACXmitError); - RMON_UPDATE(mac, TxTransmitSystemError, TxFCSErrors); - RMON_UPDATE(mac, TxUnicastFramesTransmittedOK, TxUnicastFramesOK); - RMON_UPDATE(mac, TxMulticastFramesTransmittedOK, TxMulticastFramesOK); - RMON_UPDATE(mac, TxBroadcastFramesTransmittedOK, TxBroadcastFramesOK); - RMON_UPDATE(mac, TxPAUSEMACCtrlFramesTransmitted, TxPauseFrames); - RMON_UPDATE(mac, TxJumboFramesReceivedOK, TxJumboFramesOK); - RMON_UPDATE(mac, TxJumboOctetsReceivedOK, TxJumboOctetsOK); - - return &mac->stats; -} - -static int pm3393_macaddress_get(struct cmac *cmac, u8 mac_addr[6]) -{ - memcpy(mac_addr, cmac->instance->mac_addr, 6); - return 0; -} - -static int pm3393_macaddress_set(struct cmac *cmac, u8 ma[6]) -{ - u32 val, lo, mid, hi, enabled = cmac->instance->enabled; - - /* - * MAC addr: 00:07:43:00:13:09 - * - * ma[5] = 0x09 - * ma[4] = 0x13 - * ma[3] = 0x00 - * ma[2] = 0x43 - * ma[1] = 0x07 - * ma[0] = 0x00 - * - * The PM3393 requires byte swapping and reverse order entry - * when programming MAC addresses: - * - * low_bits[15:0] = ma[1]:ma[0] - * mid_bits[31:16] = ma[3]:ma[2] - * high_bits[47:32] = ma[5]:ma[4] - */ - - /* Store local copy */ - memcpy(cmac->instance->mac_addr, ma, 6); - - lo = ((u32) ma[1] << 8) | (u32) ma[0]; - mid = ((u32) ma[3] << 8) | (u32) ma[2]; - hi = ((u32) ma[5] << 8) | (u32) ma[4]; - - /* Disable Rx/Tx MAC before configuring it. */ - if (enabled) - pm3393_disable(cmac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); - - /* Set RXXG Station Address */ - pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_SA_15_0, lo); - pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_SA_31_16, mid); - pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_SA_47_32, hi); - - /* Set TXXG Station Address */ - pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_SA_15_0, lo); - pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_SA_31_16, mid); - pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_SA_47_32, hi); - - /* Setup Exact Match Filter 1 with our MAC address - * - * Must disable exact match filter before configuring it. - */ - pmread(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_0, &val); - val &= 0xff0f; - pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_0, val); - - pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_LOW, lo); - pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_MID, mid); - pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_HIGH, hi); - - val |= 0x0090; - pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_0, val); - - if (enabled) - pm3393_enable(cmac, enabled); - return 0; -} - -static void pm3393_destroy(struct cmac *cmac) -{ - kfree(cmac); -} - -static struct cmac_ops pm3393_ops = { - .destroy = pm3393_destroy, - .reset = pm3393_reset, - .interrupt_enable = pm3393_interrupt_enable, - .interrupt_disable = pm3393_interrupt_disable, - .interrupt_clear = pm3393_interrupt_clear, - .interrupt_handler = pm3393_interrupt_handler, - .enable = pm3393_enable_port, - .disable = pm3393_disable, - .loopback_enable = pm3393_loopback_enable, - .loopback_disable = pm3393_loopback_disable, - .set_mtu = pm3393_set_mtu, - .set_rx_mode = pm3393_set_rx_mode, - .get_speed_duplex_fc = pm3393_get_speed_duplex_fc, - .set_speed_duplex_fc = pm3393_set_speed_duplex_fc, - .statistics_update = pm3393_update_statistics, - .macaddress_get = pm3393_macaddress_get, - .macaddress_set = pm3393_macaddress_set -}; - -static struct cmac *pm3393_mac_create(adapter_t *adapter, int index) -{ - struct cmac *cmac; - - cmac = kzalloc(sizeof(*cmac) + sizeof(cmac_instance), GFP_KERNEL); - if (!cmac) - return NULL; - - cmac->ops = &pm3393_ops; - cmac->instance = (cmac_instance *) (cmac + 1); - cmac->adapter = adapter; - cmac->instance->fc = PAUSE_TX | PAUSE_RX; - - t1_tpi_write(adapter, OFFSET(0x0001), 0x00008000); - t1_tpi_write(adapter, OFFSET(0x0001), 0x00000000); - t1_tpi_write(adapter, OFFSET(0x2308), 0x00009800); - t1_tpi_write(adapter, OFFSET(0x2305), 0x00001001); /* PL4IO Enable */ - t1_tpi_write(adapter, OFFSET(0x2320), 0x00008800); - t1_tpi_write(adapter, OFFSET(0x2321), 0x00008800); - t1_tpi_write(adapter, OFFSET(0x2322), 0x00008800); - t1_tpi_write(adapter, OFFSET(0x2323), 0x00008800); - t1_tpi_write(adapter, OFFSET(0x2324), 0x00008800); - t1_tpi_write(adapter, OFFSET(0x2325), 0x00008800); - t1_tpi_write(adapter, OFFSET(0x2326), 0x00008800); - t1_tpi_write(adapter, OFFSET(0x2327), 0x00008800); - t1_tpi_write(adapter, OFFSET(0x2328), 0x00008800); - t1_tpi_write(adapter, OFFSET(0x2329), 0x00008800); - t1_tpi_write(adapter, OFFSET(0x232a), 0x00008800); - t1_tpi_write(adapter, OFFSET(0x232b), 0x00008800); - t1_tpi_write(adapter, OFFSET(0x232c), 0x00008800); - t1_tpi_write(adapter, OFFSET(0x232d), 0x00008800); - t1_tpi_write(adapter, OFFSET(0x232e), 0x00008800); - t1_tpi_write(adapter, OFFSET(0x232f), 0x00008800); - t1_tpi_write(adapter, OFFSET(0x230d), 0x00009c00); - t1_tpi_write(adapter, OFFSET(0x2304), 0x00000202); /* PL4IO Calendar Repetitions */ - - t1_tpi_write(adapter, OFFSET(0x3200), 0x00008080); /* EFLX Enable */ - t1_tpi_write(adapter, OFFSET(0x3210), 0x00000000); /* EFLX Channel Deprovision */ - t1_tpi_write(adapter, OFFSET(0x3203), 0x00000000); /* EFLX Low Limit */ - t1_tpi_write(adapter, OFFSET(0x3204), 0x00000040); /* EFLX High Limit */ - t1_tpi_write(adapter, OFFSET(0x3205), 0x000002cc); /* EFLX Almost Full */ - t1_tpi_write(adapter, OFFSET(0x3206), 0x00000199); /* EFLX Almost Empty */ - t1_tpi_write(adapter, OFFSET(0x3207), 0x00000240); /* EFLX Cut Through Threshold */ - t1_tpi_write(adapter, OFFSET(0x3202), 0x00000000); /* EFLX Indirect Register Update */ - t1_tpi_write(adapter, OFFSET(0x3210), 0x00000001); /* EFLX Channel Provision */ - t1_tpi_write(adapter, OFFSET(0x3208), 0x0000ffff); /* EFLX Undocumented */ - t1_tpi_write(adapter, OFFSET(0x320a), 0x0000ffff); /* EFLX Undocumented */ - t1_tpi_write(adapter, OFFSET(0x320c), 0x0000ffff); /* EFLX enable overflow interrupt The other bit are undocumented */ - t1_tpi_write(adapter, OFFSET(0x320e), 0x0000ffff); /* EFLX Undocumented */ - - t1_tpi_write(adapter, OFFSET(0x2200), 0x0000c000); /* IFLX Configuration - enable */ - t1_tpi_write(adapter, OFFSET(0x2201), 0x00000000); /* IFLX Channel Deprovision */ - t1_tpi_write(adapter, OFFSET(0x220e), 0x00000000); /* IFLX Low Limit */ - t1_tpi_write(adapter, OFFSET(0x220f), 0x00000100); /* IFLX High Limit */ - t1_tpi_write(adapter, OFFSET(0x2210), 0x00000c00); /* IFLX Almost Full Limit */ - t1_tpi_write(adapter, OFFSET(0x2211), 0x00000599); /* IFLX Almost Empty Limit */ - t1_tpi_write(adapter, OFFSET(0x220d), 0x00000000); /* IFLX Indirect Register Update */ - t1_tpi_write(adapter, OFFSET(0x2201), 0x00000001); /* IFLX Channel Provision */ - t1_tpi_write(adapter, OFFSET(0x2203), 0x0000ffff); /* IFLX Undocumented */ - t1_tpi_write(adapter, OFFSET(0x2205), 0x0000ffff); /* IFLX Undocumented */ - t1_tpi_write(adapter, OFFSET(0x2209), 0x0000ffff); /* IFLX Enable overflow interrupt. The other bit are undocumented */ - - t1_tpi_write(adapter, OFFSET(0x2241), 0xfffffffe); /* PL4MOS Undocumented */ - t1_tpi_write(adapter, OFFSET(0x2242), 0x0000ffff); /* PL4MOS Undocumented */ - t1_tpi_write(adapter, OFFSET(0x2243), 0x00000008); /* PL4MOS Starving Burst Size */ - t1_tpi_write(adapter, OFFSET(0x2244), 0x00000008); /* PL4MOS Hungry Burst Size */ - t1_tpi_write(adapter, OFFSET(0x2245), 0x00000008); /* PL4MOS Transfer Size */ - t1_tpi_write(adapter, OFFSET(0x2240), 0x00000005); /* PL4MOS Disable */ - - t1_tpi_write(adapter, OFFSET(0x2280), 0x00002103); /* PL4ODP Training Repeat and SOP rule */ - t1_tpi_write(adapter, OFFSET(0x2284), 0x00000000); /* PL4ODP MAX_T setting */ - - t1_tpi_write(adapter, OFFSET(0x3280), 0x00000087); /* PL4IDU Enable data forward, port state machine. Set ALLOW_NON_ZERO_OLB */ - t1_tpi_write(adapter, OFFSET(0x3282), 0x0000001f); /* PL4IDU Enable Dip4 check error interrupts */ - - t1_tpi_write(adapter, OFFSET(0x3040), 0x0c32); /* # TXXG Config */ - /* For T1 use timer based Mac flow control. */ - t1_tpi_write(adapter, OFFSET(0x304d), 0x8000); - t1_tpi_write(adapter, OFFSET(0x2040), 0x059c); /* # RXXG Config */ - t1_tpi_write(adapter, OFFSET(0x2049), 0x0001); /* # RXXG Cut Through */ - t1_tpi_write(adapter, OFFSET(0x2070), 0x0000); /* # Disable promiscuous mode */ - - /* Setup Exact Match Filter 0 to allow broadcast packets. - */ - t1_tpi_write(adapter, OFFSET(0x206e), 0x0000); /* # Disable Match Enable bit */ - t1_tpi_write(adapter, OFFSET(0x204a), 0xffff); /* # low addr */ - t1_tpi_write(adapter, OFFSET(0x204b), 0xffff); /* # mid addr */ - t1_tpi_write(adapter, OFFSET(0x204c), 0xffff); /* # high addr */ - t1_tpi_write(adapter, OFFSET(0x206e), 0x0009); /* # Enable Match Enable bit */ - - t1_tpi_write(adapter, OFFSET(0x0003), 0x0000); /* # NO SOP/ PAD_EN setup */ - t1_tpi_write(adapter, OFFSET(0x0100), 0x0ff0); /* # RXEQB disabled */ - t1_tpi_write(adapter, OFFSET(0x0101), 0x0f0f); /* # No Preemphasis */ - - return cmac; -} - -static int pm3393_mac_reset(adapter_t * adapter) -{ - u32 val; - u32 x; - u32 is_pl4_reset_finished; - u32 is_pl4_outof_lock; - u32 is_xaui_mabc_pll_locked; - u32 successful_reset; - int i; - - /* The following steps are required to properly reset - * the PM3393. This information is provided in the - * PM3393 datasheet (Issue 2: November 2002) - * section 13.1 -- Device Reset. - * - * The PM3393 has three types of components that are - * individually reset: - * - * DRESETB - Digital circuitry - * PL4_ARESETB - PL4 analog circuitry - * XAUI_ARESETB - XAUI bus analog circuitry - * - * Steps to reset PM3393 using RSTB pin: - * - * 1. Assert RSTB pin low ( write 0 ) - * 2. Wait at least 1ms to initiate a complete initialization of device. - * 3. Wait until all external clocks and REFSEL are stable. - * 4. Wait minimum of 1ms. (after external clocks and REFEL are stable) - * 5. De-assert RSTB ( write 1 ) - * 6. Wait until internal timers to expires after ~14ms. - * - Allows analog clock synthesizer(PL4CSU) to stabilize to - * selected reference frequency before allowing the digital - * portion of the device to operate. - * 7. Wait at least 200us for XAUI interface to stabilize. - * 8. Verify the PM3393 came out of reset successfully. - * Set successful reset flag if everything worked else try again - * a few more times. - */ - - successful_reset = 0; - for (i = 0; i < 3 && !successful_reset; i++) { - /* 1 */ - t1_tpi_read(adapter, A_ELMER0_GPO, &val); - val &= ~1; - t1_tpi_write(adapter, A_ELMER0_GPO, val); - - /* 2 */ - msleep(1); - - /* 3 */ - msleep(1); - - /* 4 */ - msleep(2 /*1 extra ms for safety */ ); - - /* 5 */ - val |= 1; - t1_tpi_write(adapter, A_ELMER0_GPO, val); - - /* 6 */ - msleep(15 /*1 extra ms for safety */ ); - - /* 7 */ - msleep(1); - - /* 8 */ - - /* Has PL4 analog block come out of reset correctly? */ - t1_tpi_read(adapter, OFFSET(SUNI1x10GEXP_REG_DEVICE_STATUS), &val); - is_pl4_reset_finished = (val & SUNI1x10GEXP_BITMSK_TOP_EXPIRED); - - /* TBD XXX SUNI1x10GEXP_BITMSK_TOP_PL4_IS_DOOL gets locked later in the init sequence - * figure out why? */ - - /* Have all PL4 block clocks locked? */ - x = (SUNI1x10GEXP_BITMSK_TOP_PL4_ID_DOOL - /*| SUNI1x10GEXP_BITMSK_TOP_PL4_IS_DOOL */ | - SUNI1x10GEXP_BITMSK_TOP_PL4_ID_ROOL | - SUNI1x10GEXP_BITMSK_TOP_PL4_IS_ROOL | - SUNI1x10GEXP_BITMSK_TOP_PL4_OUT_ROOL); - is_pl4_outof_lock = (val & x); - - /* ??? If this fails, might be able to software reset the XAUI part - * and try to recover... thus saving us from doing another HW reset */ - /* Has the XAUI MABC PLL circuitry stablized? */ - is_xaui_mabc_pll_locked = - (val & SUNI1x10GEXP_BITMSK_TOP_SXRA_EXPIRED); - - successful_reset = (is_pl4_reset_finished && !is_pl4_outof_lock - && is_xaui_mabc_pll_locked); - - if (netif_msg_hw(adapter)) - dev_dbg(&adapter->pdev->dev, - "PM3393 HW reset %d: pl4_reset 0x%x, val 0x%x, " - "is_pl4_outof_lock 0x%x, xaui_locked 0x%x\n", - i, is_pl4_reset_finished, val, - is_pl4_outof_lock, is_xaui_mabc_pll_locked); - } - return successful_reset ? 0 : 1; -} - -const struct gmac t1_pm3393_ops = { - .stats_update_period = STATS_TICK_SECS, - .create = pm3393_mac_create, - .reset = pm3393_mac_reset, -}; diff --git a/drivers/net/chelsio/regs.h b/drivers/net/chelsio/regs.h deleted file mode 100644 index c80bf4d6d0a6..000000000000 --- a/drivers/net/chelsio/regs.h +++ /dev/null @@ -1,2168 +0,0 @@ -/***************************************************************************** - * * - * File: regs.h * - * $Revision: 1.8 $ * - * $Date: 2005/06/21 18:29:48 $ * - * Description: * - * part of the Chelsio 10Gb Ethernet Driver. * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * * - * http://www.chelsio.com * - * * - * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * - * All rights reserved. * - * * - * Maintainers: maintainers@chelsio.com * - * * - * Authors: Dimitrios Michailidis * - * Tina Yang * - * Felix Marti * - * Scott Bardone * - * Kurt Ottaway * - * Frank DiMambro * - * * - * History: * - * * - ****************************************************************************/ - -#ifndef _CXGB_REGS_H_ -#define _CXGB_REGS_H_ - -/* SGE registers */ -#define A_SG_CONTROL 0x0 - -#define S_CMDQ0_ENABLE 0 -#define V_CMDQ0_ENABLE(x) ((x) << S_CMDQ0_ENABLE) -#define F_CMDQ0_ENABLE V_CMDQ0_ENABLE(1U) - -#define S_CMDQ1_ENABLE 1 -#define V_CMDQ1_ENABLE(x) ((x) << S_CMDQ1_ENABLE) -#define F_CMDQ1_ENABLE V_CMDQ1_ENABLE(1U) - -#define S_FL0_ENABLE 2 -#define V_FL0_ENABLE(x) ((x) << S_FL0_ENABLE) -#define F_FL0_ENABLE V_FL0_ENABLE(1U) - -#define S_FL1_ENABLE 3 -#define V_FL1_ENABLE(x) ((x) << S_FL1_ENABLE) -#define F_FL1_ENABLE V_FL1_ENABLE(1U) - -#define S_CPL_ENABLE 4 -#define V_CPL_ENABLE(x) ((x) << S_CPL_ENABLE) -#define F_CPL_ENABLE V_CPL_ENABLE(1U) - -#define S_RESPONSE_QUEUE_ENABLE 5 -#define V_RESPONSE_QUEUE_ENABLE(x) ((x) << S_RESPONSE_QUEUE_ENABLE) -#define F_RESPONSE_QUEUE_ENABLE V_RESPONSE_QUEUE_ENABLE(1U) - -#define S_CMDQ_PRIORITY 6 -#define M_CMDQ_PRIORITY 0x3 -#define V_CMDQ_PRIORITY(x) ((x) << S_CMDQ_PRIORITY) -#define G_CMDQ_PRIORITY(x) (((x) >> S_CMDQ_PRIORITY) & M_CMDQ_PRIORITY) - -#define S_DISABLE_CMDQ0_GTS 8 -#define V_DISABLE_CMDQ0_GTS(x) ((x) << S_DISABLE_CMDQ0_GTS) -#define F_DISABLE_CMDQ0_GTS V_DISABLE_CMDQ0_GTS(1U) - -#define S_DISABLE_CMDQ1_GTS 9 -#define V_DISABLE_CMDQ1_GTS(x) ((x) << S_DISABLE_CMDQ1_GTS) -#define F_DISABLE_CMDQ1_GTS V_DISABLE_CMDQ1_GTS(1U) - -#define S_DISABLE_FL0_GTS 10 -#define V_DISABLE_FL0_GTS(x) ((x) << S_DISABLE_FL0_GTS) -#define F_DISABLE_FL0_GTS V_DISABLE_FL0_GTS(1U) - -#define S_DISABLE_FL1_GTS 11 -#define V_DISABLE_FL1_GTS(x) ((x) << S_DISABLE_FL1_GTS) -#define F_DISABLE_FL1_GTS V_DISABLE_FL1_GTS(1U) - -#define S_ENABLE_BIG_ENDIAN 12 -#define V_ENABLE_BIG_ENDIAN(x) ((x) << S_ENABLE_BIG_ENDIAN) -#define F_ENABLE_BIG_ENDIAN V_ENABLE_BIG_ENDIAN(1U) - -#define S_FL_SELECTION_CRITERIA 13 -#define V_FL_SELECTION_CRITERIA(x) ((x) << S_FL_SELECTION_CRITERIA) -#define F_FL_SELECTION_CRITERIA V_FL_SELECTION_CRITERIA(1U) - -#define S_ISCSI_COALESCE 14 -#define V_ISCSI_COALESCE(x) ((x) << S_ISCSI_COALESCE) -#define F_ISCSI_COALESCE V_ISCSI_COALESCE(1U) - -#define S_RX_PKT_OFFSET 15 -#define M_RX_PKT_OFFSET 0x7 -#define V_RX_PKT_OFFSET(x) ((x) << S_RX_PKT_OFFSET) -#define G_RX_PKT_OFFSET(x) (((x) >> S_RX_PKT_OFFSET) & M_RX_PKT_OFFSET) - -#define S_VLAN_XTRACT 18 -#define V_VLAN_XTRACT(x) ((x) << S_VLAN_XTRACT) -#define F_VLAN_XTRACT V_VLAN_XTRACT(1U) - -#define A_SG_DOORBELL 0x4 -#define A_SG_CMD0BASELWR 0x8 -#define A_SG_CMD0BASEUPR 0xc -#define A_SG_CMD1BASELWR 0x10 -#define A_SG_CMD1BASEUPR 0x14 -#define A_SG_FL0BASELWR 0x18 -#define A_SG_FL0BASEUPR 0x1c -#define A_SG_FL1BASELWR 0x20 -#define A_SG_FL1BASEUPR 0x24 -#define A_SG_CMD0SIZE 0x28 - -#define S_CMDQ0_SIZE 0 -#define M_CMDQ0_SIZE 0x1ffff -#define V_CMDQ0_SIZE(x) ((x) << S_CMDQ0_SIZE) -#define G_CMDQ0_SIZE(x) (((x) >> S_CMDQ0_SIZE) & M_CMDQ0_SIZE) - -#define A_SG_FL0SIZE 0x2c - -#define S_FL0_SIZE 0 -#define M_FL0_SIZE 0x1ffff -#define V_FL0_SIZE(x) ((x) << S_FL0_SIZE) -#define G_FL0_SIZE(x) (((x) >> S_FL0_SIZE) & M_FL0_SIZE) - -#define A_SG_RSPSIZE 0x30 - -#define S_RESPQ_SIZE 0 -#define M_RESPQ_SIZE 0x1ffff -#define V_RESPQ_SIZE(x) ((x) << S_RESPQ_SIZE) -#define G_RESPQ_SIZE(x) (((x) >> S_RESPQ_SIZE) & M_RESPQ_SIZE) - -#define A_SG_RSPBASELWR 0x34 -#define A_SG_RSPBASEUPR 0x38 -#define A_SG_FLTHRESHOLD 0x3c - -#define S_FL_THRESHOLD 0 -#define M_FL_THRESHOLD 0xffff -#define V_FL_THRESHOLD(x) ((x) << S_FL_THRESHOLD) -#define G_FL_THRESHOLD(x) (((x) >> S_FL_THRESHOLD) & M_FL_THRESHOLD) - -#define A_SG_RSPQUEUECREDIT 0x40 - -#define S_RESPQ_CREDIT 0 -#define M_RESPQ_CREDIT 0x1ffff -#define V_RESPQ_CREDIT(x) ((x) << S_RESPQ_CREDIT) -#define G_RESPQ_CREDIT(x) (((x) >> S_RESPQ_CREDIT) & M_RESPQ_CREDIT) - -#define A_SG_SLEEPING 0x48 - -#define S_SLEEPING 0 -#define M_SLEEPING 0xffff -#define V_SLEEPING(x) ((x) << S_SLEEPING) -#define G_SLEEPING(x) (((x) >> S_SLEEPING) & M_SLEEPING) - -#define A_SG_INTRTIMER 0x4c - -#define S_INTERRUPT_TIMER_COUNT 0 -#define M_INTERRUPT_TIMER_COUNT 0xffffff -#define V_INTERRUPT_TIMER_COUNT(x) ((x) << S_INTERRUPT_TIMER_COUNT) -#define G_INTERRUPT_TIMER_COUNT(x) (((x) >> S_INTERRUPT_TIMER_COUNT) & M_INTERRUPT_TIMER_COUNT) - -#define A_SG_CMD0PTR 0x50 - -#define S_CMDQ0_POINTER 0 -#define M_CMDQ0_POINTER 0xffff -#define V_CMDQ0_POINTER(x) ((x) << S_CMDQ0_POINTER) -#define G_CMDQ0_POINTER(x) (((x) >> S_CMDQ0_POINTER) & M_CMDQ0_POINTER) - -#define S_CURRENT_GENERATION_BIT 16 -#define V_CURRENT_GENERATION_BIT(x) ((x) << S_CURRENT_GENERATION_BIT) -#define F_CURRENT_GENERATION_BIT V_CURRENT_GENERATION_BIT(1U) - -#define A_SG_CMD1PTR 0x54 - -#define S_CMDQ1_POINTER 0 -#define M_CMDQ1_POINTER 0xffff -#define V_CMDQ1_POINTER(x) ((x) << S_CMDQ1_POINTER) -#define G_CMDQ1_POINTER(x) (((x) >> S_CMDQ1_POINTER) & M_CMDQ1_POINTER) - -#define A_SG_FL0PTR 0x58 - -#define S_FL0_POINTER 0 -#define M_FL0_POINTER 0xffff -#define V_FL0_POINTER(x) ((x) << S_FL0_POINTER) -#define G_FL0_POINTER(x) (((x) >> S_FL0_POINTER) & M_FL0_POINTER) - -#define A_SG_FL1PTR 0x5c - -#define S_FL1_POINTER 0 -#define M_FL1_POINTER 0xffff -#define V_FL1_POINTER(x) ((x) << S_FL1_POINTER) -#define G_FL1_POINTER(x) (((x) >> S_FL1_POINTER) & M_FL1_POINTER) - -#define A_SG_VERSION 0x6c - -#define S_DAY 0 -#define M_DAY 0x1f -#define V_DAY(x) ((x) << S_DAY) -#define G_DAY(x) (((x) >> S_DAY) & M_DAY) - -#define S_MONTH 5 -#define M_MONTH 0xf -#define V_MONTH(x) ((x) << S_MONTH) -#define G_MONTH(x) (((x) >> S_MONTH) & M_MONTH) - -#define A_SG_CMD1SIZE 0xb0 - -#define S_CMDQ1_SIZE 0 -#define M_CMDQ1_SIZE 0x1ffff -#define V_CMDQ1_SIZE(x) ((x) << S_CMDQ1_SIZE) -#define G_CMDQ1_SIZE(x) (((x) >> S_CMDQ1_SIZE) & M_CMDQ1_SIZE) - -#define A_SG_FL1SIZE 0xb4 - -#define S_FL1_SIZE 0 -#define M_FL1_SIZE 0x1ffff -#define V_FL1_SIZE(x) ((x) << S_FL1_SIZE) -#define G_FL1_SIZE(x) (((x) >> S_FL1_SIZE) & M_FL1_SIZE) - -#define A_SG_INT_ENABLE 0xb8 - -#define S_RESPQ_EXHAUSTED 0 -#define V_RESPQ_EXHAUSTED(x) ((x) << S_RESPQ_EXHAUSTED) -#define F_RESPQ_EXHAUSTED V_RESPQ_EXHAUSTED(1U) - -#define S_RESPQ_OVERFLOW 1 -#define V_RESPQ_OVERFLOW(x) ((x) << S_RESPQ_OVERFLOW) -#define F_RESPQ_OVERFLOW V_RESPQ_OVERFLOW(1U) - -#define S_FL_EXHAUSTED 2 -#define V_FL_EXHAUSTED(x) ((x) << S_FL_EXHAUSTED) -#define F_FL_EXHAUSTED V_FL_EXHAUSTED(1U) - -#define S_PACKET_TOO_BIG 3 -#define V_PACKET_TOO_BIG(x) ((x) << S_PACKET_TOO_BIG) -#define F_PACKET_TOO_BIG V_PACKET_TOO_BIG(1U) - -#define S_PACKET_MISMATCH 4 -#define V_PACKET_MISMATCH(x) ((x) << S_PACKET_MISMATCH) -#define F_PACKET_MISMATCH V_PACKET_MISMATCH(1U) - -#define A_SG_INT_CAUSE 0xbc -#define A_SG_RESPACCUTIMER 0xc0 - -/* MC3 registers */ -#define A_MC3_CFG 0x100 - -#define S_CLK_ENABLE 0 -#define V_CLK_ENABLE(x) ((x) << S_CLK_ENABLE) -#define F_CLK_ENABLE V_CLK_ENABLE(1U) - -#define S_READY 1 -#define V_READY(x) ((x) << S_READY) -#define F_READY V_READY(1U) - -#define S_READ_TO_WRITE_DELAY 2 -#define M_READ_TO_WRITE_DELAY 0x7 -#define V_READ_TO_WRITE_DELAY(x) ((x) << S_READ_TO_WRITE_DELAY) -#define G_READ_TO_WRITE_DELAY(x) (((x) >> S_READ_TO_WRITE_DELAY) & M_READ_TO_WRITE_DELAY) - -#define S_WRITE_TO_READ_DELAY 5 -#define M_WRITE_TO_READ_DELAY 0x7 -#define V_WRITE_TO_READ_DELAY(x) ((x) << S_WRITE_TO_READ_DELAY) -#define G_WRITE_TO_READ_DELAY(x) (((x) >> S_WRITE_TO_READ_DELAY) & M_WRITE_TO_READ_DELAY) - -#define S_MC3_BANK_CYCLE 8 -#define M_MC3_BANK_CYCLE 0xf -#define V_MC3_BANK_CYCLE(x) ((x) << S_MC3_BANK_CYCLE) -#define G_MC3_BANK_CYCLE(x) (((x) >> S_MC3_BANK_CYCLE) & M_MC3_BANK_CYCLE) - -#define S_REFRESH_CYCLE 12 -#define M_REFRESH_CYCLE 0xf -#define V_REFRESH_CYCLE(x) ((x) << S_REFRESH_CYCLE) -#define G_REFRESH_CYCLE(x) (((x) >> S_REFRESH_CYCLE) & M_REFRESH_CYCLE) - -#define S_PRECHARGE_CYCLE 16 -#define M_PRECHARGE_CYCLE 0x3 -#define V_PRECHARGE_CYCLE(x) ((x) << S_PRECHARGE_CYCLE) -#define G_PRECHARGE_CYCLE(x) (((x) >> S_PRECHARGE_CYCLE) & M_PRECHARGE_CYCLE) - -#define S_ACTIVE_TO_READ_WRITE_DELAY 18 -#define V_ACTIVE_TO_READ_WRITE_DELAY(x) ((x) << S_ACTIVE_TO_READ_WRITE_DELAY) -#define F_ACTIVE_TO_READ_WRITE_DELAY V_ACTIVE_TO_READ_WRITE_DELAY(1U) - -#define S_ACTIVE_TO_PRECHARGE_DELAY 19 -#define M_ACTIVE_TO_PRECHARGE_DELAY 0x7 -#define V_ACTIVE_TO_PRECHARGE_DELAY(x) ((x) << S_ACTIVE_TO_PRECHARGE_DELAY) -#define G_ACTIVE_TO_PRECHARGE_DELAY(x) (((x) >> S_ACTIVE_TO_PRECHARGE_DELAY) & M_ACTIVE_TO_PRECHARGE_DELAY) - -#define S_WRITE_RECOVERY_DELAY 22 -#define M_WRITE_RECOVERY_DELAY 0x3 -#define V_WRITE_RECOVERY_DELAY(x) ((x) << S_WRITE_RECOVERY_DELAY) -#define G_WRITE_RECOVERY_DELAY(x) (((x) >> S_WRITE_RECOVERY_DELAY) & M_WRITE_RECOVERY_DELAY) - -#define S_DENSITY 24 -#define M_DENSITY 0x3 -#define V_DENSITY(x) ((x) << S_DENSITY) -#define G_DENSITY(x) (((x) >> S_DENSITY) & M_DENSITY) - -#define S_ORGANIZATION 26 -#define V_ORGANIZATION(x) ((x) << S_ORGANIZATION) -#define F_ORGANIZATION V_ORGANIZATION(1U) - -#define S_BANKS 27 -#define V_BANKS(x) ((x) << S_BANKS) -#define F_BANKS V_BANKS(1U) - -#define S_UNREGISTERED 28 -#define V_UNREGISTERED(x) ((x) << S_UNREGISTERED) -#define F_UNREGISTERED V_UNREGISTERED(1U) - -#define S_MC3_WIDTH 29 -#define M_MC3_WIDTH 0x3 -#define V_MC3_WIDTH(x) ((x) << S_MC3_WIDTH) -#define G_MC3_WIDTH(x) (((x) >> S_MC3_WIDTH) & M_MC3_WIDTH) - -#define S_MC3_SLOW 31 -#define V_MC3_SLOW(x) ((x) << S_MC3_SLOW) -#define F_MC3_SLOW V_MC3_SLOW(1U) - -#define A_MC3_MODE 0x104 - -#define S_MC3_MODE 0 -#define M_MC3_MODE 0x3fff -#define V_MC3_MODE(x) ((x) << S_MC3_MODE) -#define G_MC3_MODE(x) (((x) >> S_MC3_MODE) & M_MC3_MODE) - -#define S_BUSY 31 -#define V_BUSY(x) ((x) << S_BUSY) -#define F_BUSY V_BUSY(1U) - -#define A_MC3_EXT_MODE 0x108 - -#define S_MC3_EXTENDED_MODE 0 -#define M_MC3_EXTENDED_MODE 0x3fff -#define V_MC3_EXTENDED_MODE(x) ((x) << S_MC3_EXTENDED_MODE) -#define G_MC3_EXTENDED_MODE(x) (((x) >> S_MC3_EXTENDED_MODE) & M_MC3_EXTENDED_MODE) - -#define A_MC3_PRECHARG 0x10c -#define A_MC3_REFRESH 0x110 - -#define S_REFRESH_ENABLE 0 -#define V_REFRESH_ENABLE(x) ((x) << S_REFRESH_ENABLE) -#define F_REFRESH_ENABLE V_REFRESH_ENABLE(1U) - -#define S_REFRESH_DIVISOR 1 -#define M_REFRESH_DIVISOR 0x3fff -#define V_REFRESH_DIVISOR(x) ((x) << S_REFRESH_DIVISOR) -#define G_REFRESH_DIVISOR(x) (((x) >> S_REFRESH_DIVISOR) & M_REFRESH_DIVISOR) - -#define A_MC3_STROBE 0x114 - -#define S_MASTER_DLL_RESET 0 -#define V_MASTER_DLL_RESET(x) ((x) << S_MASTER_DLL_RESET) -#define F_MASTER_DLL_RESET V_MASTER_DLL_RESET(1U) - -#define S_MASTER_DLL_TAP_COUNT 1 -#define M_MASTER_DLL_TAP_COUNT 0xff -#define V_MASTER_DLL_TAP_COUNT(x) ((x) << S_MASTER_DLL_TAP_COUNT) -#define G_MASTER_DLL_TAP_COUNT(x) (((x) >> S_MASTER_DLL_TAP_COUNT) & M_MASTER_DLL_TAP_COUNT) - -#define S_MASTER_DLL_LOCKED 9 -#define V_MASTER_DLL_LOCKED(x) ((x) << S_MASTER_DLL_LOCKED) -#define F_MASTER_DLL_LOCKED V_MASTER_DLL_LOCKED(1U) - -#define S_MASTER_DLL_MAX_TAP_COUNT 10 -#define V_MASTER_DLL_MAX_TAP_COUNT(x) ((x) << S_MASTER_DLL_MAX_TAP_COUNT) -#define F_MASTER_DLL_MAX_TAP_COUNT V_MASTER_DLL_MAX_TAP_COUNT(1U) - -#define S_MASTER_DLL_TAP_COUNT_OFFSET 11 -#define M_MASTER_DLL_TAP_COUNT_OFFSET 0x3f -#define V_MASTER_DLL_TAP_COUNT_OFFSET(x) ((x) << S_MASTER_DLL_TAP_COUNT_OFFSET) -#define G_MASTER_DLL_TAP_COUNT_OFFSET(x) (((x) >> S_MASTER_DLL_TAP_COUNT_OFFSET) & M_MASTER_DLL_TAP_COUNT_OFFSET) - -#define S_SLAVE_DLL_RESET 11 -#define V_SLAVE_DLL_RESET(x) ((x) << S_SLAVE_DLL_RESET) -#define F_SLAVE_DLL_RESET V_SLAVE_DLL_RESET(1U) - -#define S_SLAVE_DLL_DELTA 12 -#define M_SLAVE_DLL_DELTA 0xf -#define V_SLAVE_DLL_DELTA(x) ((x) << S_SLAVE_DLL_DELTA) -#define G_SLAVE_DLL_DELTA(x) (((x) >> S_SLAVE_DLL_DELTA) & M_SLAVE_DLL_DELTA) - -#define S_SLAVE_DELAY_LINE_MANUAL_TAP_COUNT 17 -#define M_SLAVE_DELAY_LINE_MANUAL_TAP_COUNT 0x3f -#define V_SLAVE_DELAY_LINE_MANUAL_TAP_COUNT(x) ((x) << S_SLAVE_DELAY_LINE_MANUAL_TAP_COUNT) -#define G_SLAVE_DELAY_LINE_MANUAL_TAP_COUNT(x) (((x) >> S_SLAVE_DELAY_LINE_MANUAL_TAP_COUNT) & M_SLAVE_DELAY_LINE_MANUAL_TAP_COUNT) - -#define S_SLAVE_DELAY_LINE_MANUAL_TAP_COUNT_ENABLE 23 -#define V_SLAVE_DELAY_LINE_MANUAL_TAP_COUNT_ENABLE(x) ((x) << S_SLAVE_DELAY_LINE_MANUAL_TAP_COUNT_ENABLE) -#define F_SLAVE_DELAY_LINE_MANUAL_TAP_COUNT_ENABLE V_SLAVE_DELAY_LINE_MANUAL_TAP_COUNT_ENABLE(1U) - -#define S_SLAVE_DELAY_LINE_TAP_COUNT 24 -#define M_SLAVE_DELAY_LINE_TAP_COUNT 0x3f -#define V_SLAVE_DELAY_LINE_TAP_COUNT(x) ((x) << S_SLAVE_DELAY_LINE_TAP_COUNT) -#define G_SLAVE_DELAY_LINE_TAP_COUNT(x) (((x) >> S_SLAVE_DELAY_LINE_TAP_COUNT) & M_SLAVE_DELAY_LINE_TAP_COUNT) - -#define A_MC3_ECC_CNTL 0x118 - -#define S_ECC_GENERATION_ENABLE 0 -#define V_ECC_GENERATION_ENABLE(x) ((x) << S_ECC_GENERATION_ENABLE) -#define F_ECC_GENERATION_ENABLE V_ECC_GENERATION_ENABLE(1U) - -#define S_ECC_CHECK_ENABLE 1 -#define V_ECC_CHECK_ENABLE(x) ((x) << S_ECC_CHECK_ENABLE) -#define F_ECC_CHECK_ENABLE V_ECC_CHECK_ENABLE(1U) - -#define S_CORRECTABLE_ERROR_COUNT 2 -#define M_CORRECTABLE_ERROR_COUNT 0xff -#define V_CORRECTABLE_ERROR_COUNT(x) ((x) << S_CORRECTABLE_ERROR_COUNT) -#define G_CORRECTABLE_ERROR_COUNT(x) (((x) >> S_CORRECTABLE_ERROR_COUNT) & M_CORRECTABLE_ERROR_COUNT) - -#define S_UNCORRECTABLE_ERROR_COUNT 10 -#define M_UNCORRECTABLE_ERROR_COUNT 0xff -#define V_UNCORRECTABLE_ERROR_COUNT(x) ((x) << S_UNCORRECTABLE_ERROR_COUNT) -#define G_UNCORRECTABLE_ERROR_COUNT(x) (((x) >> S_UNCORRECTABLE_ERROR_COUNT) & M_UNCORRECTABLE_ERROR_COUNT) - -#define A_MC3_CE_ADDR 0x11c - -#define S_MC3_CE_ADDR 4 -#define M_MC3_CE_ADDR 0xfffffff -#define V_MC3_CE_ADDR(x) ((x) << S_MC3_CE_ADDR) -#define G_MC3_CE_ADDR(x) (((x) >> S_MC3_CE_ADDR) & M_MC3_CE_ADDR) - -#define A_MC3_CE_DATA0 0x120 -#define A_MC3_CE_DATA1 0x124 -#define A_MC3_CE_DATA2 0x128 -#define A_MC3_CE_DATA3 0x12c -#define A_MC3_CE_DATA4 0x130 -#define A_MC3_UE_ADDR 0x134 - -#define S_MC3_UE_ADDR 4 -#define M_MC3_UE_ADDR 0xfffffff -#define V_MC3_UE_ADDR(x) ((x) << S_MC3_UE_ADDR) -#define G_MC3_UE_ADDR(x) (((x) >> S_MC3_UE_ADDR) & M_MC3_UE_ADDR) - -#define A_MC3_UE_DATA0 0x138 -#define A_MC3_UE_DATA1 0x13c -#define A_MC3_UE_DATA2 0x140 -#define A_MC3_UE_DATA3 0x144 -#define A_MC3_UE_DATA4 0x148 -#define A_MC3_BD_ADDR 0x14c -#define A_MC3_BD_DATA0 0x150 -#define A_MC3_BD_DATA1 0x154 -#define A_MC3_BD_DATA2 0x158 -#define A_MC3_BD_DATA3 0x15c -#define A_MC3_BD_DATA4 0x160 -#define A_MC3_BD_OP 0x164 - -#define S_BACK_DOOR_OPERATION 0 -#define V_BACK_DOOR_OPERATION(x) ((x) << S_BACK_DOOR_OPERATION) -#define F_BACK_DOOR_OPERATION V_BACK_DOOR_OPERATION(1U) - -#define A_MC3_BIST_ADDR_BEG 0x168 -#define A_MC3_BIST_ADDR_END 0x16c -#define A_MC3_BIST_DATA 0x170 -#define A_MC3_BIST_OP 0x174 - -#define S_OP 0 -#define V_OP(x) ((x) << S_OP) -#define F_OP V_OP(1U) - -#define S_DATA_PATTERN 1 -#define M_DATA_PATTERN 0x3 -#define V_DATA_PATTERN(x) ((x) << S_DATA_PATTERN) -#define G_DATA_PATTERN(x) (((x) >> S_DATA_PATTERN) & M_DATA_PATTERN) - -#define S_CONTINUOUS 3 -#define V_CONTINUOUS(x) ((x) << S_CONTINUOUS) -#define F_CONTINUOUS V_CONTINUOUS(1U) - -#define A_MC3_INT_ENABLE 0x178 - -#define S_MC3_CORR_ERR 0 -#define V_MC3_CORR_ERR(x) ((x) << S_MC3_CORR_ERR) -#define F_MC3_CORR_ERR V_MC3_CORR_ERR(1U) - -#define S_MC3_UNCORR_ERR 1 -#define V_MC3_UNCORR_ERR(x) ((x) << S_MC3_UNCORR_ERR) -#define F_MC3_UNCORR_ERR V_MC3_UNCORR_ERR(1U) - -#define S_MC3_PARITY_ERR 2 -#define M_MC3_PARITY_ERR 0xff -#define V_MC3_PARITY_ERR(x) ((x) << S_MC3_PARITY_ERR) -#define G_MC3_PARITY_ERR(x) (((x) >> S_MC3_PARITY_ERR) & M_MC3_PARITY_ERR) - -#define S_MC3_ADDR_ERR 10 -#define V_MC3_ADDR_ERR(x) ((x) << S_MC3_ADDR_ERR) -#define F_MC3_ADDR_ERR V_MC3_ADDR_ERR(1U) - -#define A_MC3_INT_CAUSE 0x17c - -/* MC4 registers */ -#define A_MC4_CFG 0x180 - -#define S_POWER_UP 0 -#define V_POWER_UP(x) ((x) << S_POWER_UP) -#define F_POWER_UP V_POWER_UP(1U) - -#define S_MC4_BANK_CYCLE 8 -#define M_MC4_BANK_CYCLE 0x7 -#define V_MC4_BANK_CYCLE(x) ((x) << S_MC4_BANK_CYCLE) -#define G_MC4_BANK_CYCLE(x) (((x) >> S_MC4_BANK_CYCLE) & M_MC4_BANK_CYCLE) - -#define S_MC4_NARROW 24 -#define V_MC4_NARROW(x) ((x) << S_MC4_NARROW) -#define F_MC4_NARROW V_MC4_NARROW(1U) - -#define S_MC4_SLOW 25 -#define V_MC4_SLOW(x) ((x) << S_MC4_SLOW) -#define F_MC4_SLOW V_MC4_SLOW(1U) - -#define S_MC4A_WIDTH 24 -#define M_MC4A_WIDTH 0x3 -#define V_MC4A_WIDTH(x) ((x) << S_MC4A_WIDTH) -#define G_MC4A_WIDTH(x) (((x) >> S_MC4A_WIDTH) & M_MC4A_WIDTH) - -#define S_MC4A_SLOW 26 -#define V_MC4A_SLOW(x) ((x) << S_MC4A_SLOW) -#define F_MC4A_SLOW V_MC4A_SLOW(1U) - -#define A_MC4_MODE 0x184 - -#define S_MC4_MODE 0 -#define M_MC4_MODE 0x7fff -#define V_MC4_MODE(x) ((x) << S_MC4_MODE) -#define G_MC4_MODE(x) (((x) >> S_MC4_MODE) & M_MC4_MODE) - -#define A_MC4_EXT_MODE 0x188 - -#define S_MC4_EXTENDED_MODE 0 -#define M_MC4_EXTENDED_MODE 0x7fff -#define V_MC4_EXTENDED_MODE(x) ((x) << S_MC4_EXTENDED_MODE) -#define G_MC4_EXTENDED_MODE(x) (((x) >> S_MC4_EXTENDED_MODE) & M_MC4_EXTENDED_MODE) - -#define A_MC4_REFRESH 0x190 -#define A_MC4_STROBE 0x194 -#define A_MC4_ECC_CNTL 0x198 -#define A_MC4_CE_ADDR 0x19c - -#define S_MC4_CE_ADDR 4 -#define M_MC4_CE_ADDR 0xffffff -#define V_MC4_CE_ADDR(x) ((x) << S_MC4_CE_ADDR) -#define G_MC4_CE_ADDR(x) (((x) >> S_MC4_CE_ADDR) & M_MC4_CE_ADDR) - -#define A_MC4_CE_DATA0 0x1a0 -#define A_MC4_CE_DATA1 0x1a4 -#define A_MC4_CE_DATA2 0x1a8 -#define A_MC4_CE_DATA3 0x1ac -#define A_MC4_CE_DATA4 0x1b0 -#define A_MC4_UE_ADDR 0x1b4 - -#define S_MC4_UE_ADDR 4 -#define M_MC4_UE_ADDR 0xffffff -#define V_MC4_UE_ADDR(x) ((x) << S_MC4_UE_ADDR) -#define G_MC4_UE_ADDR(x) (((x) >> S_MC4_UE_ADDR) & M_MC4_UE_ADDR) - -#define A_MC4_UE_DATA0 0x1b8 -#define A_MC4_UE_DATA1 0x1bc -#define A_MC4_UE_DATA2 0x1c0 -#define A_MC4_UE_DATA3 0x1c4 -#define A_MC4_UE_DATA4 0x1c8 -#define A_MC4_BD_ADDR 0x1cc - -#define S_MC4_BACK_DOOR_ADDR 0 -#define M_MC4_BACK_DOOR_ADDR 0xfffffff -#define V_MC4_BACK_DOOR_ADDR(x) ((x) << S_MC4_BACK_DOOR_ADDR) -#define G_MC4_BACK_DOOR_ADDR(x) (((x) >> S_MC4_BACK_DOOR_ADDR) & M_MC4_BACK_DOOR_ADDR) - -#define A_MC4_BD_DATA0 0x1d0 -#define A_MC4_BD_DATA1 0x1d4 -#define A_MC4_BD_DATA2 0x1d8 -#define A_MC4_BD_DATA3 0x1dc -#define A_MC4_BD_DATA4 0x1e0 -#define A_MC4_BD_OP 0x1e4 - -#define S_OPERATION 0 -#define V_OPERATION(x) ((x) << S_OPERATION) -#define F_OPERATION V_OPERATION(1U) - -#define A_MC4_BIST_ADDR_BEG 0x1e8 -#define A_MC4_BIST_ADDR_END 0x1ec -#define A_MC4_BIST_DATA 0x1f0 -#define A_MC4_BIST_OP 0x1f4 -#define A_MC4_INT_ENABLE 0x1f8 - -#define S_MC4_CORR_ERR 0 -#define V_MC4_CORR_ERR(x) ((x) << S_MC4_CORR_ERR) -#define F_MC4_CORR_ERR V_MC4_CORR_ERR(1U) - -#define S_MC4_UNCORR_ERR 1 -#define V_MC4_UNCORR_ERR(x) ((x) << S_MC4_UNCORR_ERR) -#define F_MC4_UNCORR_ERR V_MC4_UNCORR_ERR(1U) - -#define S_MC4_ADDR_ERR 2 -#define V_MC4_ADDR_ERR(x) ((x) << S_MC4_ADDR_ERR) -#define F_MC4_ADDR_ERR V_MC4_ADDR_ERR(1U) - -#define A_MC4_INT_CAUSE 0x1fc - -/* TPI registers */ -#define A_TPI_ADDR 0x280 - -#define S_TPI_ADDRESS 0 -#define M_TPI_ADDRESS 0xffffff -#define V_TPI_ADDRESS(x) ((x) << S_TPI_ADDRESS) -#define G_TPI_ADDRESS(x) (((x) >> S_TPI_ADDRESS) & M_TPI_ADDRESS) - -#define A_TPI_WR_DATA 0x284 -#define A_TPI_RD_DATA 0x288 -#define A_TPI_CSR 0x28c - -#define S_TPIWR 0 -#define V_TPIWR(x) ((x) << S_TPIWR) -#define F_TPIWR V_TPIWR(1U) - -#define S_TPIRDY 1 -#define V_TPIRDY(x) ((x) << S_TPIRDY) -#define F_TPIRDY V_TPIRDY(1U) - -#define S_INT_DIR 31 -#define V_INT_DIR(x) ((x) << S_INT_DIR) -#define F_INT_DIR V_INT_DIR(1U) - -#define A_TPI_PAR 0x29c - -#define S_TPIPAR 0 -#define M_TPIPAR 0x7f -#define V_TPIPAR(x) ((x) << S_TPIPAR) -#define G_TPIPAR(x) (((x) >> S_TPIPAR) & M_TPIPAR) - - -/* TP registers */ -#define A_TP_IN_CONFIG 0x300 - -#define S_TP_IN_CSPI_TUNNEL 0 -#define V_TP_IN_CSPI_TUNNEL(x) ((x) << S_TP_IN_CSPI_TUNNEL) -#define F_TP_IN_CSPI_TUNNEL V_TP_IN_CSPI_TUNNEL(1U) - -#define S_TP_IN_CSPI_ETHERNET 1 -#define V_TP_IN_CSPI_ETHERNET(x) ((x) << S_TP_IN_CSPI_ETHERNET) -#define F_TP_IN_CSPI_ETHERNET V_TP_IN_CSPI_ETHERNET(1U) - -#define S_TP_IN_CSPI_CPL 3 -#define V_TP_IN_CSPI_CPL(x) ((x) << S_TP_IN_CSPI_CPL) -#define F_TP_IN_CSPI_CPL V_TP_IN_CSPI_CPL(1U) - -#define S_TP_IN_CSPI_POS 4 -#define V_TP_IN_CSPI_POS(x) ((x) << S_TP_IN_CSPI_POS) -#define F_TP_IN_CSPI_POS V_TP_IN_CSPI_POS(1U) - -#define S_TP_IN_CSPI_CHECK_IP_CSUM 5 -#define V_TP_IN_CSPI_CHECK_IP_CSUM(x) ((x) << S_TP_IN_CSPI_CHECK_IP_CSUM) -#define F_TP_IN_CSPI_CHECK_IP_CSUM V_TP_IN_CSPI_CHECK_IP_CSUM(1U) - -#define S_TP_IN_CSPI_CHECK_TCP_CSUM 6 -#define V_TP_IN_CSPI_CHECK_TCP_CSUM(x) ((x) << S_TP_IN_CSPI_CHECK_TCP_CSUM) -#define F_TP_IN_CSPI_CHECK_TCP_CSUM V_TP_IN_CSPI_CHECK_TCP_CSUM(1U) - -#define S_TP_IN_ESPI_TUNNEL 7 -#define V_TP_IN_ESPI_TUNNEL(x) ((x) << S_TP_IN_ESPI_TUNNEL) -#define F_TP_IN_ESPI_TUNNEL V_TP_IN_ESPI_TUNNEL(1U) - -#define S_TP_IN_ESPI_ETHERNET 8 -#define V_TP_IN_ESPI_ETHERNET(x) ((x) << S_TP_IN_ESPI_ETHERNET) -#define F_TP_IN_ESPI_ETHERNET V_TP_IN_ESPI_ETHERNET(1U) - -#define S_TP_IN_ESPI_CPL 10 -#define V_TP_IN_ESPI_CPL(x) ((x) << S_TP_IN_ESPI_CPL) -#define F_TP_IN_ESPI_CPL V_TP_IN_ESPI_CPL(1U) - -#define S_TP_IN_ESPI_POS 11 -#define V_TP_IN_ESPI_POS(x) ((x) << S_TP_IN_ESPI_POS) -#define F_TP_IN_ESPI_POS V_TP_IN_ESPI_POS(1U) - -#define S_TP_IN_ESPI_CHECK_IP_CSUM 12 -#define V_TP_IN_ESPI_CHECK_IP_CSUM(x) ((x) << S_TP_IN_ESPI_CHECK_IP_CSUM) -#define F_TP_IN_ESPI_CHECK_IP_CSUM V_TP_IN_ESPI_CHECK_IP_CSUM(1U) - -#define S_TP_IN_ESPI_CHECK_TCP_CSUM 13 -#define V_TP_IN_ESPI_CHECK_TCP_CSUM(x) ((x) << S_TP_IN_ESPI_CHECK_TCP_CSUM) -#define F_TP_IN_ESPI_CHECK_TCP_CSUM V_TP_IN_ESPI_CHECK_TCP_CSUM(1U) - -#define S_OFFLOAD_DISABLE 14 -#define V_OFFLOAD_DISABLE(x) ((x) << S_OFFLOAD_DISABLE) -#define F_OFFLOAD_DISABLE V_OFFLOAD_DISABLE(1U) - -#define A_TP_OUT_CONFIG 0x304 - -#define S_TP_OUT_C_ETH 0 -#define V_TP_OUT_C_ETH(x) ((x) << S_TP_OUT_C_ETH) -#define F_TP_OUT_C_ETH V_TP_OUT_C_ETH(1U) - -#define S_TP_OUT_CSPI_CPL 2 -#define V_TP_OUT_CSPI_CPL(x) ((x) << S_TP_OUT_CSPI_CPL) -#define F_TP_OUT_CSPI_CPL V_TP_OUT_CSPI_CPL(1U) - -#define S_TP_OUT_CSPI_POS 3 -#define V_TP_OUT_CSPI_POS(x) ((x) << S_TP_OUT_CSPI_POS) -#define F_TP_OUT_CSPI_POS V_TP_OUT_CSPI_POS(1U) - -#define S_TP_OUT_CSPI_GENERATE_IP_CSUM 4 -#define V_TP_OUT_CSPI_GENERATE_IP_CSUM(x) ((x) << S_TP_OUT_CSPI_GENERATE_IP_CSUM) -#define F_TP_OUT_CSPI_GENERATE_IP_CSUM V_TP_OUT_CSPI_GENERATE_IP_CSUM(1U) - -#define S_TP_OUT_CSPI_GENERATE_TCP_CSUM 5 -#define V_TP_OUT_CSPI_GENERATE_TCP_CSUM(x) ((x) << S_TP_OUT_CSPI_GENERATE_TCP_CSUM) -#define F_TP_OUT_CSPI_GENERATE_TCP_CSUM V_TP_OUT_CSPI_GENERATE_TCP_CSUM(1U) - -#define S_TP_OUT_ESPI_ETHERNET 6 -#define V_TP_OUT_ESPI_ETHERNET(x) ((x) << S_TP_OUT_ESPI_ETHERNET) -#define F_TP_OUT_ESPI_ETHERNET V_TP_OUT_ESPI_ETHERNET(1U) - -#define S_TP_OUT_ESPI_TAG_ETHERNET 7 -#define V_TP_OUT_ESPI_TAG_ETHERNET(x) ((x) << S_TP_OUT_ESPI_TAG_ETHERNET) -#define F_TP_OUT_ESPI_TAG_ETHERNET V_TP_OUT_ESPI_TAG_ETHERNET(1U) - -#define S_TP_OUT_ESPI_CPL 8 -#define V_TP_OUT_ESPI_CPL(x) ((x) << S_TP_OUT_ESPI_CPL) -#define F_TP_OUT_ESPI_CPL V_TP_OUT_ESPI_CPL(1U) - -#define S_TP_OUT_ESPI_POS 9 -#define V_TP_OUT_ESPI_POS(x) ((x) << S_TP_OUT_ESPI_POS) -#define F_TP_OUT_ESPI_POS V_TP_OUT_ESPI_POS(1U) - -#define S_TP_OUT_ESPI_GENERATE_IP_CSUM 10 -#define V_TP_OUT_ESPI_GENERATE_IP_CSUM(x) ((x) << S_TP_OUT_ESPI_GENERATE_IP_CSUM) -#define F_TP_OUT_ESPI_GENERATE_IP_CSUM V_TP_OUT_ESPI_GENERATE_IP_CSUM(1U) - -#define S_TP_OUT_ESPI_GENERATE_TCP_CSUM 11 -#define V_TP_OUT_ESPI_GENERATE_TCP_CSUM(x) ((x) << S_TP_OUT_ESPI_GENERATE_TCP_CSUM) -#define F_TP_OUT_ESPI_GENERATE_TCP_CSUM V_TP_OUT_ESPI_GENERATE_TCP_CSUM(1U) - -#define A_TP_GLOBAL_CONFIG 0x308 - -#define S_IP_TTL 0 -#define M_IP_TTL 0xff -#define V_IP_TTL(x) ((x) << S_IP_TTL) -#define G_IP_TTL(x) (((x) >> S_IP_TTL) & M_IP_TTL) - -#define S_TCAM_SERVER_REGION_USAGE 8 -#define M_TCAM_SERVER_REGION_USAGE 0x3 -#define V_TCAM_SERVER_REGION_USAGE(x) ((x) << S_TCAM_SERVER_REGION_USAGE) -#define G_TCAM_SERVER_REGION_USAGE(x) (((x) >> S_TCAM_SERVER_REGION_USAGE) & M_TCAM_SERVER_REGION_USAGE) - -#define S_QOS_MAPPING 10 -#define V_QOS_MAPPING(x) ((x) << S_QOS_MAPPING) -#define F_QOS_MAPPING V_QOS_MAPPING(1U) - -#define S_TCP_CSUM 11 -#define V_TCP_CSUM(x) ((x) << S_TCP_CSUM) -#define F_TCP_CSUM V_TCP_CSUM(1U) - -#define S_UDP_CSUM 12 -#define V_UDP_CSUM(x) ((x) << S_UDP_CSUM) -#define F_UDP_CSUM V_UDP_CSUM(1U) - -#define S_IP_CSUM 13 -#define V_IP_CSUM(x) ((x) << S_IP_CSUM) -#define F_IP_CSUM V_IP_CSUM(1U) - -#define S_IP_ID_SPLIT 14 -#define V_IP_ID_SPLIT(x) ((x) << S_IP_ID_SPLIT) -#define F_IP_ID_SPLIT V_IP_ID_SPLIT(1U) - -#define S_PATH_MTU 15 -#define V_PATH_MTU(x) ((x) << S_PATH_MTU) -#define F_PATH_MTU V_PATH_MTU(1U) - -#define S_5TUPLE_LOOKUP 17 -#define M_5TUPLE_LOOKUP 0x3 -#define V_5TUPLE_LOOKUP(x) ((x) << S_5TUPLE_LOOKUP) -#define G_5TUPLE_LOOKUP(x) (((x) >> S_5TUPLE_LOOKUP) & M_5TUPLE_LOOKUP) - -#define S_IP_FRAGMENT_DROP 19 -#define V_IP_FRAGMENT_DROP(x) ((x) << S_IP_FRAGMENT_DROP) -#define F_IP_FRAGMENT_DROP V_IP_FRAGMENT_DROP(1U) - -#define S_PING_DROP 20 -#define V_PING_DROP(x) ((x) << S_PING_DROP) -#define F_PING_DROP V_PING_DROP(1U) - -#define S_PROTECT_MODE 21 -#define V_PROTECT_MODE(x) ((x) << S_PROTECT_MODE) -#define F_PROTECT_MODE V_PROTECT_MODE(1U) - -#define S_SYN_COOKIE_ALGORITHM 22 -#define V_SYN_COOKIE_ALGORITHM(x) ((x) << S_SYN_COOKIE_ALGORITHM) -#define F_SYN_COOKIE_ALGORITHM V_SYN_COOKIE_ALGORITHM(1U) - -#define S_ATTACK_FILTER 23 -#define V_ATTACK_FILTER(x) ((x) << S_ATTACK_FILTER) -#define F_ATTACK_FILTER V_ATTACK_FILTER(1U) - -#define S_INTERFACE_TYPE 24 -#define V_INTERFACE_TYPE(x) ((x) << S_INTERFACE_TYPE) -#define F_INTERFACE_TYPE V_INTERFACE_TYPE(1U) - -#define S_DISABLE_RX_FLOW_CONTROL 25 -#define V_DISABLE_RX_FLOW_CONTROL(x) ((x) << S_DISABLE_RX_FLOW_CONTROL) -#define F_DISABLE_RX_FLOW_CONTROL V_DISABLE_RX_FLOW_CONTROL(1U) - -#define S_SYN_COOKIE_PARAMETER 26 -#define M_SYN_COOKIE_PARAMETER 0x3f -#define V_SYN_COOKIE_PARAMETER(x) ((x) << S_SYN_COOKIE_PARAMETER) -#define G_SYN_COOKIE_PARAMETER(x) (((x) >> S_SYN_COOKIE_PARAMETER) & M_SYN_COOKIE_PARAMETER) - -#define A_TP_GLOBAL_RX_CREDITS 0x30c -#define A_TP_CM_SIZE 0x310 -#define A_TP_CM_MM_BASE 0x314 - -#define S_CM_MEMMGR_BASE 0 -#define M_CM_MEMMGR_BASE 0xfffffff -#define V_CM_MEMMGR_BASE(x) ((x) << S_CM_MEMMGR_BASE) -#define G_CM_MEMMGR_BASE(x) (((x) >> S_CM_MEMMGR_BASE) & M_CM_MEMMGR_BASE) - -#define A_TP_CM_TIMER_BASE 0x318 - -#define S_CM_TIMER_BASE 0 -#define M_CM_TIMER_BASE 0xfffffff -#define V_CM_TIMER_BASE(x) ((x) << S_CM_TIMER_BASE) -#define G_CM_TIMER_BASE(x) (((x) >> S_CM_TIMER_BASE) & M_CM_TIMER_BASE) - -#define A_TP_PM_SIZE 0x31c -#define A_TP_PM_TX_BASE 0x320 -#define A_TP_PM_DEFRAG_BASE 0x324 -#define A_TP_PM_RX_BASE 0x328 -#define A_TP_PM_RX_PG_SIZE 0x32c -#define A_TP_PM_RX_MAX_PGS 0x330 -#define A_TP_PM_TX_PG_SIZE 0x334 -#define A_TP_PM_TX_MAX_PGS 0x338 -#define A_TP_TCP_OPTIONS 0x340 - -#define S_TIMESTAMP 0 -#define M_TIMESTAMP 0x3 -#define V_TIMESTAMP(x) ((x) << S_TIMESTAMP) -#define G_TIMESTAMP(x) (((x) >> S_TIMESTAMP) & M_TIMESTAMP) - -#define S_WINDOW_SCALE 2 -#define M_WINDOW_SCALE 0x3 -#define V_WINDOW_SCALE(x) ((x) << S_WINDOW_SCALE) -#define G_WINDOW_SCALE(x) (((x) >> S_WINDOW_SCALE) & M_WINDOW_SCALE) - -#define S_SACK 4 -#define M_SACK 0x3 -#define V_SACK(x) ((x) << S_SACK) -#define G_SACK(x) (((x) >> S_SACK) & M_SACK) - -#define S_ECN 6 -#define M_ECN 0x3 -#define V_ECN(x) ((x) << S_ECN) -#define G_ECN(x) (((x) >> S_ECN) & M_ECN) - -#define S_SACK_ALGORITHM 8 -#define M_SACK_ALGORITHM 0x3 -#define V_SACK_ALGORITHM(x) ((x) << S_SACK_ALGORITHM) -#define G_SACK_ALGORITHM(x) (((x) >> S_SACK_ALGORITHM) & M_SACK_ALGORITHM) - -#define S_MSS 10 -#define V_MSS(x) ((x) << S_MSS) -#define F_MSS V_MSS(1U) - -#define S_DEFAULT_PEER_MSS 16 -#define M_DEFAULT_PEER_MSS 0xffff -#define V_DEFAULT_PEER_MSS(x) ((x) << S_DEFAULT_PEER_MSS) -#define G_DEFAULT_PEER_MSS(x) (((x) >> S_DEFAULT_PEER_MSS) & M_DEFAULT_PEER_MSS) - -#define A_TP_DACK_CONFIG 0x344 - -#define S_DACK_MODE 0 -#define V_DACK_MODE(x) ((x) << S_DACK_MODE) -#define F_DACK_MODE V_DACK_MODE(1U) - -#define S_DACK_AUTO_MGMT 1 -#define V_DACK_AUTO_MGMT(x) ((x) << S_DACK_AUTO_MGMT) -#define F_DACK_AUTO_MGMT V_DACK_AUTO_MGMT(1U) - -#define S_DACK_AUTO_CAREFUL 2 -#define V_DACK_AUTO_CAREFUL(x) ((x) << S_DACK_AUTO_CAREFUL) -#define F_DACK_AUTO_CAREFUL V_DACK_AUTO_CAREFUL(1U) - -#define S_DACK_MSS_SELECTOR 3 -#define M_DACK_MSS_SELECTOR 0x3 -#define V_DACK_MSS_SELECTOR(x) ((x) << S_DACK_MSS_SELECTOR) -#define G_DACK_MSS_SELECTOR(x) (((x) >> S_DACK_MSS_SELECTOR) & M_DACK_MSS_SELECTOR) - -#define S_DACK_BYTE_THRESHOLD 5 -#define M_DACK_BYTE_THRESHOLD 0xfffff -#define V_DACK_BYTE_THRESHOLD(x) ((x) << S_DACK_BYTE_THRESHOLD) -#define G_DACK_BYTE_THRESHOLD(x) (((x) >> S_DACK_BYTE_THRESHOLD) & M_DACK_BYTE_THRESHOLD) - -#define A_TP_PC_CONFIG 0x348 - -#define S_TP_ACCESS_LATENCY 0 -#define M_TP_ACCESS_LATENCY 0xf -#define V_TP_ACCESS_LATENCY(x) ((x) << S_TP_ACCESS_LATENCY) -#define G_TP_ACCESS_LATENCY(x) (((x) >> S_TP_ACCESS_LATENCY) & M_TP_ACCESS_LATENCY) - -#define S_HELD_FIN_DISABLE 4 -#define V_HELD_FIN_DISABLE(x) ((x) << S_HELD_FIN_DISABLE) -#define F_HELD_FIN_DISABLE V_HELD_FIN_DISABLE(1U) - -#define S_DDP_FC_ENABLE 5 -#define V_DDP_FC_ENABLE(x) ((x) << S_DDP_FC_ENABLE) -#define F_DDP_FC_ENABLE V_DDP_FC_ENABLE(1U) - -#define S_RDMA_ERR_ENABLE 6 -#define V_RDMA_ERR_ENABLE(x) ((x) << S_RDMA_ERR_ENABLE) -#define F_RDMA_ERR_ENABLE V_RDMA_ERR_ENABLE(1U) - -#define S_FAST_PDU_DELIVERY 7 -#define V_FAST_PDU_DELIVERY(x) ((x) << S_FAST_PDU_DELIVERY) -#define F_FAST_PDU_DELIVERY V_FAST_PDU_DELIVERY(1U) - -#define S_CLEAR_FIN 8 -#define V_CLEAR_FIN(x) ((x) << S_CLEAR_FIN) -#define F_CLEAR_FIN V_CLEAR_FIN(1U) - -#define S_DIS_TX_FILL_WIN_PUSH 12 -#define V_DIS_TX_FILL_WIN_PUSH(x) ((x) << S_DIS_TX_FILL_WIN_PUSH) -#define F_DIS_TX_FILL_WIN_PUSH V_DIS_TX_FILL_WIN_PUSH(1U) - -#define S_TP_PC_REV 30 -#define M_TP_PC_REV 0x3 -#define V_TP_PC_REV(x) ((x) << S_TP_PC_REV) -#define G_TP_PC_REV(x) (((x) >> S_TP_PC_REV) & M_TP_PC_REV) - -#define A_TP_BACKOFF0 0x350 - -#define S_ELEMENT0 0 -#define M_ELEMENT0 0xff -#define V_ELEMENT0(x) ((x) << S_ELEMENT0) -#define G_ELEMENT0(x) (((x) >> S_ELEMENT0) & M_ELEMENT0) - -#define S_ELEMENT1 8 -#define M_ELEMENT1 0xff -#define V_ELEMENT1(x) ((x) << S_ELEMENT1) -#define G_ELEMENT1(x) (((x) >> S_ELEMENT1) & M_ELEMENT1) - -#define S_ELEMENT2 16 -#define M_ELEMENT2 0xff -#define V_ELEMENT2(x) ((x) << S_ELEMENT2) -#define G_ELEMENT2(x) (((x) >> S_ELEMENT2) & M_ELEMENT2) - -#define S_ELEMENT3 24 -#define M_ELEMENT3 0xff -#define V_ELEMENT3(x) ((x) << S_ELEMENT3) -#define G_ELEMENT3(x) (((x) >> S_ELEMENT3) & M_ELEMENT3) - -#define A_TP_BACKOFF1 0x354 -#define A_TP_BACKOFF2 0x358 -#define A_TP_BACKOFF3 0x35c -#define A_TP_PARA_REG0 0x360 - -#define S_VAR_MULT 0 -#define M_VAR_MULT 0xf -#define V_VAR_MULT(x) ((x) << S_VAR_MULT) -#define G_VAR_MULT(x) (((x) >> S_VAR_MULT) & M_VAR_MULT) - -#define S_VAR_GAIN 4 -#define M_VAR_GAIN 0xf -#define V_VAR_GAIN(x) ((x) << S_VAR_GAIN) -#define G_VAR_GAIN(x) (((x) >> S_VAR_GAIN) & M_VAR_GAIN) - -#define S_SRTT_GAIN 8 -#define M_SRTT_GAIN 0xf -#define V_SRTT_GAIN(x) ((x) << S_SRTT_GAIN) -#define G_SRTT_GAIN(x) (((x) >> S_SRTT_GAIN) & M_SRTT_GAIN) - -#define S_RTTVAR_INIT 12 -#define M_RTTVAR_INIT 0xf -#define V_RTTVAR_INIT(x) ((x) << S_RTTVAR_INIT) -#define G_RTTVAR_INIT(x) (((x) >> S_RTTVAR_INIT) & M_RTTVAR_INIT) - -#define S_DUP_THRESH 20 -#define M_DUP_THRESH 0xf -#define V_DUP_THRESH(x) ((x) << S_DUP_THRESH) -#define G_DUP_THRESH(x) (((x) >> S_DUP_THRESH) & M_DUP_THRESH) - -#define S_INIT_CONG_WIN 24 -#define M_INIT_CONG_WIN 0x7 -#define V_INIT_CONG_WIN(x) ((x) << S_INIT_CONG_WIN) -#define G_INIT_CONG_WIN(x) (((x) >> S_INIT_CONG_WIN) & M_INIT_CONG_WIN) - -#define A_TP_PARA_REG1 0x364 - -#define S_INITIAL_SLOW_START_THRESHOLD 0 -#define M_INITIAL_SLOW_START_THRESHOLD 0xffff -#define V_INITIAL_SLOW_START_THRESHOLD(x) ((x) << S_INITIAL_SLOW_START_THRESHOLD) -#define G_INITIAL_SLOW_START_THRESHOLD(x) (((x) >> S_INITIAL_SLOW_START_THRESHOLD) & M_INITIAL_SLOW_START_THRESHOLD) - -#define S_RECEIVE_BUFFER_SIZE 16 -#define M_RECEIVE_BUFFER_SIZE 0xffff -#define V_RECEIVE_BUFFER_SIZE(x) ((x) << S_RECEIVE_BUFFER_SIZE) -#define G_RECEIVE_BUFFER_SIZE(x) (((x) >> S_RECEIVE_BUFFER_SIZE) & M_RECEIVE_BUFFER_SIZE) - -#define A_TP_PARA_REG2 0x368 - -#define S_RX_COALESCE_SIZE 0 -#define M_RX_COALESCE_SIZE 0xffff -#define V_RX_COALESCE_SIZE(x) ((x) << S_RX_COALESCE_SIZE) -#define G_RX_COALESCE_SIZE(x) (((x) >> S_RX_COALESCE_SIZE) & M_RX_COALESCE_SIZE) - -#define S_MAX_RX_SIZE 16 -#define M_MAX_RX_SIZE 0xffff -#define V_MAX_RX_SIZE(x) ((x) << S_MAX_RX_SIZE) -#define G_MAX_RX_SIZE(x) (((x) >> S_MAX_RX_SIZE) & M_MAX_RX_SIZE) - -#define A_TP_PARA_REG3 0x36c - -#define S_RX_COALESCING_PSH_DELIVER 0 -#define V_RX_COALESCING_PSH_DELIVER(x) ((x) << S_RX_COALESCING_PSH_DELIVER) -#define F_RX_COALESCING_PSH_DELIVER V_RX_COALESCING_PSH_DELIVER(1U) - -#define S_RX_COALESCING_ENABLE 1 -#define V_RX_COALESCING_ENABLE(x) ((x) << S_RX_COALESCING_ENABLE) -#define F_RX_COALESCING_ENABLE V_RX_COALESCING_ENABLE(1U) - -#define S_TAHOE_ENABLE 2 -#define V_TAHOE_ENABLE(x) ((x) << S_TAHOE_ENABLE) -#define F_TAHOE_ENABLE V_TAHOE_ENABLE(1U) - -#define S_MAX_REORDER_FRAGMENTS 12 -#define M_MAX_REORDER_FRAGMENTS 0x7 -#define V_MAX_REORDER_FRAGMENTS(x) ((x) << S_MAX_REORDER_FRAGMENTS) -#define G_MAX_REORDER_FRAGMENTS(x) (((x) >> S_MAX_REORDER_FRAGMENTS) & M_MAX_REORDER_FRAGMENTS) - -#define A_TP_TIMER_RESOLUTION 0x390 - -#define S_DELAYED_ACK_TIMER_RESOLUTION 0 -#define M_DELAYED_ACK_TIMER_RESOLUTION 0x3f -#define V_DELAYED_ACK_TIMER_RESOLUTION(x) ((x) << S_DELAYED_ACK_TIMER_RESOLUTION) -#define G_DELAYED_ACK_TIMER_RESOLUTION(x) (((x) >> S_DELAYED_ACK_TIMER_RESOLUTION) & M_DELAYED_ACK_TIMER_RESOLUTION) - -#define S_GENERIC_TIMER_RESOLUTION 16 -#define M_GENERIC_TIMER_RESOLUTION 0x3f -#define V_GENERIC_TIMER_RESOLUTION(x) ((x) << S_GENERIC_TIMER_RESOLUTION) -#define G_GENERIC_TIMER_RESOLUTION(x) (((x) >> S_GENERIC_TIMER_RESOLUTION) & M_GENERIC_TIMER_RESOLUTION) - -#define A_TP_2MSL 0x394 - -#define S_2MSL 0 -#define M_2MSL 0x3fffffff -#define V_2MSL(x) ((x) << S_2MSL) -#define G_2MSL(x) (((x) >> S_2MSL) & M_2MSL) - -#define A_TP_RXT_MIN 0x398 - -#define S_RETRANSMIT_TIMER_MIN 0 -#define M_RETRANSMIT_TIMER_MIN 0xffff -#define V_RETRANSMIT_TIMER_MIN(x) ((x) << S_RETRANSMIT_TIMER_MIN) -#define G_RETRANSMIT_TIMER_MIN(x) (((x) >> S_RETRANSMIT_TIMER_MIN) & M_RETRANSMIT_TIMER_MIN) - -#define A_TP_RXT_MAX 0x39c - -#define S_RETRANSMIT_TIMER_MAX 0 -#define M_RETRANSMIT_TIMER_MAX 0x3fffffff -#define V_RETRANSMIT_TIMER_MAX(x) ((x) << S_RETRANSMIT_TIMER_MAX) -#define G_RETRANSMIT_TIMER_MAX(x) (((x) >> S_RETRANSMIT_TIMER_MAX) & M_RETRANSMIT_TIMER_MAX) - -#define A_TP_PERS_MIN 0x3a0 - -#define S_PERSIST_TIMER_MIN 0 -#define M_PERSIST_TIMER_MIN 0xffff -#define V_PERSIST_TIMER_MIN(x) ((x) << S_PERSIST_TIMER_MIN) -#define G_PERSIST_TIMER_MIN(x) (((x) >> S_PERSIST_TIMER_MIN) & M_PERSIST_TIMER_MIN) - -#define A_TP_PERS_MAX 0x3a4 - -#define S_PERSIST_TIMER_MAX 0 -#define M_PERSIST_TIMER_MAX 0x3fffffff -#define V_PERSIST_TIMER_MAX(x) ((x) << S_PERSIST_TIMER_MAX) -#define G_PERSIST_TIMER_MAX(x) (((x) >> S_PERSIST_TIMER_MAX) & M_PERSIST_TIMER_MAX) - -#define A_TP_KEEP_IDLE 0x3ac - -#define S_KEEP_ALIVE_IDLE_TIME 0 -#define M_KEEP_ALIVE_IDLE_TIME 0x3fffffff -#define V_KEEP_ALIVE_IDLE_TIME(x) ((x) << S_KEEP_ALIVE_IDLE_TIME) -#define G_KEEP_ALIVE_IDLE_TIME(x) (((x) >> S_KEEP_ALIVE_IDLE_TIME) & M_KEEP_ALIVE_IDLE_TIME) - -#define A_TP_KEEP_INTVL 0x3b0 - -#define S_KEEP_ALIVE_INTERVAL_TIME 0 -#define M_KEEP_ALIVE_INTERVAL_TIME 0x3fffffff -#define V_KEEP_ALIVE_INTERVAL_TIME(x) ((x) << S_KEEP_ALIVE_INTERVAL_TIME) -#define G_KEEP_ALIVE_INTERVAL_TIME(x) (((x) >> S_KEEP_ALIVE_INTERVAL_TIME) & M_KEEP_ALIVE_INTERVAL_TIME) - -#define A_TP_INIT_SRTT 0x3b4 - -#define S_INITIAL_SRTT 0 -#define M_INITIAL_SRTT 0xffff -#define V_INITIAL_SRTT(x) ((x) << S_INITIAL_SRTT) -#define G_INITIAL_SRTT(x) (((x) >> S_INITIAL_SRTT) & M_INITIAL_SRTT) - -#define A_TP_DACK_TIME 0x3b8 - -#define S_DELAYED_ACK_TIME 0 -#define M_DELAYED_ACK_TIME 0x7ff -#define V_DELAYED_ACK_TIME(x) ((x) << S_DELAYED_ACK_TIME) -#define G_DELAYED_ACK_TIME(x) (((x) >> S_DELAYED_ACK_TIME) & M_DELAYED_ACK_TIME) - -#define A_TP_FINWAIT2_TIME 0x3bc - -#define S_FINWAIT2_TIME 0 -#define M_FINWAIT2_TIME 0x3fffffff -#define V_FINWAIT2_TIME(x) ((x) << S_FINWAIT2_TIME) -#define G_FINWAIT2_TIME(x) (((x) >> S_FINWAIT2_TIME) & M_FINWAIT2_TIME) - -#define A_TP_FAST_FINWAIT2_TIME 0x3c0 - -#define S_FAST_FINWAIT2_TIME 0 -#define M_FAST_FINWAIT2_TIME 0x3fffffff -#define V_FAST_FINWAIT2_TIME(x) ((x) << S_FAST_FINWAIT2_TIME) -#define G_FAST_FINWAIT2_TIME(x) (((x) >> S_FAST_FINWAIT2_TIME) & M_FAST_FINWAIT2_TIME) - -#define A_TP_SHIFT_CNT 0x3c4 - -#define S_KEEPALIVE_MAX 0 -#define M_KEEPALIVE_MAX 0xff -#define V_KEEPALIVE_MAX(x) ((x) << S_KEEPALIVE_MAX) -#define G_KEEPALIVE_MAX(x) (((x) >> S_KEEPALIVE_MAX) & M_KEEPALIVE_MAX) - -#define S_WINDOWPROBE_MAX 8 -#define M_WINDOWPROBE_MAX 0xff -#define V_WINDOWPROBE_MAX(x) ((x) << S_WINDOWPROBE_MAX) -#define G_WINDOWPROBE_MAX(x) (((x) >> S_WINDOWPROBE_MAX) & M_WINDOWPROBE_MAX) - -#define S_RETRANSMISSION_MAX 16 -#define M_RETRANSMISSION_MAX 0xff -#define V_RETRANSMISSION_MAX(x) ((x) << S_RETRANSMISSION_MAX) -#define G_RETRANSMISSION_MAX(x) (((x) >> S_RETRANSMISSION_MAX) & M_RETRANSMISSION_MAX) - -#define S_SYN_MAX 24 -#define M_SYN_MAX 0xff -#define V_SYN_MAX(x) ((x) << S_SYN_MAX) -#define G_SYN_MAX(x) (((x) >> S_SYN_MAX) & M_SYN_MAX) - -#define A_TP_QOS_REG0 0x3e0 - -#define S_L3_VALUE 0 -#define M_L3_VALUE 0x3f -#define V_L3_VALUE(x) ((x) << S_L3_VALUE) -#define G_L3_VALUE(x) (((x) >> S_L3_VALUE) & M_L3_VALUE) - -#define A_TP_QOS_REG1 0x3e4 -#define A_TP_QOS_REG2 0x3e8 -#define A_TP_QOS_REG3 0x3ec -#define A_TP_QOS_REG4 0x3f0 -#define A_TP_QOS_REG5 0x3f4 -#define A_TP_QOS_REG6 0x3f8 -#define A_TP_QOS_REG7 0x3fc -#define A_TP_MTU_REG0 0x404 -#define A_TP_MTU_REG1 0x408 -#define A_TP_MTU_REG2 0x40c -#define A_TP_MTU_REG3 0x410 -#define A_TP_MTU_REG4 0x414 -#define A_TP_MTU_REG5 0x418 -#define A_TP_MTU_REG6 0x41c -#define A_TP_MTU_REG7 0x420 -#define A_TP_RESET 0x44c - -#define S_TP_RESET 0 -#define V_TP_RESET(x) ((x) << S_TP_RESET) -#define F_TP_RESET V_TP_RESET(1U) - -#define S_CM_MEMMGR_INIT 1 -#define V_CM_MEMMGR_INIT(x) ((x) << S_CM_MEMMGR_INIT) -#define F_CM_MEMMGR_INIT V_CM_MEMMGR_INIT(1U) - -#define A_TP_MIB_INDEX 0x450 -#define A_TP_MIB_DATA 0x454 -#define A_TP_SYNC_TIME_HI 0x458 -#define A_TP_SYNC_TIME_LO 0x45c -#define A_TP_CM_MM_RX_FLST_BASE 0x460 - -#define S_CM_MEMMGR_RX_FREE_LIST_BASE 0 -#define M_CM_MEMMGR_RX_FREE_LIST_BASE 0xfffffff -#define V_CM_MEMMGR_RX_FREE_LIST_BASE(x) ((x) << S_CM_MEMMGR_RX_FREE_LIST_BASE) -#define G_CM_MEMMGR_RX_FREE_LIST_BASE(x) (((x) >> S_CM_MEMMGR_RX_FREE_LIST_BASE) & M_CM_MEMMGR_RX_FREE_LIST_BASE) - -#define A_TP_CM_MM_TX_FLST_BASE 0x464 - -#define S_CM_MEMMGR_TX_FREE_LIST_BASE 0 -#define M_CM_MEMMGR_TX_FREE_LIST_BASE 0xfffffff -#define V_CM_MEMMGR_TX_FREE_LIST_BASE(x) ((x) << S_CM_MEMMGR_TX_FREE_LIST_BASE) -#define G_CM_MEMMGR_TX_FREE_LIST_BASE(x) (((x) >> S_CM_MEMMGR_TX_FREE_LIST_BASE) & M_CM_MEMMGR_TX_FREE_LIST_BASE) - -#define A_TP_CM_MM_P_FLST_BASE 0x468 - -#define S_CM_MEMMGR_PSTRUCT_FREE_LIST_BASE 0 -#define M_CM_MEMMGR_PSTRUCT_FREE_LIST_BASE 0xfffffff -#define V_CM_MEMMGR_PSTRUCT_FREE_LIST_BASE(x) ((x) << S_CM_MEMMGR_PSTRUCT_FREE_LIST_BASE) -#define G_CM_MEMMGR_PSTRUCT_FREE_LIST_BASE(x) (((x) >> S_CM_MEMMGR_PSTRUCT_FREE_LIST_BASE) & M_CM_MEMMGR_PSTRUCT_FREE_LIST_BASE) - -#define A_TP_CM_MM_MAX_P 0x46c - -#define S_CM_MEMMGR_MAX_PSTRUCT 0 -#define M_CM_MEMMGR_MAX_PSTRUCT 0xfffffff -#define V_CM_MEMMGR_MAX_PSTRUCT(x) ((x) << S_CM_MEMMGR_MAX_PSTRUCT) -#define G_CM_MEMMGR_MAX_PSTRUCT(x) (((x) >> S_CM_MEMMGR_MAX_PSTRUCT) & M_CM_MEMMGR_MAX_PSTRUCT) - -#define A_TP_INT_ENABLE 0x470 - -#define S_TX_FREE_LIST_EMPTY 0 -#define V_TX_FREE_LIST_EMPTY(x) ((x) << S_TX_FREE_LIST_EMPTY) -#define F_TX_FREE_LIST_EMPTY V_TX_FREE_LIST_EMPTY(1U) - -#define S_RX_FREE_LIST_EMPTY 1 -#define V_RX_FREE_LIST_EMPTY(x) ((x) << S_RX_FREE_LIST_EMPTY) -#define F_RX_FREE_LIST_EMPTY V_RX_FREE_LIST_EMPTY(1U) - -#define A_TP_INT_CAUSE 0x474 -#define A_TP_TIMER_SEPARATOR 0x4a4 - -#define S_DISABLE_PAST_TIMER_INSERTION 0 -#define V_DISABLE_PAST_TIMER_INSERTION(x) ((x) << S_DISABLE_PAST_TIMER_INSERTION) -#define F_DISABLE_PAST_TIMER_INSERTION V_DISABLE_PAST_TIMER_INSERTION(1U) - -#define S_MODULATION_TIMER_SEPARATOR 1 -#define M_MODULATION_TIMER_SEPARATOR 0x7fff -#define V_MODULATION_TIMER_SEPARATOR(x) ((x) << S_MODULATION_TIMER_SEPARATOR) -#define G_MODULATION_TIMER_SEPARATOR(x) (((x) >> S_MODULATION_TIMER_SEPARATOR) & M_MODULATION_TIMER_SEPARATOR) - -#define S_GLOBAL_TIMER_SEPARATOR 16 -#define M_GLOBAL_TIMER_SEPARATOR 0xffff -#define V_GLOBAL_TIMER_SEPARATOR(x) ((x) << S_GLOBAL_TIMER_SEPARATOR) -#define G_GLOBAL_TIMER_SEPARATOR(x) (((x) >> S_GLOBAL_TIMER_SEPARATOR) & M_GLOBAL_TIMER_SEPARATOR) - -#define A_TP_CM_FC_MODE 0x4b0 -#define A_TP_PC_CONGESTION_CNTL 0x4b4 -#define A_TP_TX_DROP_CONFIG 0x4b8 - -#define S_ENABLE_TX_DROP 31 -#define V_ENABLE_TX_DROP(x) ((x) << S_ENABLE_TX_DROP) -#define F_ENABLE_TX_DROP V_ENABLE_TX_DROP(1U) - -#define S_ENABLE_TX_ERROR 30 -#define V_ENABLE_TX_ERROR(x) ((x) << S_ENABLE_TX_ERROR) -#define F_ENABLE_TX_ERROR V_ENABLE_TX_ERROR(1U) - -#define S_DROP_TICKS_CNT 4 -#define M_DROP_TICKS_CNT 0x3ffffff -#define V_DROP_TICKS_CNT(x) ((x) << S_DROP_TICKS_CNT) -#define G_DROP_TICKS_CNT(x) (((x) >> S_DROP_TICKS_CNT) & M_DROP_TICKS_CNT) - -#define S_NUM_PKTS_DROPPED 0 -#define M_NUM_PKTS_DROPPED 0xf -#define V_NUM_PKTS_DROPPED(x) ((x) << S_NUM_PKTS_DROPPED) -#define G_NUM_PKTS_DROPPED(x) (((x) >> S_NUM_PKTS_DROPPED) & M_NUM_PKTS_DROPPED) - -#define A_TP_TX_DROP_COUNT 0x4bc - -/* RAT registers */ -#define A_RAT_ROUTE_CONTROL 0x580 - -#define S_USE_ROUTE_TABLE 0 -#define V_USE_ROUTE_TABLE(x) ((x) << S_USE_ROUTE_TABLE) -#define F_USE_ROUTE_TABLE V_USE_ROUTE_TABLE(1U) - -#define S_ENABLE_CSPI 1 -#define V_ENABLE_CSPI(x) ((x) << S_ENABLE_CSPI) -#define F_ENABLE_CSPI V_ENABLE_CSPI(1U) - -#define S_ENABLE_PCIX 2 -#define V_ENABLE_PCIX(x) ((x) << S_ENABLE_PCIX) -#define F_ENABLE_PCIX V_ENABLE_PCIX(1U) - -#define A_RAT_ROUTE_TABLE_INDEX 0x584 - -#define S_ROUTE_TABLE_INDEX 0 -#define M_ROUTE_TABLE_INDEX 0xf -#define V_ROUTE_TABLE_INDEX(x) ((x) << S_ROUTE_TABLE_INDEX) -#define G_ROUTE_TABLE_INDEX(x) (((x) >> S_ROUTE_TABLE_INDEX) & M_ROUTE_TABLE_INDEX) - -#define A_RAT_ROUTE_TABLE_DATA 0x588 -#define A_RAT_NO_ROUTE 0x58c - -#define S_CPL_OPCODE 0 -#define M_CPL_OPCODE 0xff -#define V_CPL_OPCODE(x) ((x) << S_CPL_OPCODE) -#define G_CPL_OPCODE(x) (((x) >> S_CPL_OPCODE) & M_CPL_OPCODE) - -#define A_RAT_INTR_ENABLE 0x590 - -#define S_ZEROROUTEERROR 0 -#define V_ZEROROUTEERROR(x) ((x) << S_ZEROROUTEERROR) -#define F_ZEROROUTEERROR V_ZEROROUTEERROR(1U) - -#define S_CSPIFRAMINGERROR 1 -#define V_CSPIFRAMINGERROR(x) ((x) << S_CSPIFRAMINGERROR) -#define F_CSPIFRAMINGERROR V_CSPIFRAMINGERROR(1U) - -#define S_SGEFRAMINGERROR 2 -#define V_SGEFRAMINGERROR(x) ((x) << S_SGEFRAMINGERROR) -#define F_SGEFRAMINGERROR V_SGEFRAMINGERROR(1U) - -#define S_TPFRAMINGERROR 3 -#define V_TPFRAMINGERROR(x) ((x) << S_TPFRAMINGERROR) -#define F_TPFRAMINGERROR V_TPFRAMINGERROR(1U) - -#define A_RAT_INTR_CAUSE 0x594 - -/* CSPI registers */ -#define A_CSPI_RX_AE_WM 0x810 -#define A_CSPI_RX_AF_WM 0x814 -#define A_CSPI_CALENDAR_LEN 0x818 - -#define S_CALENDARLENGTH 0 -#define M_CALENDARLENGTH 0xffff -#define V_CALENDARLENGTH(x) ((x) << S_CALENDARLENGTH) -#define G_CALENDARLENGTH(x) (((x) >> S_CALENDARLENGTH) & M_CALENDARLENGTH) - -#define A_CSPI_FIFO_STATUS_ENABLE 0x820 - -#define S_FIFOSTATUSENABLE 0 -#define V_FIFOSTATUSENABLE(x) ((x) << S_FIFOSTATUSENABLE) -#define F_FIFOSTATUSENABLE V_FIFOSTATUSENABLE(1U) - -#define A_CSPI_MAXBURST1_MAXBURST2 0x828 - -#define S_MAXBURST1 0 -#define M_MAXBURST1 0xffff -#define V_MAXBURST1(x) ((x) << S_MAXBURST1) -#define G_MAXBURST1(x) (((x) >> S_MAXBURST1) & M_MAXBURST1) - -#define S_MAXBURST2 16 -#define M_MAXBURST2 0xffff -#define V_MAXBURST2(x) ((x) << S_MAXBURST2) -#define G_MAXBURST2(x) (((x) >> S_MAXBURST2) & M_MAXBURST2) - -#define A_CSPI_TRAIN 0x82c - -#define S_CSPI_TRAIN_ALPHA 0 -#define M_CSPI_TRAIN_ALPHA 0xffff -#define V_CSPI_TRAIN_ALPHA(x) ((x) << S_CSPI_TRAIN_ALPHA) -#define G_CSPI_TRAIN_ALPHA(x) (((x) >> S_CSPI_TRAIN_ALPHA) & M_CSPI_TRAIN_ALPHA) - -#define S_CSPI_TRAIN_DATA_MAXT 16 -#define M_CSPI_TRAIN_DATA_MAXT 0xffff -#define V_CSPI_TRAIN_DATA_MAXT(x) ((x) << S_CSPI_TRAIN_DATA_MAXT) -#define G_CSPI_TRAIN_DATA_MAXT(x) (((x) >> S_CSPI_TRAIN_DATA_MAXT) & M_CSPI_TRAIN_DATA_MAXT) - -#define A_CSPI_INTR_STATUS 0x848 - -#define S_DIP4ERR 0 -#define V_DIP4ERR(x) ((x) << S_DIP4ERR) -#define F_DIP4ERR V_DIP4ERR(1U) - -#define S_RXDROP 1 -#define V_RXDROP(x) ((x) << S_RXDROP) -#define F_RXDROP V_RXDROP(1U) - -#define S_TXDROP 2 -#define V_TXDROP(x) ((x) << S_TXDROP) -#define F_TXDROP V_TXDROP(1U) - -#define S_RXOVERFLOW 3 -#define V_RXOVERFLOW(x) ((x) << S_RXOVERFLOW) -#define F_RXOVERFLOW V_RXOVERFLOW(1U) - -#define S_RAMPARITYERR 4 -#define V_RAMPARITYERR(x) ((x) << S_RAMPARITYERR) -#define F_RAMPARITYERR V_RAMPARITYERR(1U) - -#define A_CSPI_INTR_ENABLE 0x84c - -/* ESPI registers */ -#define A_ESPI_SCH_TOKEN0 0x880 - -#define S_SCHTOKEN0 0 -#define M_SCHTOKEN0 0xffff -#define V_SCHTOKEN0(x) ((x) << S_SCHTOKEN0) -#define G_SCHTOKEN0(x) (((x) >> S_SCHTOKEN0) & M_SCHTOKEN0) - -#define A_ESPI_SCH_TOKEN1 0x884 - -#define S_SCHTOKEN1 0 -#define M_SCHTOKEN1 0xffff -#define V_SCHTOKEN1(x) ((x) << S_SCHTOKEN1) -#define G_SCHTOKEN1(x) (((x) >> S_SCHTOKEN1) & M_SCHTOKEN1) - -#define A_ESPI_SCH_TOKEN2 0x888 - -#define S_SCHTOKEN2 0 -#define M_SCHTOKEN2 0xffff -#define V_SCHTOKEN2(x) ((x) << S_SCHTOKEN2) -#define G_SCHTOKEN2(x) (((x) >> S_SCHTOKEN2) & M_SCHTOKEN2) - -#define A_ESPI_SCH_TOKEN3 0x88c - -#define S_SCHTOKEN3 0 -#define M_SCHTOKEN3 0xffff -#define V_SCHTOKEN3(x) ((x) << S_SCHTOKEN3) -#define G_SCHTOKEN3(x) (((x) >> S_SCHTOKEN3) & M_SCHTOKEN3) - -#define A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK 0x890 - -#define S_ALMOSTEMPTY 0 -#define M_ALMOSTEMPTY 0xffff -#define V_ALMOSTEMPTY(x) ((x) << S_ALMOSTEMPTY) -#define G_ALMOSTEMPTY(x) (((x) >> S_ALMOSTEMPTY) & M_ALMOSTEMPTY) - -#define A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK 0x894 - -#define S_ALMOSTFULL 0 -#define M_ALMOSTFULL 0xffff -#define V_ALMOSTFULL(x) ((x) << S_ALMOSTFULL) -#define G_ALMOSTFULL(x) (((x) >> S_ALMOSTFULL) & M_ALMOSTFULL) - -#define A_ESPI_CALENDAR_LENGTH 0x898 -#define A_PORT_CONFIG 0x89c - -#define S_RX_NPORTS 0 -#define M_RX_NPORTS 0xff -#define V_RX_NPORTS(x) ((x) << S_RX_NPORTS) -#define G_RX_NPORTS(x) (((x) >> S_RX_NPORTS) & M_RX_NPORTS) - -#define S_TX_NPORTS 8 -#define M_TX_NPORTS 0xff -#define V_TX_NPORTS(x) ((x) << S_TX_NPORTS) -#define G_TX_NPORTS(x) (((x) >> S_TX_NPORTS) & M_TX_NPORTS) - -#define A_ESPI_FIFO_STATUS_ENABLE 0x8a0 - -#define S_RXSTATUSENABLE 0 -#define V_RXSTATUSENABLE(x) ((x) << S_RXSTATUSENABLE) -#define F_RXSTATUSENABLE V_RXSTATUSENABLE(1U) - -#define S_TXDROPENABLE 1 -#define V_TXDROPENABLE(x) ((x) << S_TXDROPENABLE) -#define F_TXDROPENABLE V_TXDROPENABLE(1U) - -#define S_RXENDIANMODE 2 -#define V_RXENDIANMODE(x) ((x) << S_RXENDIANMODE) -#define F_RXENDIANMODE V_RXENDIANMODE(1U) - -#define S_TXENDIANMODE 3 -#define V_TXENDIANMODE(x) ((x) << S_TXENDIANMODE) -#define F_TXENDIANMODE V_TXENDIANMODE(1U) - -#define S_INTEL1010MODE 4 -#define V_INTEL1010MODE(x) ((x) << S_INTEL1010MODE) -#define F_INTEL1010MODE V_INTEL1010MODE(1U) - -#define A_ESPI_MAXBURST1_MAXBURST2 0x8a8 -#define A_ESPI_TRAIN 0x8ac - -#define S_MAXTRAINALPHA 0 -#define M_MAXTRAINALPHA 0xffff -#define V_MAXTRAINALPHA(x) ((x) << S_MAXTRAINALPHA) -#define G_MAXTRAINALPHA(x) (((x) >> S_MAXTRAINALPHA) & M_MAXTRAINALPHA) - -#define S_MAXTRAINDATA 16 -#define M_MAXTRAINDATA 0xffff -#define V_MAXTRAINDATA(x) ((x) << S_MAXTRAINDATA) -#define G_MAXTRAINDATA(x) (((x) >> S_MAXTRAINDATA) & M_MAXTRAINDATA) - -#define A_RAM_STATUS 0x8b0 - -#define S_RXFIFOPARITYERROR 0 -#define M_RXFIFOPARITYERROR 0x3ff -#define V_RXFIFOPARITYERROR(x) ((x) << S_RXFIFOPARITYERROR) -#define G_RXFIFOPARITYERROR(x) (((x) >> S_RXFIFOPARITYERROR) & M_RXFIFOPARITYERROR) - -#define S_TXFIFOPARITYERROR 10 -#define M_TXFIFOPARITYERROR 0x3ff -#define V_TXFIFOPARITYERROR(x) ((x) << S_TXFIFOPARITYERROR) -#define G_TXFIFOPARITYERROR(x) (((x) >> S_TXFIFOPARITYERROR) & M_TXFIFOPARITYERROR) - -#define S_RXFIFOOVERFLOW 20 -#define M_RXFIFOOVERFLOW 0x3ff -#define V_RXFIFOOVERFLOW(x) ((x) << S_RXFIFOOVERFLOW) -#define G_RXFIFOOVERFLOW(x) (((x) >> S_RXFIFOOVERFLOW) & M_RXFIFOOVERFLOW) - -#define A_TX_DROP_COUNT0 0x8b4 - -#define S_TXPORT0DROPCNT 0 -#define M_TXPORT0DROPCNT 0xffff -#define V_TXPORT0DROPCNT(x) ((x) << S_TXPORT0DROPCNT) -#define G_TXPORT0DROPCNT(x) (((x) >> S_TXPORT0DROPCNT) & M_TXPORT0DROPCNT) - -#define S_TXPORT1DROPCNT 16 -#define M_TXPORT1DROPCNT 0xffff -#define V_TXPORT1DROPCNT(x) ((x) << S_TXPORT1DROPCNT) -#define G_TXPORT1DROPCNT(x) (((x) >> S_TXPORT1DROPCNT) & M_TXPORT1DROPCNT) - -#define A_TX_DROP_COUNT1 0x8b8 - -#define S_TXPORT2DROPCNT 0 -#define M_TXPORT2DROPCNT 0xffff -#define V_TXPORT2DROPCNT(x) ((x) << S_TXPORT2DROPCNT) -#define G_TXPORT2DROPCNT(x) (((x) >> S_TXPORT2DROPCNT) & M_TXPORT2DROPCNT) - -#define S_TXPORT3DROPCNT 16 -#define M_TXPORT3DROPCNT 0xffff -#define V_TXPORT3DROPCNT(x) ((x) << S_TXPORT3DROPCNT) -#define G_TXPORT3DROPCNT(x) (((x) >> S_TXPORT3DROPCNT) & M_TXPORT3DROPCNT) - -#define A_RX_DROP_COUNT0 0x8bc - -#define S_RXPORT0DROPCNT 0 -#define M_RXPORT0DROPCNT 0xffff -#define V_RXPORT0DROPCNT(x) ((x) << S_RXPORT0DROPCNT) -#define G_RXPORT0DROPCNT(x) (((x) >> S_RXPORT0DROPCNT) & M_RXPORT0DROPCNT) - -#define S_RXPORT1DROPCNT 16 -#define M_RXPORT1DROPCNT 0xffff -#define V_RXPORT1DROPCNT(x) ((x) << S_RXPORT1DROPCNT) -#define G_RXPORT1DROPCNT(x) (((x) >> S_RXPORT1DROPCNT) & M_RXPORT1DROPCNT) - -#define A_RX_DROP_COUNT1 0x8c0 - -#define S_RXPORT2DROPCNT 0 -#define M_RXPORT2DROPCNT 0xffff -#define V_RXPORT2DROPCNT(x) ((x) << S_RXPORT2DROPCNT) -#define G_RXPORT2DROPCNT(x) (((x) >> S_RXPORT2DROPCNT) & M_RXPORT2DROPCNT) - -#define S_RXPORT3DROPCNT 16 -#define M_RXPORT3DROPCNT 0xffff -#define V_RXPORT3DROPCNT(x) ((x) << S_RXPORT3DROPCNT) -#define G_RXPORT3DROPCNT(x) (((x) >> S_RXPORT3DROPCNT) & M_RXPORT3DROPCNT) - -#define A_DIP4_ERROR_COUNT 0x8c4 - -#define S_DIP4ERRORCNT 0 -#define M_DIP4ERRORCNT 0xfff -#define V_DIP4ERRORCNT(x) ((x) << S_DIP4ERRORCNT) -#define G_DIP4ERRORCNT(x) (((x) >> S_DIP4ERRORCNT) & M_DIP4ERRORCNT) - -#define S_DIP4ERRORCNTSHADOW 12 -#define M_DIP4ERRORCNTSHADOW 0xfff -#define V_DIP4ERRORCNTSHADOW(x) ((x) << S_DIP4ERRORCNTSHADOW) -#define G_DIP4ERRORCNTSHADOW(x) (((x) >> S_DIP4ERRORCNTSHADOW) & M_DIP4ERRORCNTSHADOW) - -#define S_TRICN_RX_TRAIN_ERR 24 -#define V_TRICN_RX_TRAIN_ERR(x) ((x) << S_TRICN_RX_TRAIN_ERR) -#define F_TRICN_RX_TRAIN_ERR V_TRICN_RX_TRAIN_ERR(1U) - -#define S_TRICN_RX_TRAINING 25 -#define V_TRICN_RX_TRAINING(x) ((x) << S_TRICN_RX_TRAINING) -#define F_TRICN_RX_TRAINING V_TRICN_RX_TRAINING(1U) - -#define S_TRICN_RX_TRAIN_OK 26 -#define V_TRICN_RX_TRAIN_OK(x) ((x) << S_TRICN_RX_TRAIN_OK) -#define F_TRICN_RX_TRAIN_OK V_TRICN_RX_TRAIN_OK(1U) - -#define A_ESPI_INTR_STATUS 0x8c8 - -#define S_DIP2PARITYERR 5 -#define V_DIP2PARITYERR(x) ((x) << S_DIP2PARITYERR) -#define F_DIP2PARITYERR V_DIP2PARITYERR(1U) - -#define A_ESPI_INTR_ENABLE 0x8cc -#define A_RX_DROP_THRESHOLD 0x8d0 -#define A_ESPI_RX_RESET 0x8ec - -#define S_ESPI_RX_LNK_RST 0 -#define V_ESPI_RX_LNK_RST(x) ((x) << S_ESPI_RX_LNK_RST) -#define F_ESPI_RX_LNK_RST V_ESPI_RX_LNK_RST(1U) - -#define S_ESPI_RX_CORE_RST 1 -#define V_ESPI_RX_CORE_RST(x) ((x) << S_ESPI_RX_CORE_RST) -#define F_ESPI_RX_CORE_RST V_ESPI_RX_CORE_RST(1U) - -#define S_RX_CLK_STATUS 2 -#define V_RX_CLK_STATUS(x) ((x) << S_RX_CLK_STATUS) -#define F_RX_CLK_STATUS V_RX_CLK_STATUS(1U) - -#define A_ESPI_MISC_CONTROL 0x8f0 - -#define S_OUT_OF_SYNC_COUNT 0 -#define M_OUT_OF_SYNC_COUNT 0xf -#define V_OUT_OF_SYNC_COUNT(x) ((x) << S_OUT_OF_SYNC_COUNT) -#define G_OUT_OF_SYNC_COUNT(x) (((x) >> S_OUT_OF_SYNC_COUNT) & M_OUT_OF_SYNC_COUNT) - -#define S_DIP2_COUNT_MODE_ENABLE 4 -#define V_DIP2_COUNT_MODE_ENABLE(x) ((x) << S_DIP2_COUNT_MODE_ENABLE) -#define F_DIP2_COUNT_MODE_ENABLE V_DIP2_COUNT_MODE_ENABLE(1U) - -#define S_DIP2_PARITY_ERR_THRES 5 -#define M_DIP2_PARITY_ERR_THRES 0xf -#define V_DIP2_PARITY_ERR_THRES(x) ((x) << S_DIP2_PARITY_ERR_THRES) -#define G_DIP2_PARITY_ERR_THRES(x) (((x) >> S_DIP2_PARITY_ERR_THRES) & M_DIP2_PARITY_ERR_THRES) - -#define S_DIP4_THRES 9 -#define M_DIP4_THRES 0xfff -#define V_DIP4_THRES(x) ((x) << S_DIP4_THRES) -#define G_DIP4_THRES(x) (((x) >> S_DIP4_THRES) & M_DIP4_THRES) - -#define S_DIP4_THRES_ENABLE 21 -#define V_DIP4_THRES_ENABLE(x) ((x) << S_DIP4_THRES_ENABLE) -#define F_DIP4_THRES_ENABLE V_DIP4_THRES_ENABLE(1U) - -#define S_FORCE_DISABLE_STATUS 22 -#define V_FORCE_DISABLE_STATUS(x) ((x) << S_FORCE_DISABLE_STATUS) -#define F_FORCE_DISABLE_STATUS V_FORCE_DISABLE_STATUS(1U) - -#define S_DYNAMIC_DESKEW 23 -#define V_DYNAMIC_DESKEW(x) ((x) << S_DYNAMIC_DESKEW) -#define F_DYNAMIC_DESKEW V_DYNAMIC_DESKEW(1U) - -#define S_MONITORED_PORT_NUM 25 -#define M_MONITORED_PORT_NUM 0x3 -#define V_MONITORED_PORT_NUM(x) ((x) << S_MONITORED_PORT_NUM) -#define G_MONITORED_PORT_NUM(x) (((x) >> S_MONITORED_PORT_NUM) & M_MONITORED_PORT_NUM) - -#define S_MONITORED_DIRECTION 27 -#define V_MONITORED_DIRECTION(x) ((x) << S_MONITORED_DIRECTION) -#define F_MONITORED_DIRECTION V_MONITORED_DIRECTION(1U) - -#define S_MONITORED_INTERFACE 28 -#define V_MONITORED_INTERFACE(x) ((x) << S_MONITORED_INTERFACE) -#define F_MONITORED_INTERFACE V_MONITORED_INTERFACE(1U) - -#define A_ESPI_DIP2_ERR_COUNT 0x8f4 - -#define S_DIP2_ERR_CNT 0 -#define M_DIP2_ERR_CNT 0xf -#define V_DIP2_ERR_CNT(x) ((x) << S_DIP2_ERR_CNT) -#define G_DIP2_ERR_CNT(x) (((x) >> S_DIP2_ERR_CNT) & M_DIP2_ERR_CNT) - -#define A_ESPI_CMD_ADDR 0x8f8 - -#define S_WRITE_DATA 0 -#define M_WRITE_DATA 0xff -#define V_WRITE_DATA(x) ((x) << S_WRITE_DATA) -#define G_WRITE_DATA(x) (((x) >> S_WRITE_DATA) & M_WRITE_DATA) - -#define S_REGISTER_OFFSET 8 -#define M_REGISTER_OFFSET 0xf -#define V_REGISTER_OFFSET(x) ((x) << S_REGISTER_OFFSET) -#define G_REGISTER_OFFSET(x) (((x) >> S_REGISTER_OFFSET) & M_REGISTER_OFFSET) - -#define S_CHANNEL_ADDR 12 -#define M_CHANNEL_ADDR 0xf -#define V_CHANNEL_ADDR(x) ((x) << S_CHANNEL_ADDR) -#define G_CHANNEL_ADDR(x) (((x) >> S_CHANNEL_ADDR) & M_CHANNEL_ADDR) - -#define S_MODULE_ADDR 16 -#define M_MODULE_ADDR 0x3 -#define V_MODULE_ADDR(x) ((x) << S_MODULE_ADDR) -#define G_MODULE_ADDR(x) (((x) >> S_MODULE_ADDR) & M_MODULE_ADDR) - -#define S_BUNDLE_ADDR 20 -#define M_BUNDLE_ADDR 0x3 -#define V_BUNDLE_ADDR(x) ((x) << S_BUNDLE_ADDR) -#define G_BUNDLE_ADDR(x) (((x) >> S_BUNDLE_ADDR) & M_BUNDLE_ADDR) - -#define S_SPI4_COMMAND 24 -#define M_SPI4_COMMAND 0xff -#define V_SPI4_COMMAND(x) ((x) << S_SPI4_COMMAND) -#define G_SPI4_COMMAND(x) (((x) >> S_SPI4_COMMAND) & M_SPI4_COMMAND) - -#define A_ESPI_GOSTAT 0x8fc - -#define S_READ_DATA 0 -#define M_READ_DATA 0xff -#define V_READ_DATA(x) ((x) << S_READ_DATA) -#define G_READ_DATA(x) (((x) >> S_READ_DATA) & M_READ_DATA) - -#define S_ESPI_CMD_BUSY 8 -#define V_ESPI_CMD_BUSY(x) ((x) << S_ESPI_CMD_BUSY) -#define F_ESPI_CMD_BUSY V_ESPI_CMD_BUSY(1U) - -#define S_ERROR_ACK 9 -#define V_ERROR_ACK(x) ((x) << S_ERROR_ACK) -#define F_ERROR_ACK V_ERROR_ACK(1U) - -#define S_UNMAPPED_ERR 10 -#define V_UNMAPPED_ERR(x) ((x) << S_UNMAPPED_ERR) -#define F_UNMAPPED_ERR V_UNMAPPED_ERR(1U) - -#define S_TRANSACTION_TIMER 16 -#define M_TRANSACTION_TIMER 0xff -#define V_TRANSACTION_TIMER(x) ((x) << S_TRANSACTION_TIMER) -#define G_TRANSACTION_TIMER(x) (((x) >> S_TRANSACTION_TIMER) & M_TRANSACTION_TIMER) - - -/* ULP registers */ -#define A_ULP_ULIMIT 0x980 -#define A_ULP_TAGMASK 0x984 -#define A_ULP_HREG_INDEX 0x988 -#define A_ULP_HREG_DATA 0x98c -#define A_ULP_INT_ENABLE 0x990 -#define A_ULP_INT_CAUSE 0x994 - -#define S_HREG_PAR_ERR 0 -#define V_HREG_PAR_ERR(x) ((x) << S_HREG_PAR_ERR) -#define F_HREG_PAR_ERR V_HREG_PAR_ERR(1U) - -#define S_EGRS_DATA_PAR_ERR 1 -#define V_EGRS_DATA_PAR_ERR(x) ((x) << S_EGRS_DATA_PAR_ERR) -#define F_EGRS_DATA_PAR_ERR V_EGRS_DATA_PAR_ERR(1U) - -#define S_INGRS_DATA_PAR_ERR 2 -#define V_INGRS_DATA_PAR_ERR(x) ((x) << S_INGRS_DATA_PAR_ERR) -#define F_INGRS_DATA_PAR_ERR V_INGRS_DATA_PAR_ERR(1U) - -#define S_PM_INTR 3 -#define V_PM_INTR(x) ((x) << S_PM_INTR) -#define F_PM_INTR V_PM_INTR(1U) - -#define S_PM_E2C_SYNC_ERR 4 -#define V_PM_E2C_SYNC_ERR(x) ((x) << S_PM_E2C_SYNC_ERR) -#define F_PM_E2C_SYNC_ERR V_PM_E2C_SYNC_ERR(1U) - -#define S_PM_C2E_SYNC_ERR 5 -#define V_PM_C2E_SYNC_ERR(x) ((x) << S_PM_C2E_SYNC_ERR) -#define F_PM_C2E_SYNC_ERR V_PM_C2E_SYNC_ERR(1U) - -#define S_PM_E2C_EMPTY_ERR 6 -#define V_PM_E2C_EMPTY_ERR(x) ((x) << S_PM_E2C_EMPTY_ERR) -#define F_PM_E2C_EMPTY_ERR V_PM_E2C_EMPTY_ERR(1U) - -#define S_PM_C2E_EMPTY_ERR 7 -#define V_PM_C2E_EMPTY_ERR(x) ((x) << S_PM_C2E_EMPTY_ERR) -#define F_PM_C2E_EMPTY_ERR V_PM_C2E_EMPTY_ERR(1U) - -#define S_PM_PAR_ERR 8 -#define M_PM_PAR_ERR 0xffff -#define V_PM_PAR_ERR(x) ((x) << S_PM_PAR_ERR) -#define G_PM_PAR_ERR(x) (((x) >> S_PM_PAR_ERR) & M_PM_PAR_ERR) - -#define S_PM_E2C_WRT_FULL 24 -#define V_PM_E2C_WRT_FULL(x) ((x) << S_PM_E2C_WRT_FULL) -#define F_PM_E2C_WRT_FULL V_PM_E2C_WRT_FULL(1U) - -#define S_PM_C2E_WRT_FULL 25 -#define V_PM_C2E_WRT_FULL(x) ((x) << S_PM_C2E_WRT_FULL) -#define F_PM_C2E_WRT_FULL V_PM_C2E_WRT_FULL(1U) - -#define A_ULP_PIO_CTRL 0x998 - -/* PL registers */ -#define A_PL_ENABLE 0xa00 - -#define S_PL_INTR_SGE_ERR 0 -#define V_PL_INTR_SGE_ERR(x) ((x) << S_PL_INTR_SGE_ERR) -#define F_PL_INTR_SGE_ERR V_PL_INTR_SGE_ERR(1U) - -#define S_PL_INTR_SGE_DATA 1 -#define V_PL_INTR_SGE_DATA(x) ((x) << S_PL_INTR_SGE_DATA) -#define F_PL_INTR_SGE_DATA V_PL_INTR_SGE_DATA(1U) - -#define S_PL_INTR_MC3 2 -#define V_PL_INTR_MC3(x) ((x) << S_PL_INTR_MC3) -#define F_PL_INTR_MC3 V_PL_INTR_MC3(1U) - -#define S_PL_INTR_MC4 3 -#define V_PL_INTR_MC4(x) ((x) << S_PL_INTR_MC4) -#define F_PL_INTR_MC4 V_PL_INTR_MC4(1U) - -#define S_PL_INTR_MC5 4 -#define V_PL_INTR_MC5(x) ((x) << S_PL_INTR_MC5) -#define F_PL_INTR_MC5 V_PL_INTR_MC5(1U) - -#define S_PL_INTR_RAT 5 -#define V_PL_INTR_RAT(x) ((x) << S_PL_INTR_RAT) -#define F_PL_INTR_RAT V_PL_INTR_RAT(1U) - -#define S_PL_INTR_TP 6 -#define V_PL_INTR_TP(x) ((x) << S_PL_INTR_TP) -#define F_PL_INTR_TP V_PL_INTR_TP(1U) - -#define S_PL_INTR_ULP 7 -#define V_PL_INTR_ULP(x) ((x) << S_PL_INTR_ULP) -#define F_PL_INTR_ULP V_PL_INTR_ULP(1U) - -#define S_PL_INTR_ESPI 8 -#define V_PL_INTR_ESPI(x) ((x) << S_PL_INTR_ESPI) -#define F_PL_INTR_ESPI V_PL_INTR_ESPI(1U) - -#define S_PL_INTR_CSPI 9 -#define V_PL_INTR_CSPI(x) ((x) << S_PL_INTR_CSPI) -#define F_PL_INTR_CSPI V_PL_INTR_CSPI(1U) - -#define S_PL_INTR_PCIX 10 -#define V_PL_INTR_PCIX(x) ((x) << S_PL_INTR_PCIX) -#define F_PL_INTR_PCIX V_PL_INTR_PCIX(1U) - -#define S_PL_INTR_EXT 11 -#define V_PL_INTR_EXT(x) ((x) << S_PL_INTR_EXT) -#define F_PL_INTR_EXT V_PL_INTR_EXT(1U) - -#define A_PL_CAUSE 0xa04 - -/* MC5 registers */ -#define A_MC5_CONFIG 0xc04 - -#define S_MODE 0 -#define V_MODE(x) ((x) << S_MODE) -#define F_MODE V_MODE(1U) - -#define S_TCAM_RESET 1 -#define V_TCAM_RESET(x) ((x) << S_TCAM_RESET) -#define F_TCAM_RESET V_TCAM_RESET(1U) - -#define S_TCAM_READY 2 -#define V_TCAM_READY(x) ((x) << S_TCAM_READY) -#define F_TCAM_READY V_TCAM_READY(1U) - -#define S_DBGI_ENABLE 4 -#define V_DBGI_ENABLE(x) ((x) << S_DBGI_ENABLE) -#define F_DBGI_ENABLE V_DBGI_ENABLE(1U) - -#define S_M_BUS_ENABLE 5 -#define V_M_BUS_ENABLE(x) ((x) << S_M_BUS_ENABLE) -#define F_M_BUS_ENABLE V_M_BUS_ENABLE(1U) - -#define S_PARITY_ENABLE 6 -#define V_PARITY_ENABLE(x) ((x) << S_PARITY_ENABLE) -#define F_PARITY_ENABLE V_PARITY_ENABLE(1U) - -#define S_SYN_ISSUE_MODE 7 -#define M_SYN_ISSUE_MODE 0x3 -#define V_SYN_ISSUE_MODE(x) ((x) << S_SYN_ISSUE_MODE) -#define G_SYN_ISSUE_MODE(x) (((x) >> S_SYN_ISSUE_MODE) & M_SYN_ISSUE_MODE) - -#define S_BUILD 16 -#define V_BUILD(x) ((x) << S_BUILD) -#define F_BUILD V_BUILD(1U) - -#define S_COMPRESSION_ENABLE 17 -#define V_COMPRESSION_ENABLE(x) ((x) << S_COMPRESSION_ENABLE) -#define F_COMPRESSION_ENABLE V_COMPRESSION_ENABLE(1U) - -#define S_NUM_LIP 18 -#define M_NUM_LIP 0x3f -#define V_NUM_LIP(x) ((x) << S_NUM_LIP) -#define G_NUM_LIP(x) (((x) >> S_NUM_LIP) & M_NUM_LIP) - -#define S_TCAM_PART_CNT 24 -#define M_TCAM_PART_CNT 0x3 -#define V_TCAM_PART_CNT(x) ((x) << S_TCAM_PART_CNT) -#define G_TCAM_PART_CNT(x) (((x) >> S_TCAM_PART_CNT) & M_TCAM_PART_CNT) - -#define S_TCAM_PART_TYPE 26 -#define M_TCAM_PART_TYPE 0x3 -#define V_TCAM_PART_TYPE(x) ((x) << S_TCAM_PART_TYPE) -#define G_TCAM_PART_TYPE(x) (((x) >> S_TCAM_PART_TYPE) & M_TCAM_PART_TYPE) - -#define S_TCAM_PART_SIZE 28 -#define M_TCAM_PART_SIZE 0x3 -#define V_TCAM_PART_SIZE(x) ((x) << S_TCAM_PART_SIZE) -#define G_TCAM_PART_SIZE(x) (((x) >> S_TCAM_PART_SIZE) & M_TCAM_PART_SIZE) - -#define S_TCAM_PART_TYPE_HI 30 -#define V_TCAM_PART_TYPE_HI(x) ((x) << S_TCAM_PART_TYPE_HI) -#define F_TCAM_PART_TYPE_HI V_TCAM_PART_TYPE_HI(1U) - -#define A_MC5_SIZE 0xc08 - -#define S_SIZE 0 -#define M_SIZE 0x3fffff -#define V_SIZE(x) ((x) << S_SIZE) -#define G_SIZE(x) (((x) >> S_SIZE) & M_SIZE) - -#define A_MC5_ROUTING_TABLE_INDEX 0xc0c - -#define S_START_OF_ROUTING_TABLE 0 -#define M_START_OF_ROUTING_TABLE 0x3fffff -#define V_START_OF_ROUTING_TABLE(x) ((x) << S_START_OF_ROUTING_TABLE) -#define G_START_OF_ROUTING_TABLE(x) (((x) >> S_START_OF_ROUTING_TABLE) & M_START_OF_ROUTING_TABLE) - -#define A_MC5_SERVER_INDEX 0xc14 - -#define S_START_OF_SERVER_INDEX 0 -#define M_START_OF_SERVER_INDEX 0x3fffff -#define V_START_OF_SERVER_INDEX(x) ((x) << S_START_OF_SERVER_INDEX) -#define G_START_OF_SERVER_INDEX(x) (((x) >> S_START_OF_SERVER_INDEX) & M_START_OF_SERVER_INDEX) - -#define A_MC5_LIP_RAM_ADDR 0xc18 - -#define S_LOCAL_IP_RAM_ADDR 0 -#define M_LOCAL_IP_RAM_ADDR 0x3f -#define V_LOCAL_IP_RAM_ADDR(x) ((x) << S_LOCAL_IP_RAM_ADDR) -#define G_LOCAL_IP_RAM_ADDR(x) (((x) >> S_LOCAL_IP_RAM_ADDR) & M_LOCAL_IP_RAM_ADDR) - -#define S_RAM_WRITE_ENABLE 8 -#define V_RAM_WRITE_ENABLE(x) ((x) << S_RAM_WRITE_ENABLE) -#define F_RAM_WRITE_ENABLE V_RAM_WRITE_ENABLE(1U) - -#define A_MC5_LIP_RAM_DATA 0xc1c -#define A_MC5_RSP_LATENCY 0xc20 - -#define S_SEARCH_RESPONSE_LATENCY 0 -#define M_SEARCH_RESPONSE_LATENCY 0x1f -#define V_SEARCH_RESPONSE_LATENCY(x) ((x) << S_SEARCH_RESPONSE_LATENCY) -#define G_SEARCH_RESPONSE_LATENCY(x) (((x) >> S_SEARCH_RESPONSE_LATENCY) & M_SEARCH_RESPONSE_LATENCY) - -#define S_LEARN_RESPONSE_LATENCY 8 -#define M_LEARN_RESPONSE_LATENCY 0x1f -#define V_LEARN_RESPONSE_LATENCY(x) ((x) << S_LEARN_RESPONSE_LATENCY) -#define G_LEARN_RESPONSE_LATENCY(x) (((x) >> S_LEARN_RESPONSE_LATENCY) & M_LEARN_RESPONSE_LATENCY) - -#define A_MC5_PARITY_LATENCY 0xc24 - -#define S_SRCHLAT 0 -#define M_SRCHLAT 0x1f -#define V_SRCHLAT(x) ((x) << S_SRCHLAT) -#define G_SRCHLAT(x) (((x) >> S_SRCHLAT) & M_SRCHLAT) - -#define S_PARLAT 8 -#define M_PARLAT 0x1f -#define V_PARLAT(x) ((x) << S_PARLAT) -#define G_PARLAT(x) (((x) >> S_PARLAT) & M_PARLAT) - -#define A_MC5_WR_LRN_VERIFY 0xc28 - -#define S_POVEREN 0 -#define V_POVEREN(x) ((x) << S_POVEREN) -#define F_POVEREN V_POVEREN(1U) - -#define S_LRNVEREN 1 -#define V_LRNVEREN(x) ((x) << S_LRNVEREN) -#define F_LRNVEREN V_LRNVEREN(1U) - -#define S_VWVEREN 2 -#define V_VWVEREN(x) ((x) << S_VWVEREN) -#define F_VWVEREN V_VWVEREN(1U) - -#define A_MC5_PART_ID_INDEX 0xc2c - -#define S_IDINDEX 0 -#define M_IDINDEX 0xf -#define V_IDINDEX(x) ((x) << S_IDINDEX) -#define G_IDINDEX(x) (((x) >> S_IDINDEX) & M_IDINDEX) - -#define A_MC5_RESET_MAX 0xc30 - -#define S_RSTMAX 0 -#define M_RSTMAX 0x1ff -#define V_RSTMAX(x) ((x) << S_RSTMAX) -#define G_RSTMAX(x) (((x) >> S_RSTMAX) & M_RSTMAX) - -#define A_MC5_INT_ENABLE 0xc40 - -#define S_MC5_INT_HIT_OUT_ACTIVE_REGION_ERR 0 -#define V_MC5_INT_HIT_OUT_ACTIVE_REGION_ERR(x) ((x) << S_MC5_INT_HIT_OUT_ACTIVE_REGION_ERR) -#define F_MC5_INT_HIT_OUT_ACTIVE_REGION_ERR V_MC5_INT_HIT_OUT_ACTIVE_REGION_ERR(1U) - -#define S_MC5_INT_HIT_IN_ACTIVE_REGION_ERR 1 -#define V_MC5_INT_HIT_IN_ACTIVE_REGION_ERR(x) ((x) << S_MC5_INT_HIT_IN_ACTIVE_REGION_ERR) -#define F_MC5_INT_HIT_IN_ACTIVE_REGION_ERR V_MC5_INT_HIT_IN_ACTIVE_REGION_ERR(1U) - -#define S_MC5_INT_HIT_IN_RT_REGION_ERR 2 -#define V_MC5_INT_HIT_IN_RT_REGION_ERR(x) ((x) << S_MC5_INT_HIT_IN_RT_REGION_ERR) -#define F_MC5_INT_HIT_IN_RT_REGION_ERR V_MC5_INT_HIT_IN_RT_REGION_ERR(1U) - -#define S_MC5_INT_MISS_ERR 3 -#define V_MC5_INT_MISS_ERR(x) ((x) << S_MC5_INT_MISS_ERR) -#define F_MC5_INT_MISS_ERR V_MC5_INT_MISS_ERR(1U) - -#define S_MC5_INT_LIP0_ERR 4 -#define V_MC5_INT_LIP0_ERR(x) ((x) << S_MC5_INT_LIP0_ERR) -#define F_MC5_INT_LIP0_ERR V_MC5_INT_LIP0_ERR(1U) - -#define S_MC5_INT_LIP_MISS_ERR 5 -#define V_MC5_INT_LIP_MISS_ERR(x) ((x) << S_MC5_INT_LIP_MISS_ERR) -#define F_MC5_INT_LIP_MISS_ERR V_MC5_INT_LIP_MISS_ERR(1U) - -#define S_MC5_INT_PARITY_ERR 6 -#define V_MC5_INT_PARITY_ERR(x) ((x) << S_MC5_INT_PARITY_ERR) -#define F_MC5_INT_PARITY_ERR V_MC5_INT_PARITY_ERR(1U) - -#define S_MC5_INT_ACTIVE_REGION_FULL 7 -#define V_MC5_INT_ACTIVE_REGION_FULL(x) ((x) << S_MC5_INT_ACTIVE_REGION_FULL) -#define F_MC5_INT_ACTIVE_REGION_FULL V_MC5_INT_ACTIVE_REGION_FULL(1U) - -#define S_MC5_INT_NFA_SRCH_ERR 8 -#define V_MC5_INT_NFA_SRCH_ERR(x) ((x) << S_MC5_INT_NFA_SRCH_ERR) -#define F_MC5_INT_NFA_SRCH_ERR V_MC5_INT_NFA_SRCH_ERR(1U) - -#define S_MC5_INT_SYN_COOKIE 9 -#define V_MC5_INT_SYN_COOKIE(x) ((x) << S_MC5_INT_SYN_COOKIE) -#define F_MC5_INT_SYN_COOKIE V_MC5_INT_SYN_COOKIE(1U) - -#define S_MC5_INT_SYN_COOKIE_BAD 10 -#define V_MC5_INT_SYN_COOKIE_BAD(x) ((x) << S_MC5_INT_SYN_COOKIE_BAD) -#define F_MC5_INT_SYN_COOKIE_BAD V_MC5_INT_SYN_COOKIE_BAD(1U) - -#define S_MC5_INT_SYN_COOKIE_OFF 11 -#define V_MC5_INT_SYN_COOKIE_OFF(x) ((x) << S_MC5_INT_SYN_COOKIE_OFF) -#define F_MC5_INT_SYN_COOKIE_OFF V_MC5_INT_SYN_COOKIE_OFF(1U) - -#define S_MC5_INT_UNKNOWN_CMD 15 -#define V_MC5_INT_UNKNOWN_CMD(x) ((x) << S_MC5_INT_UNKNOWN_CMD) -#define F_MC5_INT_UNKNOWN_CMD V_MC5_INT_UNKNOWN_CMD(1U) - -#define S_MC5_INT_REQUESTQ_PARITY_ERR 16 -#define V_MC5_INT_REQUESTQ_PARITY_ERR(x) ((x) << S_MC5_INT_REQUESTQ_PARITY_ERR) -#define F_MC5_INT_REQUESTQ_PARITY_ERR V_MC5_INT_REQUESTQ_PARITY_ERR(1U) - -#define S_MC5_INT_DISPATCHQ_PARITY_ERR 17 -#define V_MC5_INT_DISPATCHQ_PARITY_ERR(x) ((x) << S_MC5_INT_DISPATCHQ_PARITY_ERR) -#define F_MC5_INT_DISPATCHQ_PARITY_ERR V_MC5_INT_DISPATCHQ_PARITY_ERR(1U) - -#define S_MC5_INT_DEL_ACT_EMPTY 18 -#define V_MC5_INT_DEL_ACT_EMPTY(x) ((x) << S_MC5_INT_DEL_ACT_EMPTY) -#define F_MC5_INT_DEL_ACT_EMPTY V_MC5_INT_DEL_ACT_EMPTY(1U) - -#define A_MC5_INT_CAUSE 0xc44 -#define A_MC5_INT_TID 0xc48 -#define A_MC5_INT_PTID 0xc4c -#define A_MC5_DBGI_CONFIG 0xc74 -#define A_MC5_DBGI_REQ_CMD 0xc78 - -#define S_CMDMODE 0 -#define M_CMDMODE 0x7 -#define V_CMDMODE(x) ((x) << S_CMDMODE) -#define G_CMDMODE(x) (((x) >> S_CMDMODE) & M_CMDMODE) - -#define S_SADRSEL 4 -#define V_SADRSEL(x) ((x) << S_SADRSEL) -#define F_SADRSEL V_SADRSEL(1U) - -#define S_WRITE_BURST_SIZE 22 -#define M_WRITE_BURST_SIZE 0x3ff -#define V_WRITE_BURST_SIZE(x) ((x) << S_WRITE_BURST_SIZE) -#define G_WRITE_BURST_SIZE(x) (((x) >> S_WRITE_BURST_SIZE) & M_WRITE_BURST_SIZE) - -#define A_MC5_DBGI_REQ_ADDR0 0xc7c -#define A_MC5_DBGI_REQ_ADDR1 0xc80 -#define A_MC5_DBGI_REQ_ADDR2 0xc84 -#define A_MC5_DBGI_REQ_DATA0 0xc88 -#define A_MC5_DBGI_REQ_DATA1 0xc8c -#define A_MC5_DBGI_REQ_DATA2 0xc90 -#define A_MC5_DBGI_REQ_DATA3 0xc94 -#define A_MC5_DBGI_REQ_DATA4 0xc98 -#define A_MC5_DBGI_REQ_MASK0 0xc9c -#define A_MC5_DBGI_REQ_MASK1 0xca0 -#define A_MC5_DBGI_REQ_MASK2 0xca4 -#define A_MC5_DBGI_REQ_MASK3 0xca8 -#define A_MC5_DBGI_REQ_MASK4 0xcac -#define A_MC5_DBGI_RSP_STATUS 0xcb0 - -#define S_DBGI_RSP_VALID 0 -#define V_DBGI_RSP_VALID(x) ((x) << S_DBGI_RSP_VALID) -#define F_DBGI_RSP_VALID V_DBGI_RSP_VALID(1U) - -#define S_DBGI_RSP_HIT 1 -#define V_DBGI_RSP_HIT(x) ((x) << S_DBGI_RSP_HIT) -#define F_DBGI_RSP_HIT V_DBGI_RSP_HIT(1U) - -#define S_DBGI_RSP_ERR 2 -#define V_DBGI_RSP_ERR(x) ((x) << S_DBGI_RSP_ERR) -#define F_DBGI_RSP_ERR V_DBGI_RSP_ERR(1U) - -#define S_DBGI_RSP_ERR_REASON 8 -#define M_DBGI_RSP_ERR_REASON 0x7 -#define V_DBGI_RSP_ERR_REASON(x) ((x) << S_DBGI_RSP_ERR_REASON) -#define G_DBGI_RSP_ERR_REASON(x) (((x) >> S_DBGI_RSP_ERR_REASON) & M_DBGI_RSP_ERR_REASON) - -#define A_MC5_DBGI_RSP_DATA0 0xcb4 -#define A_MC5_DBGI_RSP_DATA1 0xcb8 -#define A_MC5_DBGI_RSP_DATA2 0xcbc -#define A_MC5_DBGI_RSP_DATA3 0xcc0 -#define A_MC5_DBGI_RSP_DATA4 0xcc4 -#define A_MC5_DBGI_RSP_LAST_CMD 0xcc8 -#define A_MC5_POPEN_DATA_WR_CMD 0xccc -#define A_MC5_POPEN_MASK_WR_CMD 0xcd0 -#define A_MC5_AOPEN_SRCH_CMD 0xcd4 -#define A_MC5_AOPEN_LRN_CMD 0xcd8 -#define A_MC5_SYN_SRCH_CMD 0xcdc -#define A_MC5_SYN_LRN_CMD 0xce0 -#define A_MC5_ACK_SRCH_CMD 0xce4 -#define A_MC5_ACK_LRN_CMD 0xce8 -#define A_MC5_ILOOKUP_CMD 0xcec -#define A_MC5_ELOOKUP_CMD 0xcf0 -#define A_MC5_DATA_WRITE_CMD 0xcf4 -#define A_MC5_DATA_READ_CMD 0xcf8 -#define A_MC5_MASK_WRITE_CMD 0xcfc - -/* PCICFG registers */ -#define A_PCICFG_PM_CSR 0x44 -#define A_PCICFG_VPD_ADDR 0x4a - -#define S_VPD_ADDR 0 -#define M_VPD_ADDR 0x7fff -#define V_VPD_ADDR(x) ((x) << S_VPD_ADDR) -#define G_VPD_ADDR(x) (((x) >> S_VPD_ADDR) & M_VPD_ADDR) - -#define S_VPD_OP_FLAG 15 -#define V_VPD_OP_FLAG(x) ((x) << S_VPD_OP_FLAG) -#define F_VPD_OP_FLAG V_VPD_OP_FLAG(1U) - -#define A_PCICFG_VPD_DATA 0x4c -#define A_PCICFG_PCIX_CMD 0x60 -#define A_PCICFG_INTR_ENABLE 0xf4 - -#define S_MASTER_PARITY_ERR 0 -#define V_MASTER_PARITY_ERR(x) ((x) << S_MASTER_PARITY_ERR) -#define F_MASTER_PARITY_ERR V_MASTER_PARITY_ERR(1U) - -#define S_SIG_TARGET_ABORT 1 -#define V_SIG_TARGET_ABORT(x) ((x) << S_SIG_TARGET_ABORT) -#define F_SIG_TARGET_ABORT V_SIG_TARGET_ABORT(1U) - -#define S_RCV_TARGET_ABORT 2 -#define V_RCV_TARGET_ABORT(x) ((x) << S_RCV_TARGET_ABORT) -#define F_RCV_TARGET_ABORT V_RCV_TARGET_ABORT(1U) - -#define S_RCV_MASTER_ABORT 3 -#define V_RCV_MASTER_ABORT(x) ((x) << S_RCV_MASTER_ABORT) -#define F_RCV_MASTER_ABORT V_RCV_MASTER_ABORT(1U) - -#define S_SIG_SYS_ERR 4 -#define V_SIG_SYS_ERR(x) ((x) << S_SIG_SYS_ERR) -#define F_SIG_SYS_ERR V_SIG_SYS_ERR(1U) - -#define S_DET_PARITY_ERR 5 -#define V_DET_PARITY_ERR(x) ((x) << S_DET_PARITY_ERR) -#define F_DET_PARITY_ERR V_DET_PARITY_ERR(1U) - -#define S_PIO_PARITY_ERR 6 -#define V_PIO_PARITY_ERR(x) ((x) << S_PIO_PARITY_ERR) -#define F_PIO_PARITY_ERR V_PIO_PARITY_ERR(1U) - -#define S_WF_PARITY_ERR 7 -#define V_WF_PARITY_ERR(x) ((x) << S_WF_PARITY_ERR) -#define F_WF_PARITY_ERR V_WF_PARITY_ERR(1U) - -#define S_RF_PARITY_ERR 8 -#define M_RF_PARITY_ERR 0x3 -#define V_RF_PARITY_ERR(x) ((x) << S_RF_PARITY_ERR) -#define G_RF_PARITY_ERR(x) (((x) >> S_RF_PARITY_ERR) & M_RF_PARITY_ERR) - -#define S_CF_PARITY_ERR 10 -#define M_CF_PARITY_ERR 0x3 -#define V_CF_PARITY_ERR(x) ((x) << S_CF_PARITY_ERR) -#define G_CF_PARITY_ERR(x) (((x) >> S_CF_PARITY_ERR) & M_CF_PARITY_ERR) - -#define A_PCICFG_INTR_CAUSE 0xf8 -#define A_PCICFG_MODE 0xfc - -#define S_PCI_MODE_64BIT 0 -#define V_PCI_MODE_64BIT(x) ((x) << S_PCI_MODE_64BIT) -#define F_PCI_MODE_64BIT V_PCI_MODE_64BIT(1U) - -#define S_PCI_MODE_66MHZ 1 -#define V_PCI_MODE_66MHZ(x) ((x) << S_PCI_MODE_66MHZ) -#define F_PCI_MODE_66MHZ V_PCI_MODE_66MHZ(1U) - -#define S_PCI_MODE_PCIX_INITPAT 2 -#define M_PCI_MODE_PCIX_INITPAT 0x7 -#define V_PCI_MODE_PCIX_INITPAT(x) ((x) << S_PCI_MODE_PCIX_INITPAT) -#define G_PCI_MODE_PCIX_INITPAT(x) (((x) >> S_PCI_MODE_PCIX_INITPAT) & M_PCI_MODE_PCIX_INITPAT) - -#define S_PCI_MODE_PCIX 5 -#define V_PCI_MODE_PCIX(x) ((x) << S_PCI_MODE_PCIX) -#define F_PCI_MODE_PCIX V_PCI_MODE_PCIX(1U) - -#define S_PCI_MODE_CLK 6 -#define M_PCI_MODE_CLK 0x3 -#define V_PCI_MODE_CLK(x) ((x) << S_PCI_MODE_CLK) -#define G_PCI_MODE_CLK(x) (((x) >> S_PCI_MODE_CLK) & M_PCI_MODE_CLK) - -#endif /* _CXGB_REGS_H_ */ diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c deleted file mode 100644 index e9a03fffef15..000000000000 --- a/drivers/net/chelsio/sge.c +++ /dev/null @@ -1,2140 +0,0 @@ -/***************************************************************************** - * * - * File: sge.c * - * $Revision: 1.26 $ * - * $Date: 2005/06/21 18:29:48 $ * - * Description: * - * DMA engine. * - * part of the Chelsio 10Gb Ethernet Driver. * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * * - * http://www.chelsio.com * - * * - * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * - * All rights reserved. * - * * - * Maintainers: maintainers@chelsio.com * - * * - * Authors: Dimitrios Michailidis * - * Tina Yang * - * Felix Marti * - * Scott Bardone * - * Kurt Ottaway * - * Frank DiMambro * - * * - * History: * - * * - ****************************************************************************/ - -#include "common.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cpl5_cmd.h" -#include "sge.h" -#include "regs.h" -#include "espi.h" - -/* This belongs in if_ether.h */ -#define ETH_P_CPL5 0xf - -#define SGE_CMDQ_N 2 -#define SGE_FREELQ_N 2 -#define SGE_CMDQ0_E_N 1024 -#define SGE_CMDQ1_E_N 128 -#define SGE_FREEL_SIZE 4096 -#define SGE_JUMBO_FREEL_SIZE 512 -#define SGE_FREEL_REFILL_THRESH 16 -#define SGE_RESPQ_E_N 1024 -#define SGE_INTRTIMER_NRES 1000 -#define SGE_RX_SM_BUF_SIZE 1536 -#define SGE_TX_DESC_MAX_PLEN 16384 - -#define SGE_RESPQ_REPLENISH_THRES (SGE_RESPQ_E_N / 4) - -/* - * Period of the TX buffer reclaim timer. This timer does not need to run - * frequently as TX buffers are usually reclaimed by new TX packets. - */ -#define TX_RECLAIM_PERIOD (HZ / 4) - -#define M_CMD_LEN 0x7fffffff -#define V_CMD_LEN(v) (v) -#define G_CMD_LEN(v) ((v) & M_CMD_LEN) -#define V_CMD_GEN1(v) ((v) << 31) -#define V_CMD_GEN2(v) (v) -#define F_CMD_DATAVALID (1 << 1) -#define F_CMD_SOP (1 << 2) -#define V_CMD_EOP(v) ((v) << 3) - -/* - * Command queue, receive buffer list, and response queue descriptors. - */ -#if defined(__BIG_ENDIAN_BITFIELD) -struct cmdQ_e { - u32 addr_lo; - u32 len_gen; - u32 flags; - u32 addr_hi; -}; - -struct freelQ_e { - u32 addr_lo; - u32 len_gen; - u32 gen2; - u32 addr_hi; -}; - -struct respQ_e { - u32 Qsleeping : 4; - u32 Cmdq1CreditReturn : 5; - u32 Cmdq1DmaComplete : 5; - u32 Cmdq0CreditReturn : 5; - u32 Cmdq0DmaComplete : 5; - u32 FreelistQid : 2; - u32 CreditValid : 1; - u32 DataValid : 1; - u32 Offload : 1; - u32 Eop : 1; - u32 Sop : 1; - u32 GenerationBit : 1; - u32 BufferLength; -}; -#elif defined(__LITTLE_ENDIAN_BITFIELD) -struct cmdQ_e { - u32 len_gen; - u32 addr_lo; - u32 addr_hi; - u32 flags; -}; - -struct freelQ_e { - u32 len_gen; - u32 addr_lo; - u32 addr_hi; - u32 gen2; -}; - -struct respQ_e { - u32 BufferLength; - u32 GenerationBit : 1; - u32 Sop : 1; - u32 Eop : 1; - u32 Offload : 1; - u32 DataValid : 1; - u32 CreditValid : 1; - u32 FreelistQid : 2; - u32 Cmdq0DmaComplete : 5; - u32 Cmdq0CreditReturn : 5; - u32 Cmdq1DmaComplete : 5; - u32 Cmdq1CreditReturn : 5; - u32 Qsleeping : 4; -} ; -#endif - -/* - * SW Context Command and Freelist Queue Descriptors - */ -struct cmdQ_ce { - struct sk_buff *skb; - DEFINE_DMA_UNMAP_ADDR(dma_addr); - DEFINE_DMA_UNMAP_LEN(dma_len); -}; - -struct freelQ_ce { - struct sk_buff *skb; - DEFINE_DMA_UNMAP_ADDR(dma_addr); - DEFINE_DMA_UNMAP_LEN(dma_len); -}; - -/* - * SW command, freelist and response rings - */ -struct cmdQ { - unsigned long status; /* HW DMA fetch status */ - unsigned int in_use; /* # of in-use command descriptors */ - unsigned int size; /* # of descriptors */ - unsigned int processed; /* total # of descs HW has processed */ - unsigned int cleaned; /* total # of descs SW has reclaimed */ - unsigned int stop_thres; /* SW TX queue suspend threshold */ - u16 pidx; /* producer index (SW) */ - u16 cidx; /* consumer index (HW) */ - u8 genbit; /* current generation (=valid) bit */ - u8 sop; /* is next entry start of packet? */ - struct cmdQ_e *entries; /* HW command descriptor Q */ - struct cmdQ_ce *centries; /* SW command context descriptor Q */ - dma_addr_t dma_addr; /* DMA addr HW command descriptor Q */ - spinlock_t lock; /* Lock to protect cmdQ enqueuing */ -}; - -struct freelQ { - unsigned int credits; /* # of available RX buffers */ - unsigned int size; /* free list capacity */ - u16 pidx; /* producer index (SW) */ - u16 cidx; /* consumer index (HW) */ - u16 rx_buffer_size; /* Buffer size on this free list */ - u16 dma_offset; /* DMA offset to align IP headers */ - u16 recycleq_idx; /* skb recycle q to use */ - u8 genbit; /* current generation (=valid) bit */ - struct freelQ_e *entries; /* HW freelist descriptor Q */ - struct freelQ_ce *centries; /* SW freelist context descriptor Q */ - dma_addr_t dma_addr; /* DMA addr HW freelist descriptor Q */ -}; - -struct respQ { - unsigned int credits; /* credits to be returned to SGE */ - unsigned int size; /* # of response Q descriptors */ - u16 cidx; /* consumer index (SW) */ - u8 genbit; /* current generation(=valid) bit */ - struct respQ_e *entries; /* HW response descriptor Q */ - dma_addr_t dma_addr; /* DMA addr HW response descriptor Q */ -}; - -/* Bit flags for cmdQ.status */ -enum { - CMDQ_STAT_RUNNING = 1, /* fetch engine is running */ - CMDQ_STAT_LAST_PKT_DB = 2 /* last packet rung the doorbell */ -}; - -/* T204 TX SW scheduler */ - -/* Per T204 TX port */ -struct sched_port { - unsigned int avail; /* available bits - quota */ - unsigned int drain_bits_per_1024ns; /* drain rate */ - unsigned int speed; /* drain rate, mbps */ - unsigned int mtu; /* mtu size */ - struct sk_buff_head skbq; /* pending skbs */ -}; - -/* Per T204 device */ -struct sched { - ktime_t last_updated; /* last time quotas were computed */ - unsigned int max_avail; /* max bits to be sent to any port */ - unsigned int port; /* port index (round robin ports) */ - unsigned int num; /* num skbs in per port queues */ - struct sched_port p[MAX_NPORTS]; - struct tasklet_struct sched_tsk;/* tasklet used to run scheduler */ -}; -static void restart_sched(unsigned long); - - -/* - * Main SGE data structure - * - * Interrupts are handled by a single CPU and it is likely that on a MP system - * the application is migrated to another CPU. In that scenario, we try to - * separate the RX(in irq context) and TX state in order to decrease memory - * contention. - */ -struct sge { - struct adapter *adapter; /* adapter backpointer */ - struct net_device *netdev; /* netdevice backpointer */ - struct freelQ freelQ[SGE_FREELQ_N]; /* buffer free lists */ - struct respQ respQ; /* response Q */ - unsigned long stopped_tx_queues; /* bitmap of suspended Tx queues */ - unsigned int rx_pkt_pad; /* RX padding for L2 packets */ - unsigned int jumbo_fl; /* jumbo freelist Q index */ - unsigned int intrtimer_nres; /* no-resource interrupt timer */ - unsigned int fixed_intrtimer;/* non-adaptive interrupt timer */ - struct timer_list tx_reclaim_timer; /* reclaims TX buffers */ - struct timer_list espibug_timer; - unsigned long espibug_timeout; - struct sk_buff *espibug_skb[MAX_NPORTS]; - u32 sge_control; /* shadow value of sge control reg */ - struct sge_intr_counts stats; - struct sge_port_stats __percpu *port_stats[MAX_NPORTS]; - struct sched *tx_sched; - struct cmdQ cmdQ[SGE_CMDQ_N] ____cacheline_aligned_in_smp; -}; - -static const u8 ch_mac_addr[ETH_ALEN] = { - 0x0, 0x7, 0x43, 0x0, 0x0, 0x0 -}; - -/* - * stop tasklet and free all pending skb's - */ -static void tx_sched_stop(struct sge *sge) -{ - struct sched *s = sge->tx_sched; - int i; - - tasklet_kill(&s->sched_tsk); - - for (i = 0; i < MAX_NPORTS; i++) - __skb_queue_purge(&s->p[s->port].skbq); -} - -/* - * t1_sched_update_parms() is called when the MTU or link speed changes. It - * re-computes scheduler parameters to scope with the change. - */ -unsigned int t1_sched_update_parms(struct sge *sge, unsigned int port, - unsigned int mtu, unsigned int speed) -{ - struct sched *s = sge->tx_sched; - struct sched_port *p = &s->p[port]; - unsigned int max_avail_segs; - - pr_debug("t1_sched_update_params mtu=%d speed=%d\n", mtu, speed); - if (speed) - p->speed = speed; - if (mtu) - p->mtu = mtu; - - if (speed || mtu) { - unsigned long long drain = 1024ULL * p->speed * (p->mtu - 40); - do_div(drain, (p->mtu + 50) * 1000); - p->drain_bits_per_1024ns = (unsigned int) drain; - - if (p->speed < 1000) - p->drain_bits_per_1024ns = - 90 * p->drain_bits_per_1024ns / 100; - } - - if (board_info(sge->adapter)->board == CHBT_BOARD_CHT204) { - p->drain_bits_per_1024ns -= 16; - s->max_avail = max(4096U, p->mtu + 16 + 14 + 4); - max_avail_segs = max(1U, 4096 / (p->mtu - 40)); - } else { - s->max_avail = 16384; - max_avail_segs = max(1U, 9000 / (p->mtu - 40)); - } - - pr_debug("t1_sched_update_parms: mtu %u speed %u max_avail %u " - "max_avail_segs %u drain_bits_per_1024ns %u\n", p->mtu, - p->speed, s->max_avail, max_avail_segs, - p->drain_bits_per_1024ns); - - return max_avail_segs * (p->mtu - 40); -} - -#if 0 - -/* - * t1_sched_max_avail_bytes() tells the scheduler the maximum amount of - * data that can be pushed per port. - */ -void t1_sched_set_max_avail_bytes(struct sge *sge, unsigned int val) -{ - struct sched *s = sge->tx_sched; - unsigned int i; - - s->max_avail = val; - for (i = 0; i < MAX_NPORTS; i++) - t1_sched_update_parms(sge, i, 0, 0); -} - -/* - * t1_sched_set_drain_bits_per_us() tells the scheduler at which rate a port - * is draining. - */ -void t1_sched_set_drain_bits_per_us(struct sge *sge, unsigned int port, - unsigned int val) -{ - struct sched *s = sge->tx_sched; - struct sched_port *p = &s->p[port]; - p->drain_bits_per_1024ns = val * 1024 / 1000; - t1_sched_update_parms(sge, port, 0, 0); -} - -#endif /* 0 */ - - -/* - * get_clock() implements a ns clock (see ktime_get) - */ -static inline ktime_t get_clock(void) -{ - struct timespec ts; - - ktime_get_ts(&ts); - return timespec_to_ktime(ts); -} - -/* - * tx_sched_init() allocates resources and does basic initialization. - */ -static int tx_sched_init(struct sge *sge) -{ - struct sched *s; - int i; - - s = kzalloc(sizeof (struct sched), GFP_KERNEL); - if (!s) - return -ENOMEM; - - pr_debug("tx_sched_init\n"); - tasklet_init(&s->sched_tsk, restart_sched, (unsigned long) sge); - sge->tx_sched = s; - - for (i = 0; i < MAX_NPORTS; i++) { - skb_queue_head_init(&s->p[i].skbq); - t1_sched_update_parms(sge, i, 1500, 1000); - } - - return 0; -} - -/* - * sched_update_avail() computes the delta since the last time it was called - * and updates the per port quota (number of bits that can be sent to the any - * port). - */ -static inline int sched_update_avail(struct sge *sge) -{ - struct sched *s = sge->tx_sched; - ktime_t now = get_clock(); - unsigned int i; - long long delta_time_ns; - - delta_time_ns = ktime_to_ns(ktime_sub(now, s->last_updated)); - - pr_debug("sched_update_avail delta=%lld\n", delta_time_ns); - if (delta_time_ns < 15000) - return 0; - - for (i = 0; i < MAX_NPORTS; i++) { - struct sched_port *p = &s->p[i]; - unsigned int delta_avail; - - delta_avail = (p->drain_bits_per_1024ns * delta_time_ns) >> 13; - p->avail = min(p->avail + delta_avail, s->max_avail); - } - - s->last_updated = now; - - return 1; -} - -/* - * sched_skb() is called from two different places. In the tx path, any - * packet generating load on an output port will call sched_skb() - * (skb != NULL). In addition, sched_skb() is called from the irq/soft irq - * context (skb == NULL). - * The scheduler only returns a skb (which will then be sent) if the - * length of the skb is <= the current quota of the output port. - */ -static struct sk_buff *sched_skb(struct sge *sge, struct sk_buff *skb, - unsigned int credits) -{ - struct sched *s = sge->tx_sched; - struct sk_buff_head *skbq; - unsigned int i, len, update = 1; - - pr_debug("sched_skb %p\n", skb); - if (!skb) { - if (!s->num) - return NULL; - } else { - skbq = &s->p[skb->dev->if_port].skbq; - __skb_queue_tail(skbq, skb); - s->num++; - skb = NULL; - } - - if (credits < MAX_SKB_FRAGS + 1) - goto out; - -again: - for (i = 0; i < MAX_NPORTS; i++) { - s->port = (s->port + 1) & (MAX_NPORTS - 1); - skbq = &s->p[s->port].skbq; - - skb = skb_peek(skbq); - - if (!skb) - continue; - - len = skb->len; - if (len <= s->p[s->port].avail) { - s->p[s->port].avail -= len; - s->num--; - __skb_unlink(skb, skbq); - goto out; - } - skb = NULL; - } - - if (update-- && sched_update_avail(sge)) - goto again; - -out: - /* If there are more pending skbs, we use the hardware to schedule us - * again. - */ - if (s->num && !skb) { - struct cmdQ *q = &sge->cmdQ[0]; - clear_bit(CMDQ_STAT_LAST_PKT_DB, &q->status); - if (test_and_set_bit(CMDQ_STAT_RUNNING, &q->status) == 0) { - set_bit(CMDQ_STAT_LAST_PKT_DB, &q->status); - writel(F_CMDQ0_ENABLE, sge->adapter->regs + A_SG_DOORBELL); - } - } - pr_debug("sched_skb ret %p\n", skb); - - return skb; -} - -/* - * PIO to indicate that memory mapped Q contains valid descriptor(s). - */ -static inline void doorbell_pio(struct adapter *adapter, u32 val) -{ - wmb(); - writel(val, adapter->regs + A_SG_DOORBELL); -} - -/* - * Frees all RX buffers on the freelist Q. The caller must make sure that - * the SGE is turned off before calling this function. - */ -static void free_freelQ_buffers(struct pci_dev *pdev, struct freelQ *q) -{ - unsigned int cidx = q->cidx; - - while (q->credits--) { - struct freelQ_ce *ce = &q->centries[cidx]; - - pci_unmap_single(pdev, dma_unmap_addr(ce, dma_addr), - dma_unmap_len(ce, dma_len), - PCI_DMA_FROMDEVICE); - dev_kfree_skb(ce->skb); - ce->skb = NULL; - if (++cidx == q->size) - cidx = 0; - } -} - -/* - * Free RX free list and response queue resources. - */ -static void free_rx_resources(struct sge *sge) -{ - struct pci_dev *pdev = sge->adapter->pdev; - unsigned int size, i; - - if (sge->respQ.entries) { - size = sizeof(struct respQ_e) * sge->respQ.size; - pci_free_consistent(pdev, size, sge->respQ.entries, - sge->respQ.dma_addr); - } - - for (i = 0; i < SGE_FREELQ_N; i++) { - struct freelQ *q = &sge->freelQ[i]; - - if (q->centries) { - free_freelQ_buffers(pdev, q); - kfree(q->centries); - } - if (q->entries) { - size = sizeof(struct freelQ_e) * q->size; - pci_free_consistent(pdev, size, q->entries, - q->dma_addr); - } - } -} - -/* - * Allocates basic RX resources, consisting of memory mapped freelist Qs and a - * response queue. - */ -static int alloc_rx_resources(struct sge *sge, struct sge_params *p) -{ - struct pci_dev *pdev = sge->adapter->pdev; - unsigned int size, i; - - for (i = 0; i < SGE_FREELQ_N; i++) { - struct freelQ *q = &sge->freelQ[i]; - - q->genbit = 1; - q->size = p->freelQ_size[i]; - q->dma_offset = sge->rx_pkt_pad ? 0 : NET_IP_ALIGN; - size = sizeof(struct freelQ_e) * q->size; - q->entries = pci_alloc_consistent(pdev, size, &q->dma_addr); - if (!q->entries) - goto err_no_mem; - - size = sizeof(struct freelQ_ce) * q->size; - q->centries = kzalloc(size, GFP_KERNEL); - if (!q->centries) - goto err_no_mem; - } - - /* - * Calculate the buffer sizes for the two free lists. FL0 accommodates - * regular sized Ethernet frames, FL1 is sized not to exceed 16K, - * including all the sk_buff overhead. - * - * Note: For T2 FL0 and FL1 are reversed. - */ - sge->freelQ[!sge->jumbo_fl].rx_buffer_size = SGE_RX_SM_BUF_SIZE + - sizeof(struct cpl_rx_data) + - sge->freelQ[!sge->jumbo_fl].dma_offset; - - size = (16 * 1024) - - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); - - sge->freelQ[sge->jumbo_fl].rx_buffer_size = size; - - /* - * Setup which skb recycle Q should be used when recycling buffers from - * each free list. - */ - sge->freelQ[!sge->jumbo_fl].recycleq_idx = 0; - sge->freelQ[sge->jumbo_fl].recycleq_idx = 1; - - sge->respQ.genbit = 1; - sge->respQ.size = SGE_RESPQ_E_N; - sge->respQ.credits = 0; - size = sizeof(struct respQ_e) * sge->respQ.size; - sge->respQ.entries = - pci_alloc_consistent(pdev, size, &sge->respQ.dma_addr); - if (!sge->respQ.entries) - goto err_no_mem; - return 0; - -err_no_mem: - free_rx_resources(sge); - return -ENOMEM; -} - -/* - * Reclaims n TX descriptors and frees the buffers associated with them. - */ -static void free_cmdQ_buffers(struct sge *sge, struct cmdQ *q, unsigned int n) -{ - struct cmdQ_ce *ce; - struct pci_dev *pdev = sge->adapter->pdev; - unsigned int cidx = q->cidx; - - q->in_use -= n; - ce = &q->centries[cidx]; - while (n--) { - if (likely(dma_unmap_len(ce, dma_len))) { - pci_unmap_single(pdev, dma_unmap_addr(ce, dma_addr), - dma_unmap_len(ce, dma_len), - PCI_DMA_TODEVICE); - if (q->sop) - q->sop = 0; - } - if (ce->skb) { - dev_kfree_skb_any(ce->skb); - q->sop = 1; - } - ce++; - if (++cidx == q->size) { - cidx = 0; - ce = q->centries; - } - } - q->cidx = cidx; -} - -/* - * Free TX resources. - * - * Assumes that SGE is stopped and all interrupts are disabled. - */ -static void free_tx_resources(struct sge *sge) -{ - struct pci_dev *pdev = sge->adapter->pdev; - unsigned int size, i; - - for (i = 0; i < SGE_CMDQ_N; i++) { - struct cmdQ *q = &sge->cmdQ[i]; - - if (q->centries) { - if (q->in_use) - free_cmdQ_buffers(sge, q, q->in_use); - kfree(q->centries); - } - if (q->entries) { - size = sizeof(struct cmdQ_e) * q->size; - pci_free_consistent(pdev, size, q->entries, - q->dma_addr); - } - } -} - -/* - * Allocates basic TX resources, consisting of memory mapped command Qs. - */ -static int alloc_tx_resources(struct sge *sge, struct sge_params *p) -{ - struct pci_dev *pdev = sge->adapter->pdev; - unsigned int size, i; - - for (i = 0; i < SGE_CMDQ_N; i++) { - struct cmdQ *q = &sge->cmdQ[i]; - - q->genbit = 1; - q->sop = 1; - q->size = p->cmdQ_size[i]; - q->in_use = 0; - q->status = 0; - q->processed = q->cleaned = 0; - q->stop_thres = 0; - spin_lock_init(&q->lock); - size = sizeof(struct cmdQ_e) * q->size; - q->entries = pci_alloc_consistent(pdev, size, &q->dma_addr); - if (!q->entries) - goto err_no_mem; - - size = sizeof(struct cmdQ_ce) * q->size; - q->centries = kzalloc(size, GFP_KERNEL); - if (!q->centries) - goto err_no_mem; - } - - /* - * CommandQ 0 handles Ethernet and TOE packets, while queue 1 is TOE - * only. For queue 0 set the stop threshold so we can handle one more - * packet from each port, plus reserve an additional 24 entries for - * Ethernet packets only. Queue 1 never suspends nor do we reserve - * space for Ethernet packets. - */ - sge->cmdQ[0].stop_thres = sge->adapter->params.nports * - (MAX_SKB_FRAGS + 1); - return 0; - -err_no_mem: - free_tx_resources(sge); - return -ENOMEM; -} - -static inline void setup_ring_params(struct adapter *adapter, u64 addr, - u32 size, int base_reg_lo, - int base_reg_hi, int size_reg) -{ - writel((u32)addr, adapter->regs + base_reg_lo); - writel(addr >> 32, adapter->regs + base_reg_hi); - writel(size, adapter->regs + size_reg); -} - -/* - * Enable/disable VLAN acceleration. - */ -void t1_vlan_mode(struct adapter *adapter, u32 features) -{ - struct sge *sge = adapter->sge; - - if (features & NETIF_F_HW_VLAN_RX) - sge->sge_control |= F_VLAN_XTRACT; - else - sge->sge_control &= ~F_VLAN_XTRACT; - if (adapter->open_device_map) { - writel(sge->sge_control, adapter->regs + A_SG_CONTROL); - readl(adapter->regs + A_SG_CONTROL); /* flush */ - } -} - -/* - * Programs the various SGE registers. However, the engine is not yet enabled, - * but sge->sge_control is setup and ready to go. - */ -static void configure_sge(struct sge *sge, struct sge_params *p) -{ - struct adapter *ap = sge->adapter; - - writel(0, ap->regs + A_SG_CONTROL); - setup_ring_params(ap, sge->cmdQ[0].dma_addr, sge->cmdQ[0].size, - A_SG_CMD0BASELWR, A_SG_CMD0BASEUPR, A_SG_CMD0SIZE); - setup_ring_params(ap, sge->cmdQ[1].dma_addr, sge->cmdQ[1].size, - A_SG_CMD1BASELWR, A_SG_CMD1BASEUPR, A_SG_CMD1SIZE); - setup_ring_params(ap, sge->freelQ[0].dma_addr, - sge->freelQ[0].size, A_SG_FL0BASELWR, - A_SG_FL0BASEUPR, A_SG_FL0SIZE); - setup_ring_params(ap, sge->freelQ[1].dma_addr, - sge->freelQ[1].size, A_SG_FL1BASELWR, - A_SG_FL1BASEUPR, A_SG_FL1SIZE); - - /* The threshold comparison uses <. */ - writel(SGE_RX_SM_BUF_SIZE + 1, ap->regs + A_SG_FLTHRESHOLD); - - setup_ring_params(ap, sge->respQ.dma_addr, sge->respQ.size, - A_SG_RSPBASELWR, A_SG_RSPBASEUPR, A_SG_RSPSIZE); - writel((u32)sge->respQ.size - 1, ap->regs + A_SG_RSPQUEUECREDIT); - - sge->sge_control = F_CMDQ0_ENABLE | F_CMDQ1_ENABLE | F_FL0_ENABLE | - F_FL1_ENABLE | F_CPL_ENABLE | F_RESPONSE_QUEUE_ENABLE | - V_CMDQ_PRIORITY(2) | F_DISABLE_CMDQ1_GTS | F_ISCSI_COALESCE | - V_RX_PKT_OFFSET(sge->rx_pkt_pad); - -#if defined(__BIG_ENDIAN_BITFIELD) - sge->sge_control |= F_ENABLE_BIG_ENDIAN; -#endif - - /* Initialize no-resource timer */ - sge->intrtimer_nres = SGE_INTRTIMER_NRES * core_ticks_per_usec(ap); - - t1_sge_set_coalesce_params(sge, p); -} - -/* - * Return the payload capacity of the jumbo free-list buffers. - */ -static inline unsigned int jumbo_payload_capacity(const struct sge *sge) -{ - return sge->freelQ[sge->jumbo_fl].rx_buffer_size - - sge->freelQ[sge->jumbo_fl].dma_offset - - sizeof(struct cpl_rx_data); -} - -/* - * Frees all SGE related resources and the sge structure itself - */ -void t1_sge_destroy(struct sge *sge) -{ - int i; - - for_each_port(sge->adapter, i) - free_percpu(sge->port_stats[i]); - - kfree(sge->tx_sched); - free_tx_resources(sge); - free_rx_resources(sge); - kfree(sge); -} - -/* - * Allocates new RX buffers on the freelist Q (and tracks them on the freelist - * context Q) until the Q is full or alloc_skb fails. - * - * It is possible that the generation bits already match, indicating that the - * buffer is already valid and nothing needs to be done. This happens when we - * copied a received buffer into a new sk_buff during the interrupt processing. - * - * If the SGE doesn't automatically align packets properly (!sge->rx_pkt_pad), - * we specify a RX_OFFSET in order to make sure that the IP header is 4B - * aligned. - */ -static void refill_free_list(struct sge *sge, struct freelQ *q) -{ - struct pci_dev *pdev = sge->adapter->pdev; - struct freelQ_ce *ce = &q->centries[q->pidx]; - struct freelQ_e *e = &q->entries[q->pidx]; - unsigned int dma_len = q->rx_buffer_size - q->dma_offset; - - while (q->credits < q->size) { - struct sk_buff *skb; - dma_addr_t mapping; - - skb = alloc_skb(q->rx_buffer_size, GFP_ATOMIC); - if (!skb) - break; - - skb_reserve(skb, q->dma_offset); - mapping = pci_map_single(pdev, skb->data, dma_len, - PCI_DMA_FROMDEVICE); - skb_reserve(skb, sge->rx_pkt_pad); - - ce->skb = skb; - dma_unmap_addr_set(ce, dma_addr, mapping); - dma_unmap_len_set(ce, dma_len, dma_len); - e->addr_lo = (u32)mapping; - e->addr_hi = (u64)mapping >> 32; - e->len_gen = V_CMD_LEN(dma_len) | V_CMD_GEN1(q->genbit); - wmb(); - e->gen2 = V_CMD_GEN2(q->genbit); - - e++; - ce++; - if (++q->pidx == q->size) { - q->pidx = 0; - q->genbit ^= 1; - ce = q->centries; - e = q->entries; - } - q->credits++; - } -} - -/* - * Calls refill_free_list for both free lists. If we cannot fill at least 1/4 - * of both rings, we go into 'few interrupt mode' in order to give the system - * time to free up resources. - */ -static void freelQs_empty(struct sge *sge) -{ - struct adapter *adapter = sge->adapter; - u32 irq_reg = readl(adapter->regs + A_SG_INT_ENABLE); - u32 irqholdoff_reg; - - refill_free_list(sge, &sge->freelQ[0]); - refill_free_list(sge, &sge->freelQ[1]); - - if (sge->freelQ[0].credits > (sge->freelQ[0].size >> 2) && - sge->freelQ[1].credits > (sge->freelQ[1].size >> 2)) { - irq_reg |= F_FL_EXHAUSTED; - irqholdoff_reg = sge->fixed_intrtimer; - } else { - /* Clear the F_FL_EXHAUSTED interrupts for now */ - irq_reg &= ~F_FL_EXHAUSTED; - irqholdoff_reg = sge->intrtimer_nres; - } - writel(irqholdoff_reg, adapter->regs + A_SG_INTRTIMER); - writel(irq_reg, adapter->regs + A_SG_INT_ENABLE); - - /* We reenable the Qs to force a freelist GTS interrupt later */ - doorbell_pio(adapter, F_FL0_ENABLE | F_FL1_ENABLE); -} - -#define SGE_PL_INTR_MASK (F_PL_INTR_SGE_ERR | F_PL_INTR_SGE_DATA) -#define SGE_INT_FATAL (F_RESPQ_OVERFLOW | F_PACKET_TOO_BIG | F_PACKET_MISMATCH) -#define SGE_INT_ENABLE (F_RESPQ_EXHAUSTED | F_RESPQ_OVERFLOW | \ - F_FL_EXHAUSTED | F_PACKET_TOO_BIG | F_PACKET_MISMATCH) - -/* - * Disable SGE Interrupts - */ -void t1_sge_intr_disable(struct sge *sge) -{ - u32 val = readl(sge->adapter->regs + A_PL_ENABLE); - - writel(val & ~SGE_PL_INTR_MASK, sge->adapter->regs + A_PL_ENABLE); - writel(0, sge->adapter->regs + A_SG_INT_ENABLE); -} - -/* - * Enable SGE interrupts. - */ -void t1_sge_intr_enable(struct sge *sge) -{ - u32 en = SGE_INT_ENABLE; - u32 val = readl(sge->adapter->regs + A_PL_ENABLE); - - if (sge->adapter->port[0].dev->hw_features & NETIF_F_TSO) - en &= ~F_PACKET_TOO_BIG; - writel(en, sge->adapter->regs + A_SG_INT_ENABLE); - writel(val | SGE_PL_INTR_MASK, sge->adapter->regs + A_PL_ENABLE); -} - -/* - * Clear SGE interrupts. - */ -void t1_sge_intr_clear(struct sge *sge) -{ - writel(SGE_PL_INTR_MASK, sge->adapter->regs + A_PL_CAUSE); - writel(0xffffffff, sge->adapter->regs + A_SG_INT_CAUSE); -} - -/* - * SGE 'Error' interrupt handler - */ -int t1_sge_intr_error_handler(struct sge *sge) -{ - struct adapter *adapter = sge->adapter; - u32 cause = readl(adapter->regs + A_SG_INT_CAUSE); - - if (adapter->port[0].dev->hw_features & NETIF_F_TSO) - cause &= ~F_PACKET_TOO_BIG; - if (cause & F_RESPQ_EXHAUSTED) - sge->stats.respQ_empty++; - if (cause & F_RESPQ_OVERFLOW) { - sge->stats.respQ_overflow++; - pr_alert("%s: SGE response queue overflow\n", - adapter->name); - } - if (cause & F_FL_EXHAUSTED) { - sge->stats.freelistQ_empty++; - freelQs_empty(sge); - } - if (cause & F_PACKET_TOO_BIG) { - sge->stats.pkt_too_big++; - pr_alert("%s: SGE max packet size exceeded\n", - adapter->name); - } - if (cause & F_PACKET_MISMATCH) { - sge->stats.pkt_mismatch++; - pr_alert("%s: SGE packet mismatch\n", adapter->name); - } - if (cause & SGE_INT_FATAL) - t1_fatal_err(adapter); - - writel(cause, adapter->regs + A_SG_INT_CAUSE); - return 0; -} - -const struct sge_intr_counts *t1_sge_get_intr_counts(const struct sge *sge) -{ - return &sge->stats; -} - -void t1_sge_get_port_stats(const struct sge *sge, int port, - struct sge_port_stats *ss) -{ - int cpu; - - memset(ss, 0, sizeof(*ss)); - for_each_possible_cpu(cpu) { - struct sge_port_stats *st = per_cpu_ptr(sge->port_stats[port], cpu); - - ss->rx_cso_good += st->rx_cso_good; - ss->tx_cso += st->tx_cso; - ss->tx_tso += st->tx_tso; - ss->tx_need_hdrroom += st->tx_need_hdrroom; - ss->vlan_xtract += st->vlan_xtract; - ss->vlan_insert += st->vlan_insert; - } -} - -/** - * recycle_fl_buf - recycle a free list buffer - * @fl: the free list - * @idx: index of buffer to recycle - * - * Recycles the specified buffer on the given free list by adding it at - * the next available slot on the list. - */ -static void recycle_fl_buf(struct freelQ *fl, int idx) -{ - struct freelQ_e *from = &fl->entries[idx]; - struct freelQ_e *to = &fl->entries[fl->pidx]; - - fl->centries[fl->pidx] = fl->centries[idx]; - to->addr_lo = from->addr_lo; - to->addr_hi = from->addr_hi; - to->len_gen = G_CMD_LEN(from->len_gen) | V_CMD_GEN1(fl->genbit); - wmb(); - to->gen2 = V_CMD_GEN2(fl->genbit); - fl->credits++; - - if (++fl->pidx == fl->size) { - fl->pidx = 0; - fl->genbit ^= 1; - } -} - -static int copybreak __read_mostly = 256; -module_param(copybreak, int, 0); -MODULE_PARM_DESC(copybreak, "Receive copy threshold"); - -/** - * get_packet - return the next ingress packet buffer - * @pdev: the PCI device that received the packet - * @fl: the SGE free list holding the packet - * @len: the actual packet length, excluding any SGE padding - * - * Get the next packet from a free list and complete setup of the - * sk_buff. If the packet is small we make a copy and recycle the - * original buffer, otherwise we use the original buffer itself. If a - * positive drop threshold is supplied packets are dropped and their - * buffers recycled if (a) the number of remaining buffers is under the - * threshold and the packet is too big to copy, or (b) the packet should - * be copied but there is no memory for the copy. - */ -static inline struct sk_buff *get_packet(struct pci_dev *pdev, - struct freelQ *fl, unsigned int len) -{ - struct sk_buff *skb; - const struct freelQ_ce *ce = &fl->centries[fl->cidx]; - - if (len < copybreak) { - skb = alloc_skb(len + 2, GFP_ATOMIC); - if (!skb) - goto use_orig_buf; - - skb_reserve(skb, 2); /* align IP header */ - skb_put(skb, len); - pci_dma_sync_single_for_cpu(pdev, - dma_unmap_addr(ce, dma_addr), - dma_unmap_len(ce, dma_len), - PCI_DMA_FROMDEVICE); - skb_copy_from_linear_data(ce->skb, skb->data, len); - pci_dma_sync_single_for_device(pdev, - dma_unmap_addr(ce, dma_addr), - dma_unmap_len(ce, dma_len), - PCI_DMA_FROMDEVICE); - recycle_fl_buf(fl, fl->cidx); - return skb; - } - -use_orig_buf: - if (fl->credits < 2) { - recycle_fl_buf(fl, fl->cidx); - return NULL; - } - - pci_unmap_single(pdev, dma_unmap_addr(ce, dma_addr), - dma_unmap_len(ce, dma_len), PCI_DMA_FROMDEVICE); - skb = ce->skb; - prefetch(skb->data); - - skb_put(skb, len); - return skb; -} - -/** - * unexpected_offload - handle an unexpected offload packet - * @adapter: the adapter - * @fl: the free list that received the packet - * - * Called when we receive an unexpected offload packet (e.g., the TOE - * function is disabled or the card is a NIC). Prints a message and - * recycles the buffer. - */ -static void unexpected_offload(struct adapter *adapter, struct freelQ *fl) -{ - struct freelQ_ce *ce = &fl->centries[fl->cidx]; - struct sk_buff *skb = ce->skb; - - pci_dma_sync_single_for_cpu(adapter->pdev, dma_unmap_addr(ce, dma_addr), - dma_unmap_len(ce, dma_len), PCI_DMA_FROMDEVICE); - pr_err("%s: unexpected offload packet, cmd %u\n", - adapter->name, *skb->data); - recycle_fl_buf(fl, fl->cidx); -} - -/* - * T1/T2 SGE limits the maximum DMA size per TX descriptor to - * SGE_TX_DESC_MAX_PLEN (16KB). If the PAGE_SIZE is larger than 16KB, the - * stack might send more than SGE_TX_DESC_MAX_PLEN in a contiguous manner. - * Note that the *_large_page_tx_descs stuff will be optimized out when - * PAGE_SIZE <= SGE_TX_DESC_MAX_PLEN. - * - * compute_large_page_descs() computes how many additional descriptors are - * required to break down the stack's request. - */ -static inline unsigned int compute_large_page_tx_descs(struct sk_buff *skb) -{ - unsigned int count = 0; - - if (PAGE_SIZE > SGE_TX_DESC_MAX_PLEN) { - unsigned int nfrags = skb_shinfo(skb)->nr_frags; - unsigned int i, len = skb_headlen(skb); - while (len > SGE_TX_DESC_MAX_PLEN) { - count++; - len -= SGE_TX_DESC_MAX_PLEN; - } - for (i = 0; nfrags--; i++) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - len = frag->size; - while (len > SGE_TX_DESC_MAX_PLEN) { - count++; - len -= SGE_TX_DESC_MAX_PLEN; - } - } - } - return count; -} - -/* - * Write a cmdQ entry. - * - * Since this function writes the 'flags' field, it must not be used to - * write the first cmdQ entry. - */ -static inline void write_tx_desc(struct cmdQ_e *e, dma_addr_t mapping, - unsigned int len, unsigned int gen, - unsigned int eop) -{ - BUG_ON(len > SGE_TX_DESC_MAX_PLEN); - - e->addr_lo = (u32)mapping; - e->addr_hi = (u64)mapping >> 32; - e->len_gen = V_CMD_LEN(len) | V_CMD_GEN1(gen); - e->flags = F_CMD_DATAVALID | V_CMD_EOP(eop) | V_CMD_GEN2(gen); -} - -/* - * See comment for previous function. - * - * write_tx_descs_large_page() writes additional SGE tx descriptors if - * *desc_len exceeds HW's capability. - */ -static inline unsigned int write_large_page_tx_descs(unsigned int pidx, - struct cmdQ_e **e, - struct cmdQ_ce **ce, - unsigned int *gen, - dma_addr_t *desc_mapping, - unsigned int *desc_len, - unsigned int nfrags, - struct cmdQ *q) -{ - if (PAGE_SIZE > SGE_TX_DESC_MAX_PLEN) { - struct cmdQ_e *e1 = *e; - struct cmdQ_ce *ce1 = *ce; - - while (*desc_len > SGE_TX_DESC_MAX_PLEN) { - *desc_len -= SGE_TX_DESC_MAX_PLEN; - write_tx_desc(e1, *desc_mapping, SGE_TX_DESC_MAX_PLEN, - *gen, nfrags == 0 && *desc_len == 0); - ce1->skb = NULL; - dma_unmap_len_set(ce1, dma_len, 0); - *desc_mapping += SGE_TX_DESC_MAX_PLEN; - if (*desc_len) { - ce1++; - e1++; - if (++pidx == q->size) { - pidx = 0; - *gen ^= 1; - ce1 = q->centries; - e1 = q->entries; - } - } - } - *e = e1; - *ce = ce1; - } - return pidx; -} - -/* - * Write the command descriptors to transmit the given skb starting at - * descriptor pidx with the given generation. - */ -static inline void write_tx_descs(struct adapter *adapter, struct sk_buff *skb, - unsigned int pidx, unsigned int gen, - struct cmdQ *q) -{ - dma_addr_t mapping, desc_mapping; - struct cmdQ_e *e, *e1; - struct cmdQ_ce *ce; - unsigned int i, flags, first_desc_len, desc_len, - nfrags = skb_shinfo(skb)->nr_frags; - - e = e1 = &q->entries[pidx]; - ce = &q->centries[pidx]; - - mapping = pci_map_single(adapter->pdev, skb->data, - skb_headlen(skb), PCI_DMA_TODEVICE); - - desc_mapping = mapping; - desc_len = skb_headlen(skb); - - flags = F_CMD_DATAVALID | F_CMD_SOP | - V_CMD_EOP(nfrags == 0 && desc_len <= SGE_TX_DESC_MAX_PLEN) | - V_CMD_GEN2(gen); - first_desc_len = (desc_len <= SGE_TX_DESC_MAX_PLEN) ? - desc_len : SGE_TX_DESC_MAX_PLEN; - e->addr_lo = (u32)desc_mapping; - e->addr_hi = (u64)desc_mapping >> 32; - e->len_gen = V_CMD_LEN(first_desc_len) | V_CMD_GEN1(gen); - ce->skb = NULL; - dma_unmap_len_set(ce, dma_len, 0); - - if (PAGE_SIZE > SGE_TX_DESC_MAX_PLEN && - desc_len > SGE_TX_DESC_MAX_PLEN) { - desc_mapping += first_desc_len; - desc_len -= first_desc_len; - e1++; - ce++; - if (++pidx == q->size) { - pidx = 0; - gen ^= 1; - e1 = q->entries; - ce = q->centries; - } - pidx = write_large_page_tx_descs(pidx, &e1, &ce, &gen, - &desc_mapping, &desc_len, - nfrags, q); - - if (likely(desc_len)) - write_tx_desc(e1, desc_mapping, desc_len, gen, - nfrags == 0); - } - - ce->skb = NULL; - dma_unmap_addr_set(ce, dma_addr, mapping); - dma_unmap_len_set(ce, dma_len, skb_headlen(skb)); - - for (i = 0; nfrags--; i++) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - e1++; - ce++; - if (++pidx == q->size) { - pidx = 0; - gen ^= 1; - e1 = q->entries; - ce = q->centries; - } - - mapping = pci_map_page(adapter->pdev, frag->page, - frag->page_offset, frag->size, - PCI_DMA_TODEVICE); - desc_mapping = mapping; - desc_len = frag->size; - - pidx = write_large_page_tx_descs(pidx, &e1, &ce, &gen, - &desc_mapping, &desc_len, - nfrags, q); - if (likely(desc_len)) - write_tx_desc(e1, desc_mapping, desc_len, gen, - nfrags == 0); - ce->skb = NULL; - dma_unmap_addr_set(ce, dma_addr, mapping); - dma_unmap_len_set(ce, dma_len, frag->size); - } - ce->skb = skb; - wmb(); - e->flags = flags; -} - -/* - * Clean up completed Tx buffers. - */ -static inline void reclaim_completed_tx(struct sge *sge, struct cmdQ *q) -{ - unsigned int reclaim = q->processed - q->cleaned; - - if (reclaim) { - pr_debug("reclaim_completed_tx processed:%d cleaned:%d\n", - q->processed, q->cleaned); - free_cmdQ_buffers(sge, q, reclaim); - q->cleaned += reclaim; - } -} - -/* - * Called from tasklet. Checks the scheduler for any - * pending skbs that can be sent. - */ -static void restart_sched(unsigned long arg) -{ - struct sge *sge = (struct sge *) arg; - struct adapter *adapter = sge->adapter; - struct cmdQ *q = &sge->cmdQ[0]; - struct sk_buff *skb; - unsigned int credits, queued_skb = 0; - - spin_lock(&q->lock); - reclaim_completed_tx(sge, q); - - credits = q->size - q->in_use; - pr_debug("restart_sched credits=%d\n", credits); - while ((skb = sched_skb(sge, NULL, credits)) != NULL) { - unsigned int genbit, pidx, count; - count = 1 + skb_shinfo(skb)->nr_frags; - count += compute_large_page_tx_descs(skb); - q->in_use += count; - genbit = q->genbit; - pidx = q->pidx; - q->pidx += count; - if (q->pidx >= q->size) { - q->pidx -= q->size; - q->genbit ^= 1; - } - write_tx_descs(adapter, skb, pidx, genbit, q); - credits = q->size - q->in_use; - queued_skb = 1; - } - - if (queued_skb) { - clear_bit(CMDQ_STAT_LAST_PKT_DB, &q->status); - if (test_and_set_bit(CMDQ_STAT_RUNNING, &q->status) == 0) { - set_bit(CMDQ_STAT_LAST_PKT_DB, &q->status); - writel(F_CMDQ0_ENABLE, adapter->regs + A_SG_DOORBELL); - } - } - spin_unlock(&q->lock); -} - -/** - * sge_rx - process an ingress ethernet packet - * @sge: the sge structure - * @fl: the free list that contains the packet buffer - * @len: the packet length - * - * Process an ingress ethernet pakcet and deliver it to the stack. - */ -static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len) -{ - struct sk_buff *skb; - const struct cpl_rx_pkt *p; - struct adapter *adapter = sge->adapter; - struct sge_port_stats *st; - struct net_device *dev; - - skb = get_packet(adapter->pdev, fl, len - sge->rx_pkt_pad); - if (unlikely(!skb)) { - sge->stats.rx_drops++; - return; - } - - p = (const struct cpl_rx_pkt *) skb->data; - if (p->iff >= adapter->params.nports) { - kfree_skb(skb); - return; - } - __skb_pull(skb, sizeof(*p)); - - st = this_cpu_ptr(sge->port_stats[p->iff]); - dev = adapter->port[p->iff].dev; - - skb->protocol = eth_type_trans(skb, dev); - if ((dev->features & NETIF_F_RXCSUM) && p->csum == 0xffff && - skb->protocol == htons(ETH_P_IP) && - (skb->data[9] == IPPROTO_TCP || skb->data[9] == IPPROTO_UDP)) { - ++st->rx_cso_good; - skb->ip_summed = CHECKSUM_UNNECESSARY; - } else - skb_checksum_none_assert(skb); - - if (p->vlan_valid) { - st->vlan_xtract++; - __vlan_hwaccel_put_tag(skb, ntohs(p->vlan)); - } - netif_receive_skb(skb); -} - -/* - * Returns true if a command queue has enough available descriptors that - * we can resume Tx operation after temporarily disabling its packet queue. - */ -static inline int enough_free_Tx_descs(const struct cmdQ *q) -{ - unsigned int r = q->processed - q->cleaned; - - return q->in_use - r < (q->size >> 1); -} - -/* - * Called when sufficient space has become available in the SGE command queues - * after the Tx packet schedulers have been suspended to restart the Tx path. - */ -static void restart_tx_queues(struct sge *sge) -{ - struct adapter *adap = sge->adapter; - int i; - - if (!enough_free_Tx_descs(&sge->cmdQ[0])) - return; - - for_each_port(adap, i) { - struct net_device *nd = adap->port[i].dev; - - if (test_and_clear_bit(nd->if_port, &sge->stopped_tx_queues) && - netif_running(nd)) { - sge->stats.cmdQ_restarted[2]++; - netif_wake_queue(nd); - } - } -} - -/* - * update_tx_info is called from the interrupt handler/NAPI to return cmdQ0 - * information. - */ -static unsigned int update_tx_info(struct adapter *adapter, - unsigned int flags, - unsigned int pr0) -{ - struct sge *sge = adapter->sge; - struct cmdQ *cmdq = &sge->cmdQ[0]; - - cmdq->processed += pr0; - if (flags & (F_FL0_ENABLE | F_FL1_ENABLE)) { - freelQs_empty(sge); - flags &= ~(F_FL0_ENABLE | F_FL1_ENABLE); - } - if (flags & F_CMDQ0_ENABLE) { - clear_bit(CMDQ_STAT_RUNNING, &cmdq->status); - - if (cmdq->cleaned + cmdq->in_use != cmdq->processed && - !test_and_set_bit(CMDQ_STAT_LAST_PKT_DB, &cmdq->status)) { - set_bit(CMDQ_STAT_RUNNING, &cmdq->status); - writel(F_CMDQ0_ENABLE, adapter->regs + A_SG_DOORBELL); - } - if (sge->tx_sched) - tasklet_hi_schedule(&sge->tx_sched->sched_tsk); - - flags &= ~F_CMDQ0_ENABLE; - } - - if (unlikely(sge->stopped_tx_queues != 0)) - restart_tx_queues(sge); - - return flags; -} - -/* - * Process SGE responses, up to the supplied budget. Returns the number of - * responses processed. A negative budget is effectively unlimited. - */ -static int process_responses(struct adapter *adapter, int budget) -{ - struct sge *sge = adapter->sge; - struct respQ *q = &sge->respQ; - struct respQ_e *e = &q->entries[q->cidx]; - int done = 0; - unsigned int flags = 0; - unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0}; - - while (done < budget && e->GenerationBit == q->genbit) { - flags |= e->Qsleeping; - - cmdq_processed[0] += e->Cmdq0CreditReturn; - cmdq_processed[1] += e->Cmdq1CreditReturn; - - /* We batch updates to the TX side to avoid cacheline - * ping-pong of TX state information on MP where the sender - * might run on a different CPU than this function... - */ - if (unlikely((flags & F_CMDQ0_ENABLE) || cmdq_processed[0] > 64)) { - flags = update_tx_info(adapter, flags, cmdq_processed[0]); - cmdq_processed[0] = 0; - } - - if (unlikely(cmdq_processed[1] > 16)) { - sge->cmdQ[1].processed += cmdq_processed[1]; - cmdq_processed[1] = 0; - } - - if (likely(e->DataValid)) { - struct freelQ *fl = &sge->freelQ[e->FreelistQid]; - - BUG_ON(!e->Sop || !e->Eop); - if (unlikely(e->Offload)) - unexpected_offload(adapter, fl); - else - sge_rx(sge, fl, e->BufferLength); - - ++done; - - /* - * Note: this depends on each packet consuming a - * single free-list buffer; cf. the BUG above. - */ - if (++fl->cidx == fl->size) - fl->cidx = 0; - prefetch(fl->centries[fl->cidx].skb); - - if (unlikely(--fl->credits < - fl->size - SGE_FREEL_REFILL_THRESH)) - refill_free_list(sge, fl); - } else - sge->stats.pure_rsps++; - - e++; - if (unlikely(++q->cidx == q->size)) { - q->cidx = 0; - q->genbit ^= 1; - e = q->entries; - } - prefetch(e); - - if (++q->credits > SGE_RESPQ_REPLENISH_THRES) { - writel(q->credits, adapter->regs + A_SG_RSPQUEUECREDIT); - q->credits = 0; - } - } - - flags = update_tx_info(adapter, flags, cmdq_processed[0]); - sge->cmdQ[1].processed += cmdq_processed[1]; - - return done; -} - -static inline int responses_pending(const struct adapter *adapter) -{ - const struct respQ *Q = &adapter->sge->respQ; - const struct respQ_e *e = &Q->entries[Q->cidx]; - - return e->GenerationBit == Q->genbit; -} - -/* - * A simpler version of process_responses() that handles only pure (i.e., - * non data-carrying) responses. Such respones are too light-weight to justify - * calling a softirq when using NAPI, so we handle them specially in hard - * interrupt context. The function is called with a pointer to a response, - * which the caller must ensure is a valid pure response. Returns 1 if it - * encounters a valid data-carrying response, 0 otherwise. - */ -static int process_pure_responses(struct adapter *adapter) -{ - struct sge *sge = adapter->sge; - struct respQ *q = &sge->respQ; - struct respQ_e *e = &q->entries[q->cidx]; - const struct freelQ *fl = &sge->freelQ[e->FreelistQid]; - unsigned int flags = 0; - unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0}; - - prefetch(fl->centries[fl->cidx].skb); - if (e->DataValid) - return 1; - - do { - flags |= e->Qsleeping; - - cmdq_processed[0] += e->Cmdq0CreditReturn; - cmdq_processed[1] += e->Cmdq1CreditReturn; - - e++; - if (unlikely(++q->cidx == q->size)) { - q->cidx = 0; - q->genbit ^= 1; - e = q->entries; - } - prefetch(e); - - if (++q->credits > SGE_RESPQ_REPLENISH_THRES) { - writel(q->credits, adapter->regs + A_SG_RSPQUEUECREDIT); - q->credits = 0; - } - sge->stats.pure_rsps++; - } while (e->GenerationBit == q->genbit && !e->DataValid); - - flags = update_tx_info(adapter, flags, cmdq_processed[0]); - sge->cmdQ[1].processed += cmdq_processed[1]; - - return e->GenerationBit == q->genbit; -} - -/* - * Handler for new data events when using NAPI. This does not need any locking - * or protection from interrupts as data interrupts are off at this point and - * other adapter interrupts do not interfere. - */ -int t1_poll(struct napi_struct *napi, int budget) -{ - struct adapter *adapter = container_of(napi, struct adapter, napi); - int work_done = process_responses(adapter, budget); - - if (likely(work_done < budget)) { - napi_complete(napi); - writel(adapter->sge->respQ.cidx, - adapter->regs + A_SG_SLEEPING); - } - return work_done; -} - -irqreturn_t t1_interrupt(int irq, void *data) -{ - struct adapter *adapter = data; - struct sge *sge = adapter->sge; - int handled; - - if (likely(responses_pending(adapter))) { - writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE); - - if (napi_schedule_prep(&adapter->napi)) { - if (process_pure_responses(adapter)) - __napi_schedule(&adapter->napi); - else { - /* no data, no NAPI needed */ - writel(sge->respQ.cidx, adapter->regs + A_SG_SLEEPING); - /* undo schedule_prep */ - napi_enable(&adapter->napi); - } - } - return IRQ_HANDLED; - } - - spin_lock(&adapter->async_lock); - handled = t1_slow_intr_handler(adapter); - spin_unlock(&adapter->async_lock); - - if (!handled) - sge->stats.unhandled_irqs++; - - return IRQ_RETVAL(handled != 0); -} - -/* - * Enqueues the sk_buff onto the cmdQ[qid] and has hardware fetch it. - * - * The code figures out how many entries the sk_buff will require in the - * cmdQ and updates the cmdQ data structure with the state once the enqueue - * has complete. Then, it doesn't access the global structure anymore, but - * uses the corresponding fields on the stack. In conjunction with a spinlock - * around that code, we can make the function reentrant without holding the - * lock when we actually enqueue (which might be expensive, especially on - * architectures with IO MMUs). - * - * This runs with softirqs disabled. - */ -static int t1_sge_tx(struct sk_buff *skb, struct adapter *adapter, - unsigned int qid, struct net_device *dev) -{ - struct sge *sge = adapter->sge; - struct cmdQ *q = &sge->cmdQ[qid]; - unsigned int credits, pidx, genbit, count, use_sched_skb = 0; - - if (!spin_trylock(&q->lock)) - return NETDEV_TX_LOCKED; - - reclaim_completed_tx(sge, q); - - pidx = q->pidx; - credits = q->size - q->in_use; - count = 1 + skb_shinfo(skb)->nr_frags; - count += compute_large_page_tx_descs(skb); - - /* Ethernet packet */ - if (unlikely(credits < count)) { - if (!netif_queue_stopped(dev)) { - netif_stop_queue(dev); - set_bit(dev->if_port, &sge->stopped_tx_queues); - sge->stats.cmdQ_full[2]++; - pr_err("%s: Tx ring full while queue awake!\n", - adapter->name); - } - spin_unlock(&q->lock); - return NETDEV_TX_BUSY; - } - - if (unlikely(credits - count < q->stop_thres)) { - netif_stop_queue(dev); - set_bit(dev->if_port, &sge->stopped_tx_queues); - sge->stats.cmdQ_full[2]++; - } - - /* T204 cmdQ0 skbs that are destined for a certain port have to go - * through the scheduler. - */ - if (sge->tx_sched && !qid && skb->dev) { -use_sched: - use_sched_skb = 1; - /* Note that the scheduler might return a different skb than - * the one passed in. - */ - skb = sched_skb(sge, skb, credits); - if (!skb) { - spin_unlock(&q->lock); - return NETDEV_TX_OK; - } - pidx = q->pidx; - count = 1 + skb_shinfo(skb)->nr_frags; - count += compute_large_page_tx_descs(skb); - } - - q->in_use += count; - genbit = q->genbit; - pidx = q->pidx; - q->pidx += count; - if (q->pidx >= q->size) { - q->pidx -= q->size; - q->genbit ^= 1; - } - spin_unlock(&q->lock); - - write_tx_descs(adapter, skb, pidx, genbit, q); - - /* - * We always ring the doorbell for cmdQ1. For cmdQ0, we only ring - * the doorbell if the Q is asleep. There is a natural race, where - * the hardware is going to sleep just after we checked, however, - * then the interrupt handler will detect the outstanding TX packet - * and ring the doorbell for us. - */ - if (qid) - doorbell_pio(adapter, F_CMDQ1_ENABLE); - else { - clear_bit(CMDQ_STAT_LAST_PKT_DB, &q->status); - if (test_and_set_bit(CMDQ_STAT_RUNNING, &q->status) == 0) { - set_bit(CMDQ_STAT_LAST_PKT_DB, &q->status); - writel(F_CMDQ0_ENABLE, adapter->regs + A_SG_DOORBELL); - } - } - - if (use_sched_skb) { - if (spin_trylock(&q->lock)) { - credits = q->size - q->in_use; - skb = NULL; - goto use_sched; - } - } - return NETDEV_TX_OK; -} - -#define MK_ETH_TYPE_MSS(type, mss) (((mss) & 0x3FFF) | ((type) << 14)) - -/* - * eth_hdr_len - return the length of an Ethernet header - * @data: pointer to the start of the Ethernet header - * - * Returns the length of an Ethernet header, including optional VLAN tag. - */ -static inline int eth_hdr_len(const void *data) -{ - const struct ethhdr *e = data; - - return e->h_proto == htons(ETH_P_8021Q) ? VLAN_ETH_HLEN : ETH_HLEN; -} - -/* - * Adds the CPL header to the sk_buff and passes it to t1_sge_tx. - */ -netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct adapter *adapter = dev->ml_priv; - struct sge *sge = adapter->sge; - struct sge_port_stats *st = this_cpu_ptr(sge->port_stats[dev->if_port]); - struct cpl_tx_pkt *cpl; - struct sk_buff *orig_skb = skb; - int ret; - - if (skb->protocol == htons(ETH_P_CPL5)) - goto send; - - /* - * We are using a non-standard hard_header_len. - * Allocate more header room in the rare cases it is not big enough. - */ - if (unlikely(skb_headroom(skb) < dev->hard_header_len - ETH_HLEN)) { - skb = skb_realloc_headroom(skb, sizeof(struct cpl_tx_pkt_lso)); - ++st->tx_need_hdrroom; - dev_kfree_skb_any(orig_skb); - if (!skb) - return NETDEV_TX_OK; - } - - if (skb_shinfo(skb)->gso_size) { - int eth_type; - struct cpl_tx_pkt_lso *hdr; - - ++st->tx_tso; - - eth_type = skb_network_offset(skb) == ETH_HLEN ? - CPL_ETH_II : CPL_ETH_II_VLAN; - - hdr = (struct cpl_tx_pkt_lso *)skb_push(skb, sizeof(*hdr)); - hdr->opcode = CPL_TX_PKT_LSO; - hdr->ip_csum_dis = hdr->l4_csum_dis = 0; - hdr->ip_hdr_words = ip_hdr(skb)->ihl; - hdr->tcp_hdr_words = tcp_hdr(skb)->doff; - hdr->eth_type_mss = htons(MK_ETH_TYPE_MSS(eth_type, - skb_shinfo(skb)->gso_size)); - hdr->len = htonl(skb->len - sizeof(*hdr)); - cpl = (struct cpl_tx_pkt *)hdr; - } else { - /* - * Packets shorter than ETH_HLEN can break the MAC, drop them - * early. Also, we may get oversized packets because some - * parts of the kernel don't handle our unusual hard_header_len - * right, drop those too. - */ - if (unlikely(skb->len < ETH_HLEN || - skb->len > dev->mtu + eth_hdr_len(skb->data))) { - pr_debug("%s: packet size %d hdr %d mtu%d\n", dev->name, - skb->len, eth_hdr_len(skb->data), dev->mtu); - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; - } - - if (skb->ip_summed == CHECKSUM_PARTIAL && - ip_hdr(skb)->protocol == IPPROTO_UDP) { - if (unlikely(skb_checksum_help(skb))) { - pr_debug("%s: unable to do udp checksum\n", dev->name); - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; - } - } - - /* Hmmm, assuming to catch the gratious arp... and we'll use - * it to flush out stuck espi packets... - */ - if ((unlikely(!adapter->sge->espibug_skb[dev->if_port]))) { - if (skb->protocol == htons(ETH_P_ARP) && - arp_hdr(skb)->ar_op == htons(ARPOP_REQUEST)) { - adapter->sge->espibug_skb[dev->if_port] = skb; - /* We want to re-use this skb later. We - * simply bump the reference count and it - * will not be freed... - */ - skb = skb_get(skb); - } - } - - cpl = (struct cpl_tx_pkt *)__skb_push(skb, sizeof(*cpl)); - cpl->opcode = CPL_TX_PKT; - cpl->ip_csum_dis = 1; /* SW calculates IP csum */ - cpl->l4_csum_dis = skb->ip_summed == CHECKSUM_PARTIAL ? 0 : 1; - /* the length field isn't used so don't bother setting it */ - - st->tx_cso += (skb->ip_summed == CHECKSUM_PARTIAL); - } - cpl->iff = dev->if_port; - - if (vlan_tx_tag_present(skb)) { - cpl->vlan_valid = 1; - cpl->vlan = htons(vlan_tx_tag_get(skb)); - st->vlan_insert++; - } else - cpl->vlan_valid = 0; - -send: - ret = t1_sge_tx(skb, adapter, 0, dev); - - /* If transmit busy, and we reallocated skb's due to headroom limit, - * then silently discard to avoid leak. - */ - if (unlikely(ret != NETDEV_TX_OK && skb != orig_skb)) { - dev_kfree_skb_any(skb); - ret = NETDEV_TX_OK; - } - return ret; -} - -/* - * Callback for the Tx buffer reclaim timer. Runs with softirqs disabled. - */ -static void sge_tx_reclaim_cb(unsigned long data) -{ - int i; - struct sge *sge = (struct sge *)data; - - for (i = 0; i < SGE_CMDQ_N; ++i) { - struct cmdQ *q = &sge->cmdQ[i]; - - if (!spin_trylock(&q->lock)) - continue; - - reclaim_completed_tx(sge, q); - if (i == 0 && q->in_use) { /* flush pending credits */ - writel(F_CMDQ0_ENABLE, sge->adapter->regs + A_SG_DOORBELL); - } - spin_unlock(&q->lock); - } - mod_timer(&sge->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD); -} - -/* - * Propagate changes of the SGE coalescing parameters to the HW. - */ -int t1_sge_set_coalesce_params(struct sge *sge, struct sge_params *p) -{ - sge->fixed_intrtimer = p->rx_coalesce_usecs * - core_ticks_per_usec(sge->adapter); - writel(sge->fixed_intrtimer, sge->adapter->regs + A_SG_INTRTIMER); - return 0; -} - -/* - * Allocates both RX and TX resources and configures the SGE. However, - * the hardware is not enabled yet. - */ -int t1_sge_configure(struct sge *sge, struct sge_params *p) -{ - if (alloc_rx_resources(sge, p)) - return -ENOMEM; - if (alloc_tx_resources(sge, p)) { - free_rx_resources(sge); - return -ENOMEM; - } - configure_sge(sge, p); - - /* - * Now that we have sized the free lists calculate the payload - * capacity of the large buffers. Other parts of the driver use - * this to set the max offload coalescing size so that RX packets - * do not overflow our large buffers. - */ - p->large_buf_capacity = jumbo_payload_capacity(sge); - return 0; -} - -/* - * Disables the DMA engine. - */ -void t1_sge_stop(struct sge *sge) -{ - int i; - writel(0, sge->adapter->regs + A_SG_CONTROL); - readl(sge->adapter->regs + A_SG_CONTROL); /* flush */ - - if (is_T2(sge->adapter)) - del_timer_sync(&sge->espibug_timer); - - del_timer_sync(&sge->tx_reclaim_timer); - if (sge->tx_sched) - tx_sched_stop(sge); - - for (i = 0; i < MAX_NPORTS; i++) - kfree_skb(sge->espibug_skb[i]); -} - -/* - * Enables the DMA engine. - */ -void t1_sge_start(struct sge *sge) -{ - refill_free_list(sge, &sge->freelQ[0]); - refill_free_list(sge, &sge->freelQ[1]); - - writel(sge->sge_control, sge->adapter->regs + A_SG_CONTROL); - doorbell_pio(sge->adapter, F_FL0_ENABLE | F_FL1_ENABLE); - readl(sge->adapter->regs + A_SG_CONTROL); /* flush */ - - mod_timer(&sge->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD); - - if (is_T2(sge->adapter)) - mod_timer(&sge->espibug_timer, jiffies + sge->espibug_timeout); -} - -/* - * Callback for the T2 ESPI 'stuck packet feature' workaorund - */ -static void espibug_workaround_t204(unsigned long data) -{ - struct adapter *adapter = (struct adapter *)data; - struct sge *sge = adapter->sge; - unsigned int nports = adapter->params.nports; - u32 seop[MAX_NPORTS]; - - if (adapter->open_device_map & PORT_MASK) { - int i; - - if (t1_espi_get_mon_t204(adapter, &(seop[0]), 0) < 0) - return; - - for (i = 0; i < nports; i++) { - struct sk_buff *skb = sge->espibug_skb[i]; - - if (!netif_running(adapter->port[i].dev) || - netif_queue_stopped(adapter->port[i].dev) || - !seop[i] || ((seop[i] & 0xfff) != 0) || !skb) - continue; - - if (!skb->cb[0]) { - skb_copy_to_linear_data_offset(skb, - sizeof(struct cpl_tx_pkt), - ch_mac_addr, - ETH_ALEN); - skb_copy_to_linear_data_offset(skb, - skb->len - 10, - ch_mac_addr, - ETH_ALEN); - skb->cb[0] = 0xff; - } - - /* bump the reference count to avoid freeing of - * the skb once the DMA has completed. - */ - skb = skb_get(skb); - t1_sge_tx(skb, adapter, 0, adapter->port[i].dev); - } - } - mod_timer(&sge->espibug_timer, jiffies + sge->espibug_timeout); -} - -static void espibug_workaround(unsigned long data) -{ - struct adapter *adapter = (struct adapter *)data; - struct sge *sge = adapter->sge; - - if (netif_running(adapter->port[0].dev)) { - struct sk_buff *skb = sge->espibug_skb[0]; - u32 seop = t1_espi_get_mon(adapter, 0x930, 0); - - if ((seop & 0xfff0fff) == 0xfff && skb) { - if (!skb->cb[0]) { - skb_copy_to_linear_data_offset(skb, - sizeof(struct cpl_tx_pkt), - ch_mac_addr, - ETH_ALEN); - skb_copy_to_linear_data_offset(skb, - skb->len - 10, - ch_mac_addr, - ETH_ALEN); - skb->cb[0] = 0xff; - } - - /* bump the reference count to avoid freeing of the - * skb once the DMA has completed. - */ - skb = skb_get(skb); - t1_sge_tx(skb, adapter, 0, adapter->port[0].dev); - } - } - mod_timer(&sge->espibug_timer, jiffies + sge->espibug_timeout); -} - -/* - * Creates a t1_sge structure and returns suggested resource parameters. - */ -struct sge * __devinit t1_sge_create(struct adapter *adapter, - struct sge_params *p) -{ - struct sge *sge = kzalloc(sizeof(*sge), GFP_KERNEL); - int i; - - if (!sge) - return NULL; - - sge->adapter = adapter; - sge->netdev = adapter->port[0].dev; - sge->rx_pkt_pad = t1_is_T1B(adapter) ? 0 : 2; - sge->jumbo_fl = t1_is_T1B(adapter) ? 1 : 0; - - for_each_port(adapter, i) { - sge->port_stats[i] = alloc_percpu(struct sge_port_stats); - if (!sge->port_stats[i]) - goto nomem_port; - } - - init_timer(&sge->tx_reclaim_timer); - sge->tx_reclaim_timer.data = (unsigned long)sge; - sge->tx_reclaim_timer.function = sge_tx_reclaim_cb; - - if (is_T2(sge->adapter)) { - init_timer(&sge->espibug_timer); - - if (adapter->params.nports > 1) { - tx_sched_init(sge); - sge->espibug_timer.function = espibug_workaround_t204; - } else - sge->espibug_timer.function = espibug_workaround; - sge->espibug_timer.data = (unsigned long)sge->adapter; - - sge->espibug_timeout = 1; - /* for T204, every 10ms */ - if (adapter->params.nports > 1) - sge->espibug_timeout = HZ/100; - } - - - p->cmdQ_size[0] = SGE_CMDQ0_E_N; - p->cmdQ_size[1] = SGE_CMDQ1_E_N; - p->freelQ_size[!sge->jumbo_fl] = SGE_FREEL_SIZE; - p->freelQ_size[sge->jumbo_fl] = SGE_JUMBO_FREEL_SIZE; - if (sge->tx_sched) { - if (board_info(sge->adapter)->board == CHBT_BOARD_CHT204) - p->rx_coalesce_usecs = 15; - else - p->rx_coalesce_usecs = 50; - } else - p->rx_coalesce_usecs = 50; - - p->coalesce_enable = 0; - p->sample_interval_usecs = 0; - - return sge; -nomem_port: - while (i >= 0) { - free_percpu(sge->port_stats[i]); - --i; - } - kfree(sge); - return NULL; - -} diff --git a/drivers/net/chelsio/sge.h b/drivers/net/chelsio/sge.h deleted file mode 100644 index e03980bcdd65..000000000000 --- a/drivers/net/chelsio/sge.h +++ /dev/null @@ -1,94 +0,0 @@ -/***************************************************************************** - * * - * File: sge.h * - * $Revision: 1.11 $ * - * $Date: 2005/06/21 22:10:55 $ * - * Description: * - * part of the Chelsio 10Gb Ethernet Driver. * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * * - * http://www.chelsio.com * - * * - * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * - * All rights reserved. * - * * - * Maintainers: maintainers@chelsio.com * - * * - * Authors: Dimitrios Michailidis * - * Tina Yang * - * Felix Marti * - * Scott Bardone * - * Kurt Ottaway * - * Frank DiMambro * - * * - * History: * - * * - ****************************************************************************/ - -#ifndef _CXGB_SGE_H_ -#define _CXGB_SGE_H_ - -#include -#include -#include - -struct sge_intr_counts { - unsigned int rx_drops; /* # of packets dropped due to no mem */ - unsigned int pure_rsps; /* # of non-payload responses */ - unsigned int unhandled_irqs; /* # of unhandled interrupts */ - unsigned int respQ_empty; /* # times respQ empty */ - unsigned int respQ_overflow; /* # respQ overflow (fatal) */ - unsigned int freelistQ_empty; /* # times freelist empty */ - unsigned int pkt_too_big; /* packet too large (fatal) */ - unsigned int pkt_mismatch; - unsigned int cmdQ_full[3]; /* not HW IRQ, host cmdQ[] full */ - unsigned int cmdQ_restarted[3];/* # of times cmdQ X was restarted */ -}; - -struct sge_port_stats { - u64 rx_cso_good; /* # of successful RX csum offloads */ - u64 tx_cso; /* # of TX checksum offloads */ - u64 tx_tso; /* # of TSO requests */ - u64 vlan_xtract; /* # of VLAN tag extractions */ - u64 vlan_insert; /* # of VLAN tag insertions */ - u64 tx_need_hdrroom; /* # of TX skbs in need of more header room */ -}; - -struct sk_buff; -struct net_device; -struct adapter; -struct sge_params; -struct sge; - -struct sge *t1_sge_create(struct adapter *, struct sge_params *); -int t1_sge_configure(struct sge *, struct sge_params *); -int t1_sge_set_coalesce_params(struct sge *, struct sge_params *); -void t1_sge_destroy(struct sge *); -irqreturn_t t1_interrupt(int irq, void *cookie); -int t1_poll(struct napi_struct *, int); - -netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev); -void t1_vlan_mode(struct adapter *adapter, u32 features); -void t1_sge_start(struct sge *); -void t1_sge_stop(struct sge *); -int t1_sge_intr_error_handler(struct sge *); -void t1_sge_intr_enable(struct sge *); -void t1_sge_intr_disable(struct sge *); -void t1_sge_intr_clear(struct sge *); -const struct sge_intr_counts *t1_sge_get_intr_counts(const struct sge *sge); -void t1_sge_get_port_stats(const struct sge *sge, int port, struct sge_port_stats *); -unsigned int t1_sched_update_parms(struct sge *, unsigned int, unsigned int, - unsigned int); - -#endif /* _CXGB_SGE_H_ */ diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c deleted file mode 100644 index 8a43c7e19701..000000000000 --- a/drivers/net/chelsio/subr.c +++ /dev/null @@ -1,1130 +0,0 @@ -/***************************************************************************** - * * - * File: subr.c * - * $Revision: 1.27 $ * - * $Date: 2005/06/22 01:08:36 $ * - * Description: * - * Various subroutines (intr,pio,etc.) used by Chelsio 10G Ethernet driver. * - * part of the Chelsio 10Gb Ethernet Driver. * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * * - * http://www.chelsio.com * - * * - * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * - * All rights reserved. * - * * - * Maintainers: maintainers@chelsio.com * - * * - * Authors: Dimitrios Michailidis * - * Tina Yang * - * Felix Marti * - * Scott Bardone * - * Kurt Ottaway * - * Frank DiMambro * - * * - * History: * - * * - ****************************************************************************/ - -#include "common.h" -#include "elmer0.h" -#include "regs.h" -#include "gmac.h" -#include "cphy.h" -#include "sge.h" -#include "tp.h" -#include "espi.h" - -/** - * t1_wait_op_done - wait until an operation is completed - * @adapter: the adapter performing the operation - * @reg: the register to check for completion - * @mask: a single-bit field within @reg that indicates completion - * @polarity: the value of the field when the operation is completed - * @attempts: number of check iterations - * @delay: delay in usecs between iterations - * - * Wait until an operation is completed by checking a bit in a register - * up to @attempts times. Returns %0 if the operation completes and %1 - * otherwise. - */ -static int t1_wait_op_done(adapter_t *adapter, int reg, u32 mask, int polarity, - int attempts, int delay) -{ - while (1) { - u32 val = readl(adapter->regs + reg) & mask; - - if (!!val == polarity) - return 0; - if (--attempts == 0) - return 1; - if (delay) - udelay(delay); - } -} - -#define TPI_ATTEMPTS 50 - -/* - * Write a register over the TPI interface (unlocked and locked versions). - */ -int __t1_tpi_write(adapter_t *adapter, u32 addr, u32 value) -{ - int tpi_busy; - - writel(addr, adapter->regs + A_TPI_ADDR); - writel(value, adapter->regs + A_TPI_WR_DATA); - writel(F_TPIWR, adapter->regs + A_TPI_CSR); - - tpi_busy = t1_wait_op_done(adapter, A_TPI_CSR, F_TPIRDY, 1, - TPI_ATTEMPTS, 3); - if (tpi_busy) - pr_alert("%s: TPI write to 0x%x failed\n", - adapter->name, addr); - return tpi_busy; -} - -int t1_tpi_write(adapter_t *adapter, u32 addr, u32 value) -{ - int ret; - - spin_lock(&adapter->tpi_lock); - ret = __t1_tpi_write(adapter, addr, value); - spin_unlock(&adapter->tpi_lock); - return ret; -} - -/* - * Read a register over the TPI interface (unlocked and locked versions). - */ -int __t1_tpi_read(adapter_t *adapter, u32 addr, u32 *valp) -{ - int tpi_busy; - - writel(addr, adapter->regs + A_TPI_ADDR); - writel(0, adapter->regs + A_TPI_CSR); - - tpi_busy = t1_wait_op_done(adapter, A_TPI_CSR, F_TPIRDY, 1, - TPI_ATTEMPTS, 3); - if (tpi_busy) - pr_alert("%s: TPI read from 0x%x failed\n", - adapter->name, addr); - else - *valp = readl(adapter->regs + A_TPI_RD_DATA); - return tpi_busy; -} - -int t1_tpi_read(adapter_t *adapter, u32 addr, u32 *valp) -{ - int ret; - - spin_lock(&adapter->tpi_lock); - ret = __t1_tpi_read(adapter, addr, valp); - spin_unlock(&adapter->tpi_lock); - return ret; -} - -/* - * Set a TPI parameter. - */ -static void t1_tpi_par(adapter_t *adapter, u32 value) -{ - writel(V_TPIPAR(value), adapter->regs + A_TPI_PAR); -} - -/* - * Called when a port's link settings change to propagate the new values to the - * associated PHY and MAC. After performing the common tasks it invokes an - * OS-specific handler. - */ -void t1_link_changed(adapter_t *adapter, int port_id) -{ - int link_ok, speed, duplex, fc; - struct cphy *phy = adapter->port[port_id].phy; - struct link_config *lc = &adapter->port[port_id].link_config; - - phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc); - - lc->speed = speed < 0 ? SPEED_INVALID : speed; - lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex; - if (!(lc->requested_fc & PAUSE_AUTONEG)) - fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); - - if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE) { - /* Set MAC speed, duplex, and flow control to match PHY. */ - struct cmac *mac = adapter->port[port_id].mac; - - mac->ops->set_speed_duplex_fc(mac, speed, duplex, fc); - lc->fc = (unsigned char)fc; - } - t1_link_negotiated(adapter, port_id, link_ok, speed, duplex, fc); -} - -static int t1_pci_intr_handler(adapter_t *adapter) -{ - u32 pcix_cause; - - pci_read_config_dword(adapter->pdev, A_PCICFG_INTR_CAUSE, &pcix_cause); - - if (pcix_cause) { - pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_CAUSE, - pcix_cause); - t1_fatal_err(adapter); /* PCI errors are fatal */ - } - return 0; -} - -#ifdef CONFIG_CHELSIO_T1_1G -#include "fpga_defs.h" - -/* - * PHY interrupt handler for FPGA boards. - */ -static int fpga_phy_intr_handler(adapter_t *adapter) -{ - int p; - u32 cause = readl(adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_CAUSE); - - for_each_port(adapter, p) - if (cause & (1 << p)) { - struct cphy *phy = adapter->port[p].phy; - int phy_cause = phy->ops->interrupt_handler(phy); - - if (phy_cause & cphy_cause_link_change) - t1_link_changed(adapter, p); - } - writel(cause, adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_CAUSE); - return 0; -} - -/* - * Slow path interrupt handler for FPGAs. - */ -static int fpga_slow_intr(adapter_t *adapter) -{ - u32 cause = readl(adapter->regs + A_PL_CAUSE); - - cause &= ~F_PL_INTR_SGE_DATA; - if (cause & F_PL_INTR_SGE_ERR) - t1_sge_intr_error_handler(adapter->sge); - - if (cause & FPGA_PCIX_INTERRUPT_GMAC) - fpga_phy_intr_handler(adapter); - - if (cause & FPGA_PCIX_INTERRUPT_TP) { - /* - * FPGA doesn't support MC4 interrupts and it requires - * this odd layer of indirection for MC5. - */ - u32 tp_cause = readl(adapter->regs + FPGA_TP_ADDR_INTERRUPT_CAUSE); - - /* Clear TP interrupt */ - writel(tp_cause, adapter->regs + FPGA_TP_ADDR_INTERRUPT_CAUSE); - } - if (cause & FPGA_PCIX_INTERRUPT_PCIX) - t1_pci_intr_handler(adapter); - - /* Clear the interrupts just processed. */ - if (cause) - writel(cause, adapter->regs + A_PL_CAUSE); - - return cause != 0; -} -#endif - -/* - * Wait until Elmer's MI1 interface is ready for new operations. - */ -static int mi1_wait_until_ready(adapter_t *adapter, int mi1_reg) -{ - int attempts = 100, busy; - - do { - u32 val; - - __t1_tpi_read(adapter, mi1_reg, &val); - busy = val & F_MI1_OP_BUSY; - if (busy) - udelay(10); - } while (busy && --attempts); - if (busy) - pr_alert("%s: MDIO operation timed out\n", adapter->name); - return busy; -} - -/* - * MI1 MDIO initialization. - */ -static void mi1_mdio_init(adapter_t *adapter, const struct board_info *bi) -{ - u32 clkdiv = bi->clock_elmer0 / (2 * bi->mdio_mdc) - 1; - u32 val = F_MI1_PREAMBLE_ENABLE | V_MI1_MDI_INVERT(bi->mdio_mdiinv) | - V_MI1_MDI_ENABLE(bi->mdio_mdien) | V_MI1_CLK_DIV(clkdiv); - - if (!(bi->caps & SUPPORTED_10000baseT_Full)) - val |= V_MI1_SOF(1); - t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_CFG, val); -} - -#if defined(CONFIG_CHELSIO_T1_1G) -/* - * Elmer MI1 MDIO read/write operations. - */ -static int mi1_mdio_read(struct net_device *dev, int phy_addr, int mmd_addr, - u16 reg_addr) -{ - struct adapter *adapter = dev->ml_priv; - u32 addr = V_MI1_REG_ADDR(reg_addr) | V_MI1_PHY_ADDR(phy_addr); - unsigned int val; - - spin_lock(&adapter->tpi_lock); - __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr); - __t1_tpi_write(adapter, - A_ELMER0_PORT0_MI1_OP, MI1_OP_DIRECT_READ); - mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP); - __t1_tpi_read(adapter, A_ELMER0_PORT0_MI1_DATA, &val); - spin_unlock(&adapter->tpi_lock); - return val; -} - -static int mi1_mdio_write(struct net_device *dev, int phy_addr, int mmd_addr, - u16 reg_addr, u16 val) -{ - struct adapter *adapter = dev->ml_priv; - u32 addr = V_MI1_REG_ADDR(reg_addr) | V_MI1_PHY_ADDR(phy_addr); - - spin_lock(&adapter->tpi_lock); - __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr); - __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_DATA, val); - __t1_tpi_write(adapter, - A_ELMER0_PORT0_MI1_OP, MI1_OP_DIRECT_WRITE); - mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP); - spin_unlock(&adapter->tpi_lock); - return 0; -} - -static const struct mdio_ops mi1_mdio_ops = { - .init = mi1_mdio_init, - .read = mi1_mdio_read, - .write = mi1_mdio_write, - .mode_support = MDIO_SUPPORTS_C22 -}; - -#endif - -static int mi1_mdio_ext_read(struct net_device *dev, int phy_addr, int mmd_addr, - u16 reg_addr) -{ - struct adapter *adapter = dev->ml_priv; - u32 addr = V_MI1_REG_ADDR(mmd_addr) | V_MI1_PHY_ADDR(phy_addr); - unsigned int val; - - spin_lock(&adapter->tpi_lock); - - /* Write the address we want. */ - __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr); - __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_DATA, reg_addr); - __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_OP, - MI1_OP_INDIRECT_ADDRESS); - mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP); - - /* Write the operation we want. */ - __t1_tpi_write(adapter, - A_ELMER0_PORT0_MI1_OP, MI1_OP_INDIRECT_READ); - mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP); - - /* Read the data. */ - __t1_tpi_read(adapter, A_ELMER0_PORT0_MI1_DATA, &val); - spin_unlock(&adapter->tpi_lock); - return val; -} - -static int mi1_mdio_ext_write(struct net_device *dev, int phy_addr, - int mmd_addr, u16 reg_addr, u16 val) -{ - struct adapter *adapter = dev->ml_priv; - u32 addr = V_MI1_REG_ADDR(mmd_addr) | V_MI1_PHY_ADDR(phy_addr); - - spin_lock(&adapter->tpi_lock); - - /* Write the address we want. */ - __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr); - __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_DATA, reg_addr); - __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_OP, - MI1_OP_INDIRECT_ADDRESS); - mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP); - - /* Write the data. */ - __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_DATA, val); - __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_OP, MI1_OP_INDIRECT_WRITE); - mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP); - spin_unlock(&adapter->tpi_lock); - return 0; -} - -static const struct mdio_ops mi1_mdio_ext_ops = { - .init = mi1_mdio_init, - .read = mi1_mdio_ext_read, - .write = mi1_mdio_ext_write, - .mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22 -}; - -enum { - CH_BRD_T110_1CU, - CH_BRD_N110_1F, - CH_BRD_N210_1F, - CH_BRD_T210_1F, - CH_BRD_T210_1CU, - CH_BRD_N204_4CU, -}; - -static const struct board_info t1_board[] = { - { - .board = CHBT_BOARD_CHT110, - .port_number = 1, - .caps = SUPPORTED_10000baseT_Full, - .chip_term = CHBT_TERM_T1, - .chip_mac = CHBT_MAC_PM3393, - .chip_phy = CHBT_PHY_MY3126, - .clock_core = 125000000, - .clock_mc3 = 150000000, - .clock_mc4 = 125000000, - .espi_nports = 1, - .clock_elmer0 = 44, - .mdio_mdien = 1, - .mdio_mdiinv = 1, - .mdio_mdc = 1, - .mdio_phybaseaddr = 1, - .gmac = &t1_pm3393_ops, - .gphy = &t1_my3126_ops, - .mdio_ops = &mi1_mdio_ext_ops, - .desc = "Chelsio T110 1x10GBase-CX4 TOE", - }, - - { - .board = CHBT_BOARD_N110, - .port_number = 1, - .caps = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE, - .chip_term = CHBT_TERM_T1, - .chip_mac = CHBT_MAC_PM3393, - .chip_phy = CHBT_PHY_88X2010, - .clock_core = 125000000, - .espi_nports = 1, - .clock_elmer0 = 44, - .mdio_mdien = 0, - .mdio_mdiinv = 0, - .mdio_mdc = 1, - .mdio_phybaseaddr = 0, - .gmac = &t1_pm3393_ops, - .gphy = &t1_mv88x201x_ops, - .mdio_ops = &mi1_mdio_ext_ops, - .desc = "Chelsio N110 1x10GBaseX NIC", - }, - - { - .board = CHBT_BOARD_N210, - .port_number = 1, - .caps = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE, - .chip_term = CHBT_TERM_T2, - .chip_mac = CHBT_MAC_PM3393, - .chip_phy = CHBT_PHY_88X2010, - .clock_core = 125000000, - .espi_nports = 1, - .clock_elmer0 = 44, - .mdio_mdien = 0, - .mdio_mdiinv = 0, - .mdio_mdc = 1, - .mdio_phybaseaddr = 0, - .gmac = &t1_pm3393_ops, - .gphy = &t1_mv88x201x_ops, - .mdio_ops = &mi1_mdio_ext_ops, - .desc = "Chelsio N210 1x10GBaseX NIC", - }, - - { - .board = CHBT_BOARD_CHT210, - .port_number = 1, - .caps = SUPPORTED_10000baseT_Full, - .chip_term = CHBT_TERM_T2, - .chip_mac = CHBT_MAC_PM3393, - .chip_phy = CHBT_PHY_88X2010, - .clock_core = 125000000, - .clock_mc3 = 133000000, - .clock_mc4 = 125000000, - .espi_nports = 1, - .clock_elmer0 = 44, - .mdio_mdien = 0, - .mdio_mdiinv = 0, - .mdio_mdc = 1, - .mdio_phybaseaddr = 0, - .gmac = &t1_pm3393_ops, - .gphy = &t1_mv88x201x_ops, - .mdio_ops = &mi1_mdio_ext_ops, - .desc = "Chelsio T210 1x10GBaseX TOE", - }, - - { - .board = CHBT_BOARD_CHT210, - .port_number = 1, - .caps = SUPPORTED_10000baseT_Full, - .chip_term = CHBT_TERM_T2, - .chip_mac = CHBT_MAC_PM3393, - .chip_phy = CHBT_PHY_MY3126, - .clock_core = 125000000, - .clock_mc3 = 133000000, - .clock_mc4 = 125000000, - .espi_nports = 1, - .clock_elmer0 = 44, - .mdio_mdien = 1, - .mdio_mdiinv = 1, - .mdio_mdc = 1, - .mdio_phybaseaddr = 1, - .gmac = &t1_pm3393_ops, - .gphy = &t1_my3126_ops, - .mdio_ops = &mi1_mdio_ext_ops, - .desc = "Chelsio T210 1x10GBase-CX4 TOE", - }, - -#ifdef CONFIG_CHELSIO_T1_1G - { - .board = CHBT_BOARD_CHN204, - .port_number = 4, - .caps = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full - | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full - | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | - SUPPORTED_PAUSE | SUPPORTED_TP, - .chip_term = CHBT_TERM_T2, - .chip_mac = CHBT_MAC_VSC7321, - .chip_phy = CHBT_PHY_88E1111, - .clock_core = 100000000, - .espi_nports = 4, - .clock_elmer0 = 44, - .mdio_mdien = 0, - .mdio_mdiinv = 0, - .mdio_mdc = 0, - .mdio_phybaseaddr = 4, - .gmac = &t1_vsc7326_ops, - .gphy = &t1_mv88e1xxx_ops, - .mdio_ops = &mi1_mdio_ops, - .desc = "Chelsio N204 4x100/1000BaseT NIC", - }, -#endif - -}; - -DEFINE_PCI_DEVICE_TABLE(t1_pci_tbl) = { - CH_DEVICE(8, 0, CH_BRD_T110_1CU), - CH_DEVICE(8, 1, CH_BRD_T110_1CU), - CH_DEVICE(7, 0, CH_BRD_N110_1F), - CH_DEVICE(10, 1, CH_BRD_N210_1F), - CH_DEVICE(11, 1, CH_BRD_T210_1F), - CH_DEVICE(14, 1, CH_BRD_T210_1CU), - CH_DEVICE(16, 1, CH_BRD_N204_4CU), - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, t1_pci_tbl); - -/* - * Return the board_info structure with a given index. Out-of-range indices - * return NULL. - */ -const struct board_info *t1_get_board_info(unsigned int board_id) -{ - return board_id < ARRAY_SIZE(t1_board) ? &t1_board[board_id] : NULL; -} - -struct chelsio_vpd_t { - u32 format_version; - u8 serial_number[16]; - u8 mac_base_address[6]; - u8 pad[2]; /* make multiple-of-4 size requirement explicit */ -}; - -#define EEPROMSIZE (8 * 1024) -#define EEPROM_MAX_POLL 4 - -/* - * Read SEEPROM. A zero is written to the flag register when the address is - * written to the Control register. The hardware device will set the flag to a - * one when 4B have been transferred to the Data register. - */ -int t1_seeprom_read(adapter_t *adapter, u32 addr, __le32 *data) -{ - int i = EEPROM_MAX_POLL; - u16 val; - u32 v; - - if (addr >= EEPROMSIZE || (addr & 3)) - return -EINVAL; - - pci_write_config_word(adapter->pdev, A_PCICFG_VPD_ADDR, (u16)addr); - do { - udelay(50); - pci_read_config_word(adapter->pdev, A_PCICFG_VPD_ADDR, &val); - } while (!(val & F_VPD_OP_FLAG) && --i); - - if (!(val & F_VPD_OP_FLAG)) { - pr_err("%s: reading EEPROM address 0x%x failed\n", - adapter->name, addr); - return -EIO; - } - pci_read_config_dword(adapter->pdev, A_PCICFG_VPD_DATA, &v); - *data = cpu_to_le32(v); - return 0; -} - -static int t1_eeprom_vpd_get(adapter_t *adapter, struct chelsio_vpd_t *vpd) -{ - int addr, ret = 0; - - for (addr = 0; !ret && addr < sizeof(*vpd); addr += sizeof(u32)) - ret = t1_seeprom_read(adapter, addr, - (__le32 *)((u8 *)vpd + addr)); - - return ret; -} - -/* - * Read a port's MAC address from the VPD ROM. - */ -static int vpd_macaddress_get(adapter_t *adapter, int index, u8 mac_addr[]) -{ - struct chelsio_vpd_t vpd; - - if (t1_eeprom_vpd_get(adapter, &vpd)) - return 1; - memcpy(mac_addr, vpd.mac_base_address, 5); - mac_addr[5] = vpd.mac_base_address[5] + index; - return 0; -} - -/* - * Set up the MAC/PHY according to the requested link settings. - * - * If the PHY can auto-negotiate first decide what to advertise, then - * enable/disable auto-negotiation as desired and reset. - * - * If the PHY does not auto-negotiate we just reset it. - * - * If auto-negotiation is off set the MAC to the proper speed/duplex/FC, - * otherwise do it later based on the outcome of auto-negotiation. - */ -int t1_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc) -{ - unsigned int fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); - - if (lc->supported & SUPPORTED_Autoneg) { - lc->advertising &= ~(ADVERTISED_ASYM_PAUSE | ADVERTISED_PAUSE); - if (fc) { - if (fc == ((PAUSE_RX | PAUSE_TX) & - (mac->adapter->params.nports < 2))) - lc->advertising |= ADVERTISED_PAUSE; - else { - lc->advertising |= ADVERTISED_ASYM_PAUSE; - if (fc == PAUSE_RX) - lc->advertising |= ADVERTISED_PAUSE; - } - } - phy->ops->advertise(phy, lc->advertising); - - if (lc->autoneg == AUTONEG_DISABLE) { - lc->speed = lc->requested_speed; - lc->duplex = lc->requested_duplex; - lc->fc = (unsigned char)fc; - mac->ops->set_speed_duplex_fc(mac, lc->speed, - lc->duplex, fc); - /* Also disables autoneg */ - phy->state = PHY_AUTONEG_RDY; - phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex); - phy->ops->reset(phy, 0); - } else { - phy->state = PHY_AUTONEG_EN; - phy->ops->autoneg_enable(phy); /* also resets PHY */ - } - } else { - phy->state = PHY_AUTONEG_RDY; - mac->ops->set_speed_duplex_fc(mac, -1, -1, fc); - lc->fc = (unsigned char)fc; - phy->ops->reset(phy, 0); - } - return 0; -} - -/* - * External interrupt handler for boards using elmer0. - */ -int t1_elmer0_ext_intr_handler(adapter_t *adapter) -{ - struct cphy *phy; - int phy_cause; - u32 cause; - - t1_tpi_read(adapter, A_ELMER0_INT_CAUSE, &cause); - - switch (board_info(adapter)->board) { -#ifdef CONFIG_CHELSIO_T1_1G - case CHBT_BOARD_CHT204: - case CHBT_BOARD_CHT204E: - case CHBT_BOARD_CHN204: - case CHBT_BOARD_CHT204V: { - int i, port_bit; - for_each_port(adapter, i) { - port_bit = i + 1; - if (!(cause & (1 << port_bit))) - continue; - - phy = adapter->port[i].phy; - phy_cause = phy->ops->interrupt_handler(phy); - if (phy_cause & cphy_cause_link_change) - t1_link_changed(adapter, i); - } - break; - } - case CHBT_BOARD_CHT101: - if (cause & ELMER0_GP_BIT1) { /* Marvell 88E1111 interrupt */ - phy = adapter->port[0].phy; - phy_cause = phy->ops->interrupt_handler(phy); - if (phy_cause & cphy_cause_link_change) - t1_link_changed(adapter, 0); - } - break; - case CHBT_BOARD_7500: { - int p; - /* - * Elmer0's interrupt cause isn't useful here because there is - * only one bit that can be set for all 4 ports. This means - * we are forced to check every PHY's interrupt status - * register to see who initiated the interrupt. - */ - for_each_port(adapter, p) { - phy = adapter->port[p].phy; - phy_cause = phy->ops->interrupt_handler(phy); - if (phy_cause & cphy_cause_link_change) - t1_link_changed(adapter, p); - } - break; - } -#endif - case CHBT_BOARD_CHT210: - case CHBT_BOARD_N210: - case CHBT_BOARD_N110: - if (cause & ELMER0_GP_BIT6) { /* Marvell 88x2010 interrupt */ - phy = adapter->port[0].phy; - phy_cause = phy->ops->interrupt_handler(phy); - if (phy_cause & cphy_cause_link_change) - t1_link_changed(adapter, 0); - } - break; - case CHBT_BOARD_8000: - case CHBT_BOARD_CHT110: - if (netif_msg_intr(adapter)) - dev_dbg(&adapter->pdev->dev, - "External interrupt cause 0x%x\n", cause); - if (cause & ELMER0_GP_BIT1) { /* PMC3393 INTB */ - struct cmac *mac = adapter->port[0].mac; - - mac->ops->interrupt_handler(mac); - } - if (cause & ELMER0_GP_BIT5) { /* XPAK MOD_DETECT */ - u32 mod_detect; - - t1_tpi_read(adapter, - A_ELMER0_GPI_STAT, &mod_detect); - if (netif_msg_link(adapter)) - dev_info(&adapter->pdev->dev, "XPAK %s\n", - mod_detect ? "removed" : "inserted"); - } - break; - } - t1_tpi_write(adapter, A_ELMER0_INT_CAUSE, cause); - return 0; -} - -/* Enables all interrupts. */ -void t1_interrupts_enable(adapter_t *adapter) -{ - unsigned int i; - - adapter->slow_intr_mask = F_PL_INTR_SGE_ERR | F_PL_INTR_TP; - - t1_sge_intr_enable(adapter->sge); - t1_tp_intr_enable(adapter->tp); - if (adapter->espi) { - adapter->slow_intr_mask |= F_PL_INTR_ESPI; - t1_espi_intr_enable(adapter->espi); - } - - /* Enable MAC/PHY interrupts for each port. */ - for_each_port(adapter, i) { - adapter->port[i].mac->ops->interrupt_enable(adapter->port[i].mac); - adapter->port[i].phy->ops->interrupt_enable(adapter->port[i].phy); - } - - /* Enable PCIX & external chip interrupts on ASIC boards. */ - if (t1_is_asic(adapter)) { - u32 pl_intr = readl(adapter->regs + A_PL_ENABLE); - - /* PCI-X interrupts */ - pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_ENABLE, - 0xffffffff); - - adapter->slow_intr_mask |= F_PL_INTR_EXT | F_PL_INTR_PCIX; - pl_intr |= F_PL_INTR_EXT | F_PL_INTR_PCIX; - writel(pl_intr, adapter->regs + A_PL_ENABLE); - } -} - -/* Disables all interrupts. */ -void t1_interrupts_disable(adapter_t* adapter) -{ - unsigned int i; - - t1_sge_intr_disable(adapter->sge); - t1_tp_intr_disable(adapter->tp); - if (adapter->espi) - t1_espi_intr_disable(adapter->espi); - - /* Disable MAC/PHY interrupts for each port. */ - for_each_port(adapter, i) { - adapter->port[i].mac->ops->interrupt_disable(adapter->port[i].mac); - adapter->port[i].phy->ops->interrupt_disable(adapter->port[i].phy); - } - - /* Disable PCIX & external chip interrupts. */ - if (t1_is_asic(adapter)) - writel(0, adapter->regs + A_PL_ENABLE); - - /* PCI-X interrupts */ - pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_ENABLE, 0); - - adapter->slow_intr_mask = 0; -} - -/* Clears all interrupts */ -void t1_interrupts_clear(adapter_t* adapter) -{ - unsigned int i; - - t1_sge_intr_clear(adapter->sge); - t1_tp_intr_clear(adapter->tp); - if (adapter->espi) - t1_espi_intr_clear(adapter->espi); - - /* Clear MAC/PHY interrupts for each port. */ - for_each_port(adapter, i) { - adapter->port[i].mac->ops->interrupt_clear(adapter->port[i].mac); - adapter->port[i].phy->ops->interrupt_clear(adapter->port[i].phy); - } - - /* Enable interrupts for external devices. */ - if (t1_is_asic(adapter)) { - u32 pl_intr = readl(adapter->regs + A_PL_CAUSE); - - writel(pl_intr | F_PL_INTR_EXT | F_PL_INTR_PCIX, - adapter->regs + A_PL_CAUSE); - } - - /* PCI-X interrupts */ - pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_CAUSE, 0xffffffff); -} - -/* - * Slow path interrupt handler for ASICs. - */ -static int asic_slow_intr(adapter_t *adapter) -{ - u32 cause = readl(adapter->regs + A_PL_CAUSE); - - cause &= adapter->slow_intr_mask; - if (!cause) - return 0; - if (cause & F_PL_INTR_SGE_ERR) - t1_sge_intr_error_handler(adapter->sge); - if (cause & F_PL_INTR_TP) - t1_tp_intr_handler(adapter->tp); - if (cause & F_PL_INTR_ESPI) - t1_espi_intr_handler(adapter->espi); - if (cause & F_PL_INTR_PCIX) - t1_pci_intr_handler(adapter); - if (cause & F_PL_INTR_EXT) - t1_elmer0_ext_intr(adapter); - - /* Clear the interrupts just processed. */ - writel(cause, adapter->regs + A_PL_CAUSE); - readl(adapter->regs + A_PL_CAUSE); /* flush writes */ - return 1; -} - -int t1_slow_intr_handler(adapter_t *adapter) -{ -#ifdef CONFIG_CHELSIO_T1_1G - if (!t1_is_asic(adapter)) - return fpga_slow_intr(adapter); -#endif - return asic_slow_intr(adapter); -} - -/* Power sequencing is a work-around for Intel's XPAKs. */ -static void power_sequence_xpak(adapter_t* adapter) -{ - u32 mod_detect; - u32 gpo; - - /* Check for XPAK */ - t1_tpi_read(adapter, A_ELMER0_GPI_STAT, &mod_detect); - if (!(ELMER0_GP_BIT5 & mod_detect)) { - /* XPAK is present */ - t1_tpi_read(adapter, A_ELMER0_GPO, &gpo); - gpo |= ELMER0_GP_BIT18; - t1_tpi_write(adapter, A_ELMER0_GPO, gpo); - } -} - -int __devinit t1_get_board_rev(adapter_t *adapter, const struct board_info *bi, - struct adapter_params *p) -{ - p->chip_version = bi->chip_term; - p->is_asic = (p->chip_version != CHBT_TERM_FPGA); - if (p->chip_version == CHBT_TERM_T1 || - p->chip_version == CHBT_TERM_T2 || - p->chip_version == CHBT_TERM_FPGA) { - u32 val = readl(adapter->regs + A_TP_PC_CONFIG); - - val = G_TP_PC_REV(val); - if (val == 2) - p->chip_revision = TERM_T1B; - else if (val == 3) - p->chip_revision = TERM_T2; - else - return -1; - } else - return -1; - return 0; -} - -/* - * Enable board components other than the Chelsio chip, such as external MAC - * and PHY. - */ -static int board_init(adapter_t *adapter, const struct board_info *bi) -{ - switch (bi->board) { - case CHBT_BOARD_8000: - case CHBT_BOARD_N110: - case CHBT_BOARD_N210: - case CHBT_BOARD_CHT210: - t1_tpi_par(adapter, 0xf); - t1_tpi_write(adapter, A_ELMER0_GPO, 0x800); - break; - case CHBT_BOARD_CHT110: - t1_tpi_par(adapter, 0xf); - t1_tpi_write(adapter, A_ELMER0_GPO, 0x1800); - - /* TBD XXX Might not need. This fixes a problem - * described in the Intel SR XPAK errata. - */ - power_sequence_xpak(adapter); - break; -#ifdef CONFIG_CHELSIO_T1_1G - case CHBT_BOARD_CHT204E: - /* add config space write here */ - case CHBT_BOARD_CHT204: - case CHBT_BOARD_CHT204V: - case CHBT_BOARD_CHN204: - t1_tpi_par(adapter, 0xf); - t1_tpi_write(adapter, A_ELMER0_GPO, 0x804); - break; - case CHBT_BOARD_CHT101: - case CHBT_BOARD_7500: - t1_tpi_par(adapter, 0xf); - t1_tpi_write(adapter, A_ELMER0_GPO, 0x1804); - break; -#endif - } - return 0; -} - -/* - * Initialize and configure the Terminator HW modules. Note that external - * MAC and PHYs are initialized separately. - */ -int t1_init_hw_modules(adapter_t *adapter) -{ - int err = -EIO; - const struct board_info *bi = board_info(adapter); - - if (!bi->clock_mc4) { - u32 val = readl(adapter->regs + A_MC4_CFG); - - writel(val | F_READY | F_MC4_SLOW, adapter->regs + A_MC4_CFG); - writel(F_M_BUS_ENABLE | F_TCAM_RESET, - adapter->regs + A_MC5_CONFIG); - } - - if (adapter->espi && t1_espi_init(adapter->espi, bi->chip_mac, - bi->espi_nports)) - goto out_err; - - if (t1_tp_reset(adapter->tp, &adapter->params.tp, bi->clock_core)) - goto out_err; - - err = t1_sge_configure(adapter->sge, &adapter->params.sge); - if (err) - goto out_err; - - err = 0; -out_err: - return err; -} - -/* - * Determine a card's PCI mode. - */ -static void __devinit get_pci_mode(adapter_t *adapter, struct chelsio_pci_params *p) -{ - static const unsigned short speed_map[] = { 33, 66, 100, 133 }; - u32 pci_mode; - - pci_read_config_dword(adapter->pdev, A_PCICFG_MODE, &pci_mode); - p->speed = speed_map[G_PCI_MODE_CLK(pci_mode)]; - p->width = (pci_mode & F_PCI_MODE_64BIT) ? 64 : 32; - p->is_pcix = (pci_mode & F_PCI_MODE_PCIX) != 0; -} - -/* - * Release the structures holding the SW per-Terminator-HW-module state. - */ -void t1_free_sw_modules(adapter_t *adapter) -{ - unsigned int i; - - for_each_port(adapter, i) { - struct cmac *mac = adapter->port[i].mac; - struct cphy *phy = adapter->port[i].phy; - - if (mac) - mac->ops->destroy(mac); - if (phy) - phy->ops->destroy(phy); - } - - if (adapter->sge) - t1_sge_destroy(adapter->sge); - if (adapter->tp) - t1_tp_destroy(adapter->tp); - if (adapter->espi) - t1_espi_destroy(adapter->espi); -} - -static void __devinit init_link_config(struct link_config *lc, - const struct board_info *bi) -{ - lc->supported = bi->caps; - lc->requested_speed = lc->speed = SPEED_INVALID; - lc->requested_duplex = lc->duplex = DUPLEX_INVALID; - lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX; - if (lc->supported & SUPPORTED_Autoneg) { - lc->advertising = lc->supported; - lc->autoneg = AUTONEG_ENABLE; - lc->requested_fc |= PAUSE_AUTONEG; - } else { - lc->advertising = 0; - lc->autoneg = AUTONEG_DISABLE; - } -} - -/* - * Allocate and initialize the data structures that hold the SW state of - * the Terminator HW modules. - */ -int __devinit t1_init_sw_modules(adapter_t *adapter, - const struct board_info *bi) -{ - unsigned int i; - - adapter->params.brd_info = bi; - adapter->params.nports = bi->port_number; - adapter->params.stats_update_period = bi->gmac->stats_update_period; - - adapter->sge = t1_sge_create(adapter, &adapter->params.sge); - if (!adapter->sge) { - pr_err("%s: SGE initialization failed\n", - adapter->name); - goto error; - } - - if (bi->espi_nports && !(adapter->espi = t1_espi_create(adapter))) { - pr_err("%s: ESPI initialization failed\n", - adapter->name); - goto error; - } - - adapter->tp = t1_tp_create(adapter, &adapter->params.tp); - if (!adapter->tp) { - pr_err("%s: TP initialization failed\n", - adapter->name); - goto error; - } - - board_init(adapter, bi); - bi->mdio_ops->init(adapter, bi); - if (bi->gphy->reset) - bi->gphy->reset(adapter); - if (bi->gmac->reset) - bi->gmac->reset(adapter); - - for_each_port(adapter, i) { - u8 hw_addr[6]; - struct cmac *mac; - int phy_addr = bi->mdio_phybaseaddr + i; - - adapter->port[i].phy = bi->gphy->create(adapter->port[i].dev, - phy_addr, bi->mdio_ops); - if (!adapter->port[i].phy) { - pr_err("%s: PHY %d initialization failed\n", - adapter->name, i); - goto error; - } - - adapter->port[i].mac = mac = bi->gmac->create(adapter, i); - if (!mac) { - pr_err("%s: MAC %d initialization failed\n", - adapter->name, i); - goto error; - } - - /* - * Get the port's MAC addresses either from the EEPROM if one - * exists or the one hardcoded in the MAC. - */ - if (!t1_is_asic(adapter) || bi->chip_mac == CHBT_MAC_DUMMY) - mac->ops->macaddress_get(mac, hw_addr); - else if (vpd_macaddress_get(adapter, i, hw_addr)) { - pr_err("%s: could not read MAC address from VPD ROM\n", - adapter->port[i].dev->name); - goto error; - } - memcpy(adapter->port[i].dev->dev_addr, hw_addr, ETH_ALEN); - init_link_config(&adapter->port[i].link_config, bi); - } - - get_pci_mode(adapter, &adapter->params.pci); - t1_interrupts_clear(adapter); - return 0; - -error: - t1_free_sw_modules(adapter); - return -1; -} diff --git a/drivers/net/chelsio/suni1x10gexp_regs.h b/drivers/net/chelsio/suni1x10gexp_regs.h deleted file mode 100644 index d0f87d82566a..000000000000 --- a/drivers/net/chelsio/suni1x10gexp_regs.h +++ /dev/null @@ -1,1643 +0,0 @@ -/***************************************************************************** - * * - * File: suni1x10gexp_regs.h * - * $Revision: 1.9 $ * - * $Date: 2005/06/22 00:17:04 $ * - * Description: * - * PMC/SIERRA (pm3393) MAC-PHY functionality. * - * part of the Chelsio 10Gb Ethernet Driver. * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, write to the Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * * - * http://www.chelsio.com * - * * - * Maintainers: maintainers@chelsio.com * - * * - * Authors: PMC/SIERRA * - * * - * History: * - * * - ****************************************************************************/ - -#ifndef _CXGB_SUNI1x10GEXP_REGS_H_ -#define _CXGB_SUNI1x10GEXP_REGS_H_ - -/* -** Space allocated for each Exact Match Filter -** There are 8 filter configurations -*/ -#define SUNI1x10GEXP_REG_SIZEOF_MAC_FILTER 0x0003 - -#define mSUNI1x10GEXP_MAC_FILTER_OFFSET(filterId) ( (filterId) * SUNI1x10GEXP_REG_SIZEOF_MAC_FILTER ) - -/* -** Space allocated for VLAN-Id Filter -** There are 8 filter configurations -*/ -#define SUNI1x10GEXP_REG_SIZEOF_MAC_VID_FILTER 0x0001 - -#define mSUNI1x10GEXP_MAC_VID_FILTER_OFFSET(filterId) ( (filterId) * SUNI1x10GEXP_REG_SIZEOF_MAC_VID_FILTER ) - -/* -** Space allocated for each MSTAT Counter -*/ -#define SUNI1x10GEXP_REG_SIZEOF_MSTAT_COUNT 0x0004 - -#define mSUNI1x10GEXP_MSTAT_COUNT_OFFSET(countId) ( (countId) * SUNI1x10GEXP_REG_SIZEOF_MSTAT_COUNT ) - - -/******************************************************************************/ -/** S/UNI-1x10GE-XP REGISTER ADDRESS MAP **/ -/******************************************************************************/ -/* Refer to the Register Bit Masks bellow for the naming of each register and */ -/* to the S/UNI-1x10GE-XP Data Sheet for the signification of each bit */ -/******************************************************************************/ - - -#define SUNI1x10GEXP_REG_IDENTIFICATION 0x0000 -#define SUNI1x10GEXP_REG_PRODUCT_REVISION 0x0001 -#define SUNI1x10GEXP_REG_CONFIG_AND_RESET_CONTROL 0x0002 -#define SUNI1x10GEXP_REG_LOOPBACK_MISC_CTRL 0x0003 -#define SUNI1x10GEXP_REG_DEVICE_STATUS 0x0004 -#define SUNI1x10GEXP_REG_GLOBAL_PERFORMANCE_MONITOR_UPDATE 0x0005 - -#define SUNI1x10GEXP_REG_MDIO_COMMAND 0x0006 -#define SUNI1x10GEXP_REG_MDIO_INTERRUPT_ENABLE 0x0007 -#define SUNI1x10GEXP_REG_MDIO_INTERRUPT_STATUS 0x0008 -#define SUNI1x10GEXP_REG_MMD_PHY_ADDRESS 0x0009 -#define SUNI1x10GEXP_REG_MMD_CONTROL_ADDRESS_DATA 0x000A -#define SUNI1x10GEXP_REG_MDIO_READ_STATUS_DATA 0x000B - -#define SUNI1x10GEXP_REG_OAM_INTF_CTRL 0x000C -#define SUNI1x10GEXP_REG_MASTER_INTERRUPT_STATUS 0x000D -#define SUNI1x10GEXP_REG_GLOBAL_INTERRUPT_ENABLE 0x000E -#define SUNI1x10GEXP_REG_FREE 0x000F - -#define SUNI1x10GEXP_REG_XTEF_MISC_CTRL 0x0010 -#define SUNI1x10GEXP_REG_XRF_MISC_CTRL 0x0011 - -#define SUNI1x10GEXP_REG_SERDES_3125_CONFIG_1 0x0100 -#define SUNI1x10GEXP_REG_SERDES_3125_CONFIG_2 0x0101 -#define SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_ENABLE 0x0102 -#define SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_VISIBLE 0x0103 -#define SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_STATUS 0x0104 -#define SUNI1x10GEXP_REG_SERDES_3125_TEST_CONFIG 0x0107 - -#define SUNI1x10GEXP_REG_RXXG_CONFIG_1 0x2040 -#define SUNI1x10GEXP_REG_RXXG_CONFIG_2 0x2041 -#define SUNI1x10GEXP_REG_RXXG_CONFIG_3 0x2042 -#define SUNI1x10GEXP_REG_RXXG_INTERRUPT 0x2043 -#define SUNI1x10GEXP_REG_RXXG_MAX_FRAME_LENGTH 0x2045 -#define SUNI1x10GEXP_REG_RXXG_SA_15_0 0x2046 -#define SUNI1x10GEXP_REG_RXXG_SA_31_16 0x2047 -#define SUNI1x10GEXP_REG_RXXG_SA_47_32 0x2048 -#define SUNI1x10GEXP_REG_RXXG_RECEIVE_FIFO_THRESHOLD 0x2049 -#define mSUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_LOW(filterId) (0x204A + mSUNI1x10GEXP_MAC_FILTER_OFFSET(filterId)) -#define mSUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_MID(filterId) (0x204B + mSUNI1x10GEXP_MAC_FILTER_OFFSET(filterId)) -#define mSUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_HIGH(filterId)(0x204C + mSUNI1x10GEXP_MAC_FILTER_OFFSET(filterId)) -#define mSUNI1x10GEXP_REG_RXXG_EXACT_MATCH_VID(filterId) (0x2062 + mSUNI1x10GEXP_MAC_VID_FILTER_OFFSET(filterId)) -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_0_LOW 0x204A -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_0_MID 0x204B -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_0_HIGH 0x204C -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_LOW 0x204D -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_MID 0x204E -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_HIGH 0x204F -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_2_LOW 0x2050 -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_2_MID 0x2051 -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_2_HIGH 0x2052 -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_3_LOW 0x2053 -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_3_MID 0x2054 -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_3_HIGH 0x2055 -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_4_LOW 0x2056 -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_4_MID 0x2057 -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_4_HIGH 0x2058 -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_5_LOW 0x2059 -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_5_MID 0x205A -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_5_HIGH 0x205B -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_6_LOW 0x205C -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_6_MID 0x205D -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_6_HIGH 0x205E -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_7_LOW 0x205F -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_7_MID 0x2060 -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_7_HIGH 0x2061 -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_VID_0 0x2062 -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_VID_1 0x2063 -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_VID_2 0x2064 -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_VID_3 0x2065 -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_VID_4 0x2066 -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_VID_5 0x2067 -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_VID_6 0x2068 -#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_VID_7 0x2069 -#define SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_LOW 0x206A -#define SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDLOW 0x206B -#define SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDHIGH 0x206C -#define SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_HIGH 0x206D -#define SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_0 0x206E -#define SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_1 0x206F -#define SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_2 0x2070 - -#define SUNI1x10GEXP_REG_XRF_PATTERN_GEN_CTRL 0x2081 -#define SUNI1x10GEXP_REG_XRF_8BTB_ERR_COUNT_LANE_0 0x2084 -#define SUNI1x10GEXP_REG_XRF_8BTB_ERR_COUNT_LANE_1 0x2085 -#define SUNI1x10GEXP_REG_XRF_8BTB_ERR_COUNT_LANE_2 0x2086 -#define SUNI1x10GEXP_REG_XRF_8BTB_ERR_COUNT_LANE_3 0x2087 -#define SUNI1x10GEXP_REG_XRF_INTERRUPT_ENABLE 0x2088 -#define SUNI1x10GEXP_REG_XRF_INTERRUPT_STATUS 0x2089 -#define SUNI1x10GEXP_REG_XRF_ERR_STATUS 0x208A -#define SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_ENABLE 0x208B -#define SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_STATUS 0x208C -#define SUNI1x10GEXP_REG_XRF_CODE_ERR_THRES 0x2092 - -#define SUNI1x10GEXP_REG_RXOAM_CONFIG 0x20C0 -#define SUNI1x10GEXP_REG_RXOAM_FILTER_1_CONFIG 0x20C1 -#define SUNI1x10GEXP_REG_RXOAM_FILTER_2_CONFIG 0x20C2 -#define SUNI1x10GEXP_REG_RXOAM_CONFIG_2 0x20C3 -#define SUNI1x10GEXP_REG_RXOAM_HEC_CONFIG 0x20C4 -#define SUNI1x10GEXP_REG_RXOAM_HEC_ERR_THRES 0x20C5 -#define SUNI1x10GEXP_REG_RXOAM_INTERRUPT_ENABLE 0x20C7 -#define SUNI1x10GEXP_REG_RXOAM_INTERRUPT_STATUS 0x20C8 -#define SUNI1x10GEXP_REG_RXOAM_STATUS 0x20C9 -#define SUNI1x10GEXP_REG_RXOAM_HEC_ERR_COUNT 0x20CA -#define SUNI1x10GEXP_REG_RXOAM_FIFO_OVERFLOW_COUNT 0x20CB -#define SUNI1x10GEXP_REG_RXOAM_FILTER_MISMATCH_COUNT_LSB 0x20CC -#define SUNI1x10GEXP_REG_RXOAM_FILTER_MISMATCH_COUNT_MSB 0x20CD -#define SUNI1x10GEXP_REG_RXOAM_FILTER_1_MISMATCH_COUNT_LSB 0x20CE -#define SUNI1x10GEXP_REG_RXOAM_FILTER_1_MISMATCH_COUNT_MSB 0x20CF -#define SUNI1x10GEXP_REG_RXOAM_FILTER_2_MISMATCH_COUNT_LSB 0x20D0 -#define SUNI1x10GEXP_REG_RXOAM_FILTER_2_MISMATCH_COUNT_MSB 0x20D1 -#define SUNI1x10GEXP_REG_RXOAM_OAM_EXTRACT_COUNT_LSB 0x20D2 -#define SUNI1x10GEXP_REG_RXOAM_OAM_EXTRACT_COUNT_MSB 0x20D3 -#define SUNI1x10GEXP_REG_RXOAM_MINI_PACKET_COUNT_LSB 0x20D4 -#define SUNI1x10GEXP_REG_RXOAM_MINI_PACKET_COUNT_MSB 0x20D5 -#define SUNI1x10GEXP_REG_RXOAM_FILTER_MISMATCH_THRES_LSB 0x20D6 -#define SUNI1x10GEXP_REG_RXOAM_FILTER_MISMATCH_THRES_MSB 0x20D7 - -#define SUNI1x10GEXP_REG_MSTAT_CONTROL 0x2100 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_0 0x2101 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_1 0x2102 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_2 0x2103 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_3 0x2104 -#define SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_0 0x2105 -#define SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_1 0x2106 -#define SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_2 0x2107 -#define SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_3 0x2108 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_WRITE_ADDRESS 0x2109 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_WRITE_DATA_LOW 0x210A -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_WRITE_DATA_MIDDLE 0x210B -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_WRITE_DATA_HIGH 0x210C -#define mSUNI1x10GEXP_REG_MSTAT_COUNTER_LOW(countId) (0x2110 + mSUNI1x10GEXP_MSTAT_COUNT_OFFSET(countId)) -#define mSUNI1x10GEXP_REG_MSTAT_COUNTER_MID(countId) (0x2111 + mSUNI1x10GEXP_MSTAT_COUNT_OFFSET(countId)) -#define mSUNI1x10GEXP_REG_MSTAT_COUNTER_HIGH(countId) (0x2112 + mSUNI1x10GEXP_MSTAT_COUNT_OFFSET(countId)) -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_0_LOW 0x2110 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_0_MID 0x2111 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_0_HIGH 0x2112 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_0_RESVD 0x2113 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_1_LOW 0x2114 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_1_MID 0x2115 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_1_HIGH 0x2116 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_1_RESVD 0x2117 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_2_LOW 0x2118 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_2_MID 0x2119 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_2_HIGH 0x211A -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_2_RESVD 0x211B -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_3_LOW 0x211C -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_3_MID 0x211D -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_3_HIGH 0x211E -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_3_RESVD 0x211F -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_4_LOW 0x2120 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_4_MID 0x2121 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_4_HIGH 0x2122 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_4_RESVD 0x2123 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_5_LOW 0x2124 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_5_MID 0x2125 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_5_HIGH 0x2126 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_5_RESVD 0x2127 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_6_LOW 0x2128 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_6_MID 0x2129 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_6_HIGH 0x212A -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_6_RESVD 0x212B -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_7_LOW 0x212C -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_7_MID 0x212D -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_7_HIGH 0x212E -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_7_RESVD 0x212F -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_8_LOW 0x2130 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_8_MID 0x2131 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_8_HIGH 0x2132 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_8_RESVD 0x2133 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_9_LOW 0x2134 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_9_MID 0x2135 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_9_HIGH 0x2136 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_9_RESVD 0x2137 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_10_LOW 0x2138 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_10_MID 0x2139 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_10_HIGH 0x213A -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_10_RESVD 0x213B -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_11_LOW 0x213C -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_11_MID 0x213D -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_11_HIGH 0x213E -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_11_RESVD 0x213F -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_12_LOW 0x2140 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_12_MID 0x2141 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_12_HIGH 0x2142 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_12_RESVD 0x2143 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_13_LOW 0x2144 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_13_MID 0x2145 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_13_HIGH 0x2146 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_13_RESVD 0x2147 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_14_LOW 0x2148 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_14_MID 0x2149 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_14_HIGH 0x214A -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_14_RESVD 0x214B -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_15_LOW 0x214C -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_15_MID 0x214D -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_15_HIGH 0x214E -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_15_RESVD 0x214F -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_16_LOW 0x2150 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_16_MID 0x2151 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_16_HIGH 0x2152 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_16_RESVD 0x2153 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_17_LOW 0x2154 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_17_MID 0x2155 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_17_HIGH 0x2156 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_17_RESVD 0x2157 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_18_LOW 0x2158 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_18_MID 0x2159 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_18_HIGH 0x215A -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_18_RESVD 0x215B -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_19_LOW 0x215C -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_19_MID 0x215D -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_19_HIGH 0x215E -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_19_RESVD 0x215F -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_20_LOW 0x2160 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_20_MID 0x2161 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_20_HIGH 0x2162 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_20_RESVD 0x2163 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_21_LOW 0x2164 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_21_MID 0x2165 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_21_HIGH 0x2166 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_21_RESVD 0x2167 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_22_LOW 0x2168 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_22_MID 0x2169 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_22_HIGH 0x216A -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_22_RESVD 0x216B -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_23_LOW 0x216C -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_23_MID 0x216D -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_23_HIGH 0x216E -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_23_RESVD 0x216F -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_24_LOW 0x2170 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_24_MID 0x2171 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_24_HIGH 0x2172 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_24_RESVD 0x2173 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_25_LOW 0x2174 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_25_MID 0x2175 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_25_HIGH 0x2176 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_25_RESVD 0x2177 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_26_LOW 0x2178 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_26_MID 0x2179 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_26_HIGH 0x217a -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_26_RESVD 0x217b -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_27_LOW 0x217c -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_27_MID 0x217d -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_27_HIGH 0x217e -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_27_RESVD 0x217f -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_28_LOW 0x2180 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_28_MID 0x2181 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_28_HIGH 0x2182 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_28_RESVD 0x2183 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_29_LOW 0x2184 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_29_MID 0x2185 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_29_HIGH 0x2186 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_29_RESVD 0x2187 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_30_LOW 0x2188 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_30_MID 0x2189 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_30_HIGH 0x218A -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_30_RESVD 0x218B -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_31_LOW 0x218C -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_31_MID 0x218D -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_31_HIGH 0x218E -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_31_RESVD 0x218F -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_32_LOW 0x2190 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_32_MID 0x2191 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_32_HIGH 0x2192 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_32_RESVD 0x2193 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_33_LOW 0x2194 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_33_MID 0x2195 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_33_HIGH 0x2196 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_33_RESVD 0x2197 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_34_LOW 0x2198 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_34_MID 0x2199 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_34_HIGH 0x219A -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_34_RESVD 0x219B -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_35_LOW 0x219C -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_35_MID 0x219D -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_35_HIGH 0x219E -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_35_RESVD 0x219F -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_36_LOW 0x21A0 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_36_MID 0x21A1 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_36_HIGH 0x21A2 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_36_RESVD 0x21A3 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_37_LOW 0x21A4 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_37_MID 0x21A5 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_37_HIGH 0x21A6 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_37_RESVD 0x21A7 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_38_LOW 0x21A8 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_38_MID 0x21A9 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_38_HIGH 0x21AA -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_38_RESVD 0x21AB -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_39_LOW 0x21AC -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_39_MID 0x21AD -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_39_HIGH 0x21AE -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_39_RESVD 0x21AF -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_40_LOW 0x21B0 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_40_MID 0x21B1 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_40_HIGH 0x21B2 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_40_RESVD 0x21B3 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_41_LOW 0x21B4 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_41_MID 0x21B5 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_41_HIGH 0x21B6 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_41_RESVD 0x21B7 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_42_LOW 0x21B8 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_42_MID 0x21B9 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_42_HIGH 0x21BA -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_42_RESVD 0x21BB -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_43_LOW 0x21BC -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_43_MID 0x21BD -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_43_HIGH 0x21BE -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_43_RESVD 0x21BF -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_44_LOW 0x21C0 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_44_MID 0x21C1 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_44_HIGH 0x21C2 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_44_RESVD 0x21C3 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_45_LOW 0x21C4 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_45_MID 0x21C5 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_45_HIGH 0x21C6 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_45_RESVD 0x21C7 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_46_LOW 0x21C8 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_46_MID 0x21C9 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_46_HIGH 0x21CA -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_46_RESVD 0x21CB -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_47_LOW 0x21CC -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_47_MID 0x21CD -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_47_HIGH 0x21CE -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_47_RESVD 0x21CF -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_48_LOW 0x21D0 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_48_MID 0x21D1 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_48_HIGH 0x21D2 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_48_RESVD 0x21D3 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_49_LOW 0x21D4 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_49_MID 0x21D5 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_49_HIGH 0x21D6 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_49_RESVD 0x21D7 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_50_LOW 0x21D8 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_50_MID 0x21D9 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_50_HIGH 0x21DA -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_50_RESVD 0x21DB -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_51_LOW 0x21DC -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_51_MID 0x21DD -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_51_HIGH 0x21DE -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_51_RESVD 0x21DF -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_52_LOW 0x21E0 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_52_MID 0x21E1 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_52_HIGH 0x21E2 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_52_RESVD 0x21E3 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_53_LOW 0x21E4 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_53_MID 0x21E5 -#define SUNI1x10GEXP_REG_MSTAT_COUNTER_53_HIGH 0x21E6 -#define SUNI1x10GEXP_CNTR_MAC_ETHERNET_NUM 51 - -#define SUNI1x10GEXP_REG_IFLX_GLOBAL_CONFIG 0x2200 -#define SUNI1x10GEXP_REG_IFLX_CHANNEL_PROVISION 0x2201 -#define SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_ENABLE 0x2209 -#define SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_INTERRUPT 0x220A -#define SUNI1x10GEXP_REG_IFLX_INDIR_CHANNEL_ADDRESS 0x220D -#define SUNI1x10GEXP_REG_IFLX_INDIR_LOGICAL_FIFO_LOW_LIMIT_PROVISION 0x220E -#define SUNI1x10GEXP_REG_IFLX_INDIR_LOGICAL_FIFO_HIGH_LIMIT 0x220F -#define SUNI1x10GEXP_REG_IFLX_INDIR_FULL_ALMOST_FULL_STATUS_LIMIT 0x2210 -#define SUNI1x10GEXP_REG_IFLX_INDIR_EMPTY_ALMOST_EMPTY_STATUS_LIMIT 0x2211 - -#define SUNI1x10GEXP_REG_PL4MOS_CONFIG 0x2240 -#define SUNI1x10GEXP_REG_PL4MOS_MASK 0x2241 -#define SUNI1x10GEXP_REG_PL4MOS_FAIRNESS_MASKING 0x2242 -#define SUNI1x10GEXP_REG_PL4MOS_MAXBURST1 0x2243 -#define SUNI1x10GEXP_REG_PL4MOS_MAXBURST2 0x2244 -#define SUNI1x10GEXP_REG_PL4MOS_TRANSFER_SIZE 0x2245 - -#define SUNI1x10GEXP_REG_PL4ODP_CONFIG 0x2280 -#define SUNI1x10GEXP_REG_PL4ODP_INTERRUPT_MASK 0x2282 -#define SUNI1x10GEXP_REG_PL4ODP_INTERRUPT 0x2283 -#define SUNI1x10GEXP_REG_PL4ODP_CONFIG_MAX_T 0x2284 - -#define SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_STATUS 0x2300 -#define SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_CHANGE 0x2301 -#define SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_MASK 0x2302 -#define SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_LIMITS 0x2303 -#define SUNI1x10GEXP_REG_PL4IO_CALENDAR_REPETITIONS 0x2304 -#define SUNI1x10GEXP_REG_PL4IO_CONFIG 0x2305 - -#define SUNI1x10GEXP_REG_TXXG_CONFIG_1 0x3040 -#define SUNI1x10GEXP_REG_TXXG_CONFIG_2 0x3041 -#define SUNI1x10GEXP_REG_TXXG_CONFIG_3 0x3042 -#define SUNI1x10GEXP_REG_TXXG_INTERRUPT 0x3043 -#define SUNI1x10GEXP_REG_TXXG_STATUS 0x3044 -#define SUNI1x10GEXP_REG_TXXG_MAX_FRAME_SIZE 0x3045 -#define SUNI1x10GEXP_REG_TXXG_MIN_FRAME_SIZE 0x3046 -#define SUNI1x10GEXP_REG_TXXG_SA_15_0 0x3047 -#define SUNI1x10GEXP_REG_TXXG_SA_31_16 0x3048 -#define SUNI1x10GEXP_REG_TXXG_SA_47_32 0x3049 -#define SUNI1x10GEXP_REG_TXXG_PAUSE_TIMER 0x304D -#define SUNI1x10GEXP_REG_TXXG_PAUSE_TIMER_INTERVAL 0x304E -#define SUNI1x10GEXP_REG_TXXG_FILTER_ERROR_COUNTER 0x3051 -#define SUNI1x10GEXP_REG_TXXG_PAUSE_QUANTUM_CONFIG 0x3052 - -#define SUNI1x10GEXP_REG_XTEF_CTRL 0x3080 -#define SUNI1x10GEXP_REG_XTEF_INTERRUPT_STATUS 0x3084 -#define SUNI1x10GEXP_REG_XTEF_INTERRUPT_ENABLE 0x3085 -#define SUNI1x10GEXP_REG_XTEF_VISIBILITY 0x3086 - -#define SUNI1x10GEXP_REG_TXOAM_OAM_CONFIG 0x30C0 -#define SUNI1x10GEXP_REG_TXOAM_MINI_RATE_CONFIG 0x30C1 -#define SUNI1x10GEXP_REG_TXOAM_MINI_GAP_FIFO_CONFIG 0x30C2 -#define SUNI1x10GEXP_REG_TXOAM_P1P2_STATIC_VALUES 0x30C3 -#define SUNI1x10GEXP_REG_TXOAM_P3P4_STATIC_VALUES 0x30C4 -#define SUNI1x10GEXP_REG_TXOAM_P5P6_STATIC_VALUES 0x30C5 -#define SUNI1x10GEXP_REG_TXOAM_INTERRUPT_ENABLE 0x30C6 -#define SUNI1x10GEXP_REG_TXOAM_INTERRUPT_STATUS 0x30C7 -#define SUNI1x10GEXP_REG_TXOAM_INSERT_COUNT_LSB 0x30C8 -#define SUNI1x10GEXP_REG_TXOAM_INSERT_COUNT_MSB 0x30C9 -#define SUNI1x10GEXP_REG_TXOAM_OAM_MINI_COUNT_LSB 0x30CA -#define SUNI1x10GEXP_REG_TXOAM_OAM_MINI_COUNT_MSB 0x30CB -#define SUNI1x10GEXP_REG_TXOAM_P1P2_MINI_MASK 0x30CC -#define SUNI1x10GEXP_REG_TXOAM_P3P4_MINI_MASK 0x30CD -#define SUNI1x10GEXP_REG_TXOAM_P5P6_MINI_MASK 0x30CE -#define SUNI1x10GEXP_REG_TXOAM_COSET 0x30CF -#define SUNI1x10GEXP_REG_TXOAM_EMPTY_FIFO_INS_OP_CNT_LSB 0x30D0 -#define SUNI1x10GEXP_REG_TXOAM_EMPTY_FIFO_INS_OP_CNT_MSB 0x30D1 -#define SUNI1x10GEXP_REG_TXOAM_STATIC_VALUE_MINI_COUNT_LSB 0x30D2 -#define SUNI1x10GEXP_REG_TXOAM_STATIC_VALUE_MINI_COUNT_MSB 0x30D3 - - -#define SUNI1x10GEXP_REG_EFLX_GLOBAL_CONFIG 0x3200 -#define SUNI1x10GEXP_REG_EFLX_ERCU_GLOBAL_STATUS 0x3201 -#define SUNI1x10GEXP_REG_EFLX_INDIR_CHANNEL_ADDRESS 0x3202 -#define SUNI1x10GEXP_REG_EFLX_INDIR_FIFO_LOW_LIMIT 0x3203 -#define SUNI1x10GEXP_REG_EFLX_INDIR_FIFO_HIGH_LIMIT 0x3204 -#define SUNI1x10GEXP_REG_EFLX_INDIR_FULL_ALMOST_FULL_STATUS_AND_LIMIT 0x3205 -#define SUNI1x10GEXP_REG_EFLX_INDIR_EMPTY_ALMOST_EMPTY_STATUS_AND_LIMIT 0x3206 -#define SUNI1x10GEXP_REG_EFLX_INDIR_FIFO_CUT_THROUGH_THRESHOLD 0x3207 -#define SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_ENABLE 0x320C -#define SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_INDICATION 0x320D -#define SUNI1x10GEXP_REG_EFLX_CHANNEL_PROVISION 0x3210 - -#define SUNI1x10GEXP_REG_PL4IDU_CONFIG 0x3280 -#define SUNI1x10GEXP_REG_PL4IDU_INTERRUPT_MASK 0x3282 -#define SUNI1x10GEXP_REG_PL4IDU_INTERRUPT 0x3283 - - -/*----------------------------------------*/ -#define SUNI1x10GEXP_REG_MAX_OFFSET 0x3480 - -/******************************************************************************/ -/* -- End register offset definitions -- */ -/******************************************************************************/ - -/******************************************************************************/ -/** SUNI-1x10GE-XP REGISTER BIT MASKS **/ -/******************************************************************************/ - -#define SUNI1x10GEXP_BITMSK_BITS_1 0x00001 -#define SUNI1x10GEXP_BITMSK_BITS_2 0x00003 -#define SUNI1x10GEXP_BITMSK_BITS_3 0x00007 -#define SUNI1x10GEXP_BITMSK_BITS_4 0x0000f -#define SUNI1x10GEXP_BITMSK_BITS_5 0x0001f -#define SUNI1x10GEXP_BITMSK_BITS_6 0x0003f -#define SUNI1x10GEXP_BITMSK_BITS_7 0x0007f -#define SUNI1x10GEXP_BITMSK_BITS_8 0x000ff -#define SUNI1x10GEXP_BITMSK_BITS_9 0x001ff -#define SUNI1x10GEXP_BITMSK_BITS_10 0x003ff -#define SUNI1x10GEXP_BITMSK_BITS_11 0x007ff -#define SUNI1x10GEXP_BITMSK_BITS_12 0x00fff -#define SUNI1x10GEXP_BITMSK_BITS_13 0x01fff -#define SUNI1x10GEXP_BITMSK_BITS_14 0x03fff -#define SUNI1x10GEXP_BITMSK_BITS_15 0x07fff -#define SUNI1x10GEXP_BITMSK_BITS_16 0x0ffff - -#define mSUNI1x10GEXP_CLR_MSBITS_1(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_15) -#define mSUNI1x10GEXP_CLR_MSBITS_2(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_14) -#define mSUNI1x10GEXP_CLR_MSBITS_3(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_13) -#define mSUNI1x10GEXP_CLR_MSBITS_4(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_12) -#define mSUNI1x10GEXP_CLR_MSBITS_5(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_11) -#define mSUNI1x10GEXP_CLR_MSBITS_6(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_10) -#define mSUNI1x10GEXP_CLR_MSBITS_7(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_9) -#define mSUNI1x10GEXP_CLR_MSBITS_8(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_8) -#define mSUNI1x10GEXP_CLR_MSBITS_9(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_7) -#define mSUNI1x10GEXP_CLR_MSBITS_10(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_6) -#define mSUNI1x10GEXP_CLR_MSBITS_11(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_5) -#define mSUNI1x10GEXP_CLR_MSBITS_12(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_4) -#define mSUNI1x10GEXP_CLR_MSBITS_13(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_3) -#define mSUNI1x10GEXP_CLR_MSBITS_14(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_2) -#define mSUNI1x10GEXP_CLR_MSBITS_15(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_1) - -#define mSUNI1x10GEXP_GET_BIT(val, bitMsk) (((val)&(bitMsk)) ? 1:0) - - - -/*---------------------------------------------------------------------------- - * Register 0x0001: S/UNI-1x10GE-XP Product Revision - * Bit 3-0 REVISION - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_REVISION 0x000F - -/*---------------------------------------------------------------------------- - * Register 0x0002: S/UNI-1x10GE-XP Configuration and Reset Control - * Bit 2 XAUI_ARESETB - * Bit 1 PL4_ARESETB - * Bit 0 DRESETB - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_XAUI_ARESET 0x0004 -#define SUNI1x10GEXP_BITMSK_PL4_ARESET 0x0002 -#define SUNI1x10GEXP_BITMSK_DRESETB 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x0003: S/UNI-1x10GE-XP Loop Back and Miscellaneous Control - * Bit 11 PL4IO_OUTCLKSEL - * Bit 9 SYSPCSLB - * Bit 8 LINEPCSLB - * Bit 7 MSTAT_BYPASS - * Bit 6 RXXG_BYPASS - * Bit 5 TXXG_BYPASS - * Bit 4 SOP_PAD_EN - * Bit 1 LOS_INV - * Bit 0 OVERRIDE_LOS - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_PL4IO_OUTCLKSEL 0x0800 -#define SUNI1x10GEXP_BITMSK_SYSPCSLB 0x0200 -#define SUNI1x10GEXP_BITMSK_LINEPCSLB 0x0100 -#define SUNI1x10GEXP_BITMSK_MSTAT_BYPASS 0x0080 -#define SUNI1x10GEXP_BITMSK_RXXG_BYPASS 0x0040 -#define SUNI1x10GEXP_BITMSK_TXXG_BYPASS 0x0020 -#define SUNI1x10GEXP_BITMSK_SOP_PAD_EN 0x0010 -#define SUNI1x10GEXP_BITMSK_LOS_INV 0x0002 -#define SUNI1x10GEXP_BITMSK_OVERRIDE_LOS 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x0004: S/UNI-1x10GE-XP Device Status - * Bit 9 TOP_SXRA_EXPIRED - * Bit 8 TOP_MDIO_BUSY - * Bit 7 TOP_DTRB - * Bit 6 TOP_EXPIRED - * Bit 5 TOP_PAUSED - * Bit 4 TOP_PL4_ID_DOOL - * Bit 3 TOP_PL4_IS_DOOL - * Bit 2 TOP_PL4_ID_ROOL - * Bit 1 TOP_PL4_IS_ROOL - * Bit 0 TOP_PL4_OUT_ROOL - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_TOP_SXRA_EXPIRED 0x0200 -#define SUNI1x10GEXP_BITMSK_TOP_MDIO_BUSY 0x0100 -#define SUNI1x10GEXP_BITMSK_TOP_DTRB 0x0080 -#define SUNI1x10GEXP_BITMSK_TOP_EXPIRED 0x0040 -#define SUNI1x10GEXP_BITMSK_TOP_PAUSED 0x0020 -#define SUNI1x10GEXP_BITMSK_TOP_PL4_ID_DOOL 0x0010 -#define SUNI1x10GEXP_BITMSK_TOP_PL4_IS_DOOL 0x0008 -#define SUNI1x10GEXP_BITMSK_TOP_PL4_ID_ROOL 0x0004 -#define SUNI1x10GEXP_BITMSK_TOP_PL4_IS_ROOL 0x0002 -#define SUNI1x10GEXP_BITMSK_TOP_PL4_OUT_ROOL 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x0005: Global Performance Update and Clock Monitors - * Bit 15 TIP - * Bit 8 XAUI_REF_CLKA - * Bit 7 RXLANE3CLKA - * Bit 6 RXLANE2CLKA - * Bit 5 RXLANE1CLKA - * Bit 4 RXLANE0CLKA - * Bit 3 CSUCLKA - * Bit 2 TDCLKA - * Bit 1 RSCLKA - * Bit 0 RDCLKA - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_TIP 0x8000 -#define SUNI1x10GEXP_BITMSK_XAUI_REF_CLKA 0x0100 -#define SUNI1x10GEXP_BITMSK_RXLANE3CLKA 0x0080 -#define SUNI1x10GEXP_BITMSK_RXLANE2CLKA 0x0040 -#define SUNI1x10GEXP_BITMSK_RXLANE1CLKA 0x0020 -#define SUNI1x10GEXP_BITMSK_RXLANE0CLKA 0x0010 -#define SUNI1x10GEXP_BITMSK_CSUCLKA 0x0008 -#define SUNI1x10GEXP_BITMSK_TDCLKA 0x0004 -#define SUNI1x10GEXP_BITMSK_RSCLKA 0x0002 -#define SUNI1x10GEXP_BITMSK_RDCLKA 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x0006: MDIO Command - * Bit 4 MDIO_RDINC - * Bit 3 MDIO_RSTAT - * Bit 2 MDIO_LCTLD - * Bit 1 MDIO_LCTLA - * Bit 0 MDIO_SPRE - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_MDIO_RDINC 0x0010 -#define SUNI1x10GEXP_BITMSK_MDIO_RSTAT 0x0008 -#define SUNI1x10GEXP_BITMSK_MDIO_LCTLD 0x0004 -#define SUNI1x10GEXP_BITMSK_MDIO_LCTLA 0x0002 -#define SUNI1x10GEXP_BITMSK_MDIO_SPRE 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x0007: MDIO Interrupt Enable - * Bit 0 MDIO_BUSY_EN - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_MDIO_BUSY_EN 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x0008: MDIO Interrupt Status - * Bit 0 MDIO_BUSYI - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_MDIO_BUSYI 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x0009: MMD PHY Address - * Bit 12-8 MDIO_DEVADR - * Bit 4-0 MDIO_PRTADR - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_MDIO_DEVADR 0x1F00 -#define SUNI1x10GEXP_BITOFF_MDIO_DEVADR 8 -#define SUNI1x10GEXP_BITMSK_MDIO_PRTADR 0x001F -#define SUNI1x10GEXP_BITOFF_MDIO_PRTADR 0 - -/*---------------------------------------------------------------------------- - * Register 0x000C: OAM Interface Control - * Bit 6 MDO_OD_ENB - * Bit 5 MDI_INV - * Bit 4 MDI_SEL - * Bit 3 RXOAMEN - * Bit 2 RXOAMCLKEN - * Bit 1 TXOAMEN - * Bit 0 TXOAMCLKEN - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_MDO_OD_ENB 0x0040 -#define SUNI1x10GEXP_BITMSK_MDI_INV 0x0020 -#define SUNI1x10GEXP_BITMSK_MDI_SEL 0x0010 -#define SUNI1x10GEXP_BITMSK_RXOAMEN 0x0008 -#define SUNI1x10GEXP_BITMSK_RXOAMCLKEN 0x0004 -#define SUNI1x10GEXP_BITMSK_TXOAMEN 0x0002 -#define SUNI1x10GEXP_BITMSK_TXOAMCLKEN 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x000D: S/UNI-1x10GE-XP Master Interrupt Status - * Bit 15 TOP_PL4IO_INT - * Bit 14 TOP_IRAM_INT - * Bit 13 TOP_ERAM_INT - * Bit 12 TOP_XAUI_INT - * Bit 11 TOP_MSTAT_INT - * Bit 10 TOP_RXXG_INT - * Bit 9 TOP_TXXG_INT - * Bit 8 TOP_XRF_INT - * Bit 7 TOP_XTEF_INT - * Bit 6 TOP_MDIO_BUSY_INT - * Bit 5 TOP_RXOAM_INT - * Bit 4 TOP_TXOAM_INT - * Bit 3 TOP_IFLX_INT - * Bit 2 TOP_EFLX_INT - * Bit 1 TOP_PL4ODP_INT - * Bit 0 TOP_PL4IDU_INT - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_TOP_PL4IO_INT 0x8000 -#define SUNI1x10GEXP_BITMSK_TOP_IRAM_INT 0x4000 -#define SUNI1x10GEXP_BITMSK_TOP_ERAM_INT 0x2000 -#define SUNI1x10GEXP_BITMSK_TOP_XAUI_INT 0x1000 -#define SUNI1x10GEXP_BITMSK_TOP_MSTAT_INT 0x0800 -#define SUNI1x10GEXP_BITMSK_TOP_RXXG_INT 0x0400 -#define SUNI1x10GEXP_BITMSK_TOP_TXXG_INT 0x0200 -#define SUNI1x10GEXP_BITMSK_TOP_XRF_INT 0x0100 -#define SUNI1x10GEXP_BITMSK_TOP_XTEF_INT 0x0080 -#define SUNI1x10GEXP_BITMSK_TOP_MDIO_BUSY_INT 0x0040 -#define SUNI1x10GEXP_BITMSK_TOP_RXOAM_INT 0x0020 -#define SUNI1x10GEXP_BITMSK_TOP_TXOAM_INT 0x0010 -#define SUNI1x10GEXP_BITMSK_TOP_IFLX_INT 0x0008 -#define SUNI1x10GEXP_BITMSK_TOP_EFLX_INT 0x0004 -#define SUNI1x10GEXP_BITMSK_TOP_PL4ODP_INT 0x0002 -#define SUNI1x10GEXP_BITMSK_TOP_PL4IDU_INT 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x000E:PM3393 Global interrupt enable - * Bit 15 TOP_INTE - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_TOP_INTE 0x8000 - -/*---------------------------------------------------------------------------- - * Register 0x0010: XTEF Miscellaneous Control - * Bit 7 RF_VAL - * Bit 6 RF_OVERRIDE - * Bit 5 LF_VAL - * Bit 4 LF_OVERRIDE - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_RF_VAL 0x0080 -#define SUNI1x10GEXP_BITMSK_RF_OVERRIDE 0x0040 -#define SUNI1x10GEXP_BITMSK_LF_VAL 0x0020 -#define SUNI1x10GEXP_BITMSK_LF_OVERRIDE 0x0010 -#define SUNI1x10GEXP_BITMSK_LFRF_OVERRIDE_VAL 0x00F0 - -/*---------------------------------------------------------------------------- - * Register 0x0011: XRF Miscellaneous Control - * Bit 6-4 EN_IDLE_REP - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_EN_IDLE_REP 0x0070 - -/*---------------------------------------------------------------------------- - * Register 0x0100: SERDES 3125 Configuration Register 1 - * Bit 10 RXEQB_3 - * Bit 8 RXEQB_2 - * Bit 6 RXEQB_1 - * Bit 4 RXEQB_0 - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_RXEQB 0x0FF0 -#define SUNI1x10GEXP_BITOFF_RXEQB_3 10 -#define SUNI1x10GEXP_BITOFF_RXEQB_2 8 -#define SUNI1x10GEXP_BITOFF_RXEQB_1 6 -#define SUNI1x10GEXP_BITOFF_RXEQB_0 4 - -/*---------------------------------------------------------------------------- - * Register 0x0101: SERDES 3125 Configuration Register 2 - * Bit 12 YSEL - * Bit 7 PRE_EMPH_3 - * Bit 6 PRE_EMPH_2 - * Bit 5 PRE_EMPH_1 - * Bit 4 PRE_EMPH_0 - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_YSEL 0x1000 -#define SUNI1x10GEXP_BITMSK_PRE_EMPH 0x00F0 -#define SUNI1x10GEXP_BITMSK_PRE_EMPH_3 0x0080 -#define SUNI1x10GEXP_BITMSK_PRE_EMPH_2 0x0040 -#define SUNI1x10GEXP_BITMSK_PRE_EMPH_1 0x0020 -#define SUNI1x10GEXP_BITMSK_PRE_EMPH_0 0x0010 - -/*---------------------------------------------------------------------------- - * Register 0x0102: SERDES 3125 Interrupt Enable Register - * Bit 3 LASIE - * Bit 2 SPLL_RAE - * Bit 1 MPLL_RAE - * Bit 0 PLL_LOCKE - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_LASIE 0x0008 -#define SUNI1x10GEXP_BITMSK_SPLL_RAE 0x0004 -#define SUNI1x10GEXP_BITMSK_MPLL_RAE 0x0002 -#define SUNI1x10GEXP_BITMSK_PLL_LOCKE 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x0103: SERDES 3125 Interrupt Visibility Register - * Bit 3 LASIV - * Bit 2 SPLL_RAV - * Bit 1 MPLL_RAV - * Bit 0 PLL_LOCKV - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_LASIV 0x0008 -#define SUNI1x10GEXP_BITMSK_SPLL_RAV 0x0004 -#define SUNI1x10GEXP_BITMSK_MPLL_RAV 0x0002 -#define SUNI1x10GEXP_BITMSK_PLL_LOCKV 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x0104: SERDES 3125 Interrupt Status Register - * Bit 3 LASII - * Bit 2 SPLL_RAI - * Bit 1 MPLL_RAI - * Bit 0 PLL_LOCKI - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_LASII 0x0008 -#define SUNI1x10GEXP_BITMSK_SPLL_RAI 0x0004 -#define SUNI1x10GEXP_BITMSK_MPLL_RAI 0x0002 -#define SUNI1x10GEXP_BITMSK_PLL_LOCKI 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x0107: SERDES 3125 Test Configuration - * Bit 12 DUALTX - * Bit 10 HC_1 - * Bit 9 HC_0 - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_DUALTX 0x1000 -#define SUNI1x10GEXP_BITMSK_HC 0x0600 -#define SUNI1x10GEXP_BITOFF_HC_0 9 - -/*---------------------------------------------------------------------------- - * Register 0x2040: RXXG Configuration 1 - * Bit 15 RXXG_RXEN - * Bit 14 RXXG_ROCF - * Bit 13 RXXG_PAD_STRIP - * Bit 10 RXXG_PUREP - * Bit 9 RXXG_LONGP - * Bit 8 RXXG_PARF - * Bit 7 RXXG_FLCHK - * Bit 5 RXXG_PASS_CTRL - * Bit 3 RXXG_CRC_STRIP - * Bit 2-0 RXXG_MIFG - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_RXXG_RXEN 0x8000 -#define SUNI1x10GEXP_BITMSK_RXXG_ROCF 0x4000 -#define SUNI1x10GEXP_BITMSK_RXXG_PAD_STRIP 0x2000 -#define SUNI1x10GEXP_BITMSK_RXXG_PUREP 0x0400 -#define SUNI1x10GEXP_BITMSK_RXXG_LONGP 0x0200 -#define SUNI1x10GEXP_BITMSK_RXXG_PARF 0x0100 -#define SUNI1x10GEXP_BITMSK_RXXG_FLCHK 0x0080 -#define SUNI1x10GEXP_BITMSK_RXXG_PASS_CTRL 0x0020 -#define SUNI1x10GEXP_BITMSK_RXXG_CRC_STRIP 0x0008 - -/*---------------------------------------------------------------------------- - * Register 0x02041: RXXG Configuration 2 - * Bit 7-0 RXXG_HDRSIZE - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_RXXG_HDRSIZE 0x00FF - -/*---------------------------------------------------------------------------- - * Register 0x2042: RXXG Configuration 3 - * Bit 15 RXXG_MIN_LERRE - * Bit 14 RXXG_MAX_LERRE - * Bit 12 RXXG_LINE_ERRE - * Bit 10 RXXG_RX_OVRE - * Bit 9 RXXG_ADR_FILTERE - * Bit 8 RXXG_ERR_FILTERE - * Bit 5 RXXG_PRMB_ERRE - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_RXXG_MIN_LERRE 0x8000 -#define SUNI1x10GEXP_BITMSK_RXXG_MAX_LERRE 0x4000 -#define SUNI1x10GEXP_BITMSK_RXXG_LINE_ERRE 0x1000 -#define SUNI1x10GEXP_BITMSK_RXXG_RX_OVRE 0x0400 -#define SUNI1x10GEXP_BITMSK_RXXG_ADR_FILTERE 0x0200 -#define SUNI1x10GEXP_BITMSK_RXXG_ERR_FILTERRE 0x0100 -#define SUNI1x10GEXP_BITMSK_RXXG_PRMB_ERRE 0x0020 - -/*---------------------------------------------------------------------------- - * Register 0x2043: RXXG Interrupt - * Bit 15 RXXG_MIN_LERRI - * Bit 14 RXXG_MAX_LERRI - * Bit 12 RXXG_LINE_ERRI - * Bit 10 RXXG_RX_OVRI - * Bit 9 RXXG_ADR_FILTERI - * Bit 8 RXXG_ERR_FILTERI - * Bit 5 RXXG_PRMB_ERRE - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_RXXG_MIN_LERRI 0x8000 -#define SUNI1x10GEXP_BITMSK_RXXG_MAX_LERRI 0x4000 -#define SUNI1x10GEXP_BITMSK_RXXG_LINE_ERRI 0x1000 -#define SUNI1x10GEXP_BITMSK_RXXG_RX_OVRI 0x0400 -#define SUNI1x10GEXP_BITMSK_RXXG_ADR_FILTERI 0x0200 -#define SUNI1x10GEXP_BITMSK_RXXG_ERR_FILTERI 0x0100 -#define SUNI1x10GEXP_BITMSK_RXXG_PRMB_ERRE 0x0020 - -/*---------------------------------------------------------------------------- - * Register 0x2049: RXXG Receive FIFO Threshold - * Bit 2-0 RXXG_CUT_THRU - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_RXXG_CUT_THRU 0x0007 -#define SUNI1x10GEXP_BITOFF_RXXG_CUT_THRU 0 - -/*---------------------------------------------------------------------------- - * Register 0x2062H - 0x2069: RXXG Exact Match VID - * Bit 11-0 RXXG_VID_MATCH - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_RXXG_VID_MATCH 0x0FFF -#define SUNI1x10GEXP_BITOFF_RXXG_VID_MATCH 0 - -/*---------------------------------------------------------------------------- - * Register 0x206EH - 0x206F: RXXG Address Filter Control - * Bit 3 RXXG_FORWARD_ENABLE - * Bit 2 RXXG_VLAN_ENABLE - * Bit 1 RXXG_SRC_ADDR - * Bit 0 RXXG_MATCH_ENABLE - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_RXXG_FORWARD_ENABLE 0x0008 -#define SUNI1x10GEXP_BITMSK_RXXG_VLAN_ENABLE 0x0004 -#define SUNI1x10GEXP_BITMSK_RXXG_SRC_ADDR 0x0002 -#define SUNI1x10GEXP_BITMSK_RXXG_MATCH_ENABLE 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x2070: RXXG Address Filter Control 2 - * Bit 1 RXXG_PMODE - * Bit 0 RXXG_MHASH_EN - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_RXXG_PMODE 0x0002 -#define SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x2081: XRF Control Register 2 - * Bit 6 EN_PKT_GEN - * Bit 4-2 PATT - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_EN_PKT_GEN 0x0040 -#define SUNI1x10GEXP_BITMSK_PATT 0x001C -#define SUNI1x10GEXP_BITOFF_PATT 2 - -/*---------------------------------------------------------------------------- - * Register 0x2088: XRF Interrupt Enable - * Bit 12-9 LANE_HICERE - * Bit 8-5 HS_SD_LANEE - * Bit 4 ALIGN_STATUS_ERRE - * Bit 3-0 LANE_SYNC_STAT_ERRE - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_LANE_HICERE 0x1E00 -#define SUNI1x10GEXP_BITOFF_LANE_HICERE 9 -#define SUNI1x10GEXP_BITMSK_HS_SD_LANEE 0x01E0 -#define SUNI1x10GEXP_BITOFF_HS_SD_LANEE 5 -#define SUNI1x10GEXP_BITMSK_ALIGN_STATUS_ERRE 0x0010 -#define SUNI1x10GEXP_BITMSK_LANE_SYNC_STAT_ERRE 0x000F -#define SUNI1x10GEXP_BITOFF_LANE_SYNC_STAT_ERRE 0 - -/*---------------------------------------------------------------------------- - * Register 0x2089: XRF Interrupt Status - * Bit 12-9 LANE_HICERI - * Bit 8-5 HS_SD_LANEI - * Bit 4 ALIGN_STATUS_ERRI - * Bit 3-0 LANE_SYNC_STAT_ERRI - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_LANE_HICERI 0x1E00 -#define SUNI1x10GEXP_BITOFF_LANE_HICERI 9 -#define SUNI1x10GEXP_BITMSK_HS_SD_LANEI 0x01E0 -#define SUNI1x10GEXP_BITOFF_HS_SD_LANEI 5 -#define SUNI1x10GEXP_BITMSK_ALIGN_STATUS_ERRI 0x0010 -#define SUNI1x10GEXP_BITMSK_LANE_SYNC_STAT_ERRI 0x000F -#define SUNI1x10GEXP_BITOFF_LANE_SYNC_STAT_ERRI 0 - -/*---------------------------------------------------------------------------- - * Register 0x208A: XRF Error Status - * Bit 8-5 HS_SD_LANE - * Bit 4 ALIGN_STATUS_ERR - * Bit 3-0 LANE_SYNC_STAT_ERR - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_HS_SD_LANE3 0x0100 -#define SUNI1x10GEXP_BITMSK_HS_SD_LANE2 0x0080 -#define SUNI1x10GEXP_BITMSK_HS_SD_LANE1 0x0040 -#define SUNI1x10GEXP_BITMSK_HS_SD_LANE0 0x0020 -#define SUNI1x10GEXP_BITMSK_ALIGN_STATUS_ERR 0x0010 -#define SUNI1x10GEXP_BITMSK_LANE3_SYNC_STAT_ERR 0x0008 -#define SUNI1x10GEXP_BITMSK_LANE2_SYNC_STAT_ERR 0x0004 -#define SUNI1x10GEXP_BITMSK_LANE1_SYNC_STAT_ERR 0x0002 -#define SUNI1x10GEXP_BITMSK_LANE0_SYNC_STAT_ERR 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x208B: XRF Diagnostic Interrupt Enable - * Bit 7-4 LANE_OVERRUNE - * Bit 3-0 LANE_UNDERRUNE - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_LANE_OVERRUNE 0x00F0 -#define SUNI1x10GEXP_BITOFF_LANE_OVERRUNE 4 -#define SUNI1x10GEXP_BITMSK_LANE_UNDERRUNE 0x000F -#define SUNI1x10GEXP_BITOFF_LANE_UNDERRUNE 0 - -/*---------------------------------------------------------------------------- - * Register 0x208C: XRF Diagnostic Interrupt Status - * Bit 7-4 LANE_OVERRUNI - * Bit 3-0 LANE_UNDERRUNI - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_LANE_OVERRUNI 0x00F0 -#define SUNI1x10GEXP_BITOFF_LANE_OVERRUNI 4 -#define SUNI1x10GEXP_BITMSK_LANE_UNDERRUNI 0x000F -#define SUNI1x10GEXP_BITOFF_LANE_UNDERRUNI 0 - -/*---------------------------------------------------------------------------- - * Register 0x20C0: RXOAM Configuration - * Bit 15 RXOAM_BUSY - * Bit 14-12 RXOAM_F2_SEL - * Bit 10-8 RXOAM_F1_SEL - * Bit 7-6 RXOAM_FILTER_CTRL - * Bit 5-0 RXOAM_PX_EN - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_RXOAM_BUSY 0x8000 -#define SUNI1x10GEXP_BITMSK_RXOAM_F2_SEL 0x7000 -#define SUNI1x10GEXP_BITOFF_RXOAM_F2_SEL 12 -#define SUNI1x10GEXP_BITMSK_RXOAM_F1_SEL 0x0700 -#define SUNI1x10GEXP_BITOFF_RXOAM_F1_SEL 8 -#define SUNI1x10GEXP_BITMSK_RXOAM_FILTER_CTRL 0x00C0 -#define SUNI1x10GEXP_BITOFF_RXOAM_FILTER_CTRL 6 -#define SUNI1x10GEXP_BITMSK_RXOAM_PX_EN 0x003F -#define SUNI1x10GEXP_BITOFF_RXOAM_PX_EN 0 - -/*---------------------------------------------------------------------------- - * Register 0x20C1,0x20C2: RXOAM Filter Configuration - * Bit 15-8 RXOAM_FX_MASK - * Bit 7-0 RXOAM_FX_VAL - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_RXOAM_FX_MASK 0xFF00 -#define SUNI1x10GEXP_BITOFF_RXOAM_FX_MASK 8 -#define SUNI1x10GEXP_BITMSK_RXOAM_FX_VAL 0x00FF -#define SUNI1x10GEXP_BITOFF_RXOAM_FX_VAl 0 - -/*---------------------------------------------------------------------------- - * Register 0x20C3: RXOAM Configuration Register 2 - * Bit 13 RXOAM_REC_BYTE_VAL - * Bit 11-10 RXOAM_BYPASS_MODE - * Bit 5-0 RXOAM_PX_CLEAR - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_RXOAM_REC_BYTE_VAL 0x2000 -#define SUNI1x10GEXP_BITMSK_RXOAM_BYPASS_MODE 0x0C00 -#define SUNI1x10GEXP_BITOFF_RXOAM_BYPASS_MODE 10 -#define SUNI1x10GEXP_BITMSK_RXOAM_PX_CLEAR 0x003F -#define SUNI1x10GEXP_BITOFF_RXOAM_PX_CLEAR 0 - -/*---------------------------------------------------------------------------- - * Register 0x20C4: RXOAM HEC Configuration - * Bit 15-8 RXOAM_COSET - * Bit 2 RXOAM_HEC_ERR_PKT - * Bit 0 RXOAM_HEC_EN - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_RXOAM_COSET 0xFF00 -#define SUNI1x10GEXP_BITOFF_RXOAM_COSET 8 -#define SUNI1x10GEXP_BITMSK_RXOAM_HEC_ERR_PKT 0x0004 -#define SUNI1x10GEXP_BITMSK_RXOAM_HEC_EN 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x20C7: RXOAM Interrupt Enable - * Bit 10 RXOAM_FILTER_THRSHE - * Bit 9 RXOAM_OAM_ERRE - * Bit 8 RXOAM_HECE_THRSHE - * Bit 7 RXOAM_SOPE - * Bit 6 RXOAM_RFE - * Bit 5 RXOAM_LFE - * Bit 4 RXOAM_DV_ERRE - * Bit 3 RXOAM_DATA_INVALIDE - * Bit 2 RXOAM_FILTER_DROPE - * Bit 1 RXOAM_HECE - * Bit 0 RXOAM_OFLE - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_RXOAM_FILTER_THRSHE 0x0400 -#define SUNI1x10GEXP_BITMSK_RXOAM_OAM_ERRE 0x0200 -#define SUNI1x10GEXP_BITMSK_RXOAM_HECE_THRSHE 0x0100 -#define SUNI1x10GEXP_BITMSK_RXOAM_SOPE 0x0080 -#define SUNI1x10GEXP_BITMSK_RXOAM_RFE 0x0040 -#define SUNI1x10GEXP_BITMSK_RXOAM_LFE 0x0020 -#define SUNI1x10GEXP_BITMSK_RXOAM_DV_ERRE 0x0010 -#define SUNI1x10GEXP_BITMSK_RXOAM_DATA_INVALIDE 0x0008 -#define SUNI1x10GEXP_BITMSK_RXOAM_FILTER_DROPE 0x0004 -#define SUNI1x10GEXP_BITMSK_RXOAM_HECE 0x0002 -#define SUNI1x10GEXP_BITMSK_RXOAM_OFLE 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x20C8: RXOAM Interrupt Status - * Bit 10 RXOAM_FILTER_THRSHI - * Bit 9 RXOAM_OAM_ERRI - * Bit 8 RXOAM_HECE_THRSHI - * Bit 7 RXOAM_SOPI - * Bit 6 RXOAM_RFI - * Bit 5 RXOAM_LFI - * Bit 4 RXOAM_DV_ERRI - * Bit 3 RXOAM_DATA_INVALIDI - * Bit 2 RXOAM_FILTER_DROPI - * Bit 1 RXOAM_HECI - * Bit 0 RXOAM_OFLI - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_RXOAM_FILTER_THRSHI 0x0400 -#define SUNI1x10GEXP_BITMSK_RXOAM_OAM_ERRI 0x0200 -#define SUNI1x10GEXP_BITMSK_RXOAM_HECE_THRSHI 0x0100 -#define SUNI1x10GEXP_BITMSK_RXOAM_SOPI 0x0080 -#define SUNI1x10GEXP_BITMSK_RXOAM_RFI 0x0040 -#define SUNI1x10GEXP_BITMSK_RXOAM_LFI 0x0020 -#define SUNI1x10GEXP_BITMSK_RXOAM_DV_ERRI 0x0010 -#define SUNI1x10GEXP_BITMSK_RXOAM_DATA_INVALIDI 0x0008 -#define SUNI1x10GEXP_BITMSK_RXOAM_FILTER_DROPI 0x0004 -#define SUNI1x10GEXP_BITMSK_RXOAM_HECI 0x0002 -#define SUNI1x10GEXP_BITMSK_RXOAM_OFLI 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x20C9: RXOAM Status - * Bit 10 RXOAM_FILTER_THRSHV - * Bit 8 RXOAM_HECE_THRSHV - * Bit 6 RXOAM_RFV - * Bit 5 RXOAM_LFV - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_RXOAM_FILTER_THRSHV 0x0400 -#define SUNI1x10GEXP_BITMSK_RXOAM_HECE_THRSHV 0x0100 -#define SUNI1x10GEXP_BITMSK_RXOAM_RFV 0x0040 -#define SUNI1x10GEXP_BITMSK_RXOAM_LFV 0x0020 - -/*---------------------------------------------------------------------------- - * Register 0x2100: MSTAT Control - * Bit 2 MSTAT_WRITE - * Bit 1 MSTAT_CLEAR - * Bit 0 MSTAT_SNAP - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_MSTAT_WRITE 0x0004 -#define SUNI1x10GEXP_BITMSK_MSTAT_CLEAR 0x0002 -#define SUNI1x10GEXP_BITMSK_MSTAT_SNAP 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x2109: MSTAT Counter Write Address - * Bit 5-0 MSTAT_WRITE_ADDRESS - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_MSTAT_WRITE_ADDRESS 0x003F -#define SUNI1x10GEXP_BITOFF_MSTAT_WRITE_ADDRESS 0 - -/*---------------------------------------------------------------------------- - * Register 0x2200: IFLX Global Configuration Register - * Bit 15 IFLX_IRCU_ENABLE - * Bit 14 IFLX_IDSWT_ENABLE - * Bit 13-0 IFLX_IFD_CNT - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_IFLX_IRCU_ENABLE 0x8000 -#define SUNI1x10GEXP_BITMSK_IFLX_IDSWT_ENABLE 0x4000 -#define SUNI1x10GEXP_BITMSK_IFLX_IFD_CNT 0x3FFF -#define SUNI1x10GEXP_BITOFF_IFLX_IFD_CNT 0 - -/*---------------------------------------------------------------------------- - * Register 0x2209: IFLX FIFO Overflow Enable - * Bit 0 IFLX_OVFE - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_IFLX_OVFE 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x220A: IFLX FIFO Overflow Interrupt - * Bit 0 IFLX_OVFI - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_IFLX_OVFI 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x220D: IFLX Indirect Channel Address - * Bit 15 IFLX_BUSY - * Bit 14 IFLX_RWB - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_IFLX_BUSY 0x8000 -#define SUNI1x10GEXP_BITMSK_IFLX_RWB 0x4000 - -/*---------------------------------------------------------------------------- - * Register 0x220E: IFLX Indirect Logical FIFO Low Limit & Provision - * Bit 9-0 IFLX_LOLIM - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_IFLX_LOLIM 0x03FF -#define SUNI1x10GEXP_BITOFF_IFLX_LOLIM 0 - -/*---------------------------------------------------------------------------- - * Register 0x220F: IFLX Indirect Logical FIFO High Limit - * Bit 9-0 IFLX_HILIM - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_IFLX_HILIM 0x03FF -#define SUNI1x10GEXP_BITOFF_IFLX_HILIM 0 - -/*---------------------------------------------------------------------------- - * Register 0x2210: IFLX Indirect Full/Almost Full Status & Limit - * Bit 15 IFLX_FULL - * Bit 14 IFLX_AFULL - * Bit 13-0 IFLX_AFTH - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_IFLX_FULL 0x8000 -#define SUNI1x10GEXP_BITMSK_IFLX_AFULL 0x4000 -#define SUNI1x10GEXP_BITMSK_IFLX_AFTH 0x3FFF -#define SUNI1x10GEXP_BITOFF_IFLX_AFTH 0 - -/*---------------------------------------------------------------------------- - * Register 0x2211: IFLX Indirect Empty/Almost Empty Status & Limit - * Bit 15 IFLX_EMPTY - * Bit 14 IFLX_AEMPTY - * Bit 13-0 IFLX_AETH - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_IFLX_EMPTY 0x8000 -#define SUNI1x10GEXP_BITMSK_IFLX_AEMPTY 0x4000 -#define SUNI1x10GEXP_BITMSK_IFLX_AETH 0x3FFF -#define SUNI1x10GEXP_BITOFF_IFLX_AETH 0 - -/*---------------------------------------------------------------------------- - * Register 0x2240: PL4MOS Configuration Register - * Bit 3 PL4MOS_RE_INIT - * Bit 2 PL4MOS_EN - * Bit 1 PL4MOS_NO_STATUS - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_PL4MOS_RE_INIT 0x0008 -#define SUNI1x10GEXP_BITMSK_PL4MOS_EN 0x0004 -#define SUNI1x10GEXP_BITMSK_PL4MOS_NO_STATUS 0x0002 - -/*---------------------------------------------------------------------------- - * Register 0x2243: PL4MOS MaxBurst1 Register - * Bit 11-0 PL4MOS_MAX_BURST1 - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_PL4MOS_MAX_BURST1 0x0FFF -#define SUNI1x10GEXP_BITOFF_PL4MOS_MAX_BURST1 0 - -/*---------------------------------------------------------------------------- - * Register 0x2244: PL4MOS MaxBurst2 Register - * Bit 11-0 PL4MOS_MAX_BURST2 - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_PL4MOS_MAX_BURST2 0x0FFF -#define SUNI1x10GEXP_BITOFF_PL4MOS_MAX_BURST2 0 - -/*---------------------------------------------------------------------------- - * Register 0x2245: PL4MOS Transfer Size Register - * Bit 7-0 PL4MOS_MAX_TRANSFER - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_PL4MOS_MAX_TRANSFER 0x00FF -#define SUNI1x10GEXP_BITOFF_PL4MOS_MAX_TRANSFER 0 - -/*---------------------------------------------------------------------------- - * Register 0x2280: PL4ODP Configuration - * Bit 15-12 PL4ODP_REPEAT_T - * Bit 8 PL4ODP_SOP_RULE - * Bit 1 PL4ODP_EN_PORTS - * Bit 0 PL4ODP_EN_DFWD - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_PL4ODP_REPEAT_T 0xF000 -#define SUNI1x10GEXP_BITOFF_PL4ODP_REPEAT_T 12 -#define SUNI1x10GEXP_BITMSK_PL4ODP_SOP_RULE 0x0100 -#define SUNI1x10GEXP_BITMSK_PL4ODP_EN_PORTS 0x0002 -#define SUNI1x10GEXP_BITMSK_PL4ODP_EN_DFWD 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x2282: PL4ODP Interrupt Mask - * Bit 0 PL4ODP_OUT_DISE - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_PL4ODP_OUT_DISE 0x0001 - - - -#define SUNI1x10GEXP_BITMSK_PL4ODP_PPE_EOPEOBE 0x0080 -#define SUNI1x10GEXP_BITMSK_PL4ODP_PPE_ERREOPE 0x0040 -#define SUNI1x10GEXP_BITMSK_PL4ODP_PPE_MEOPE 0x0008 -#define SUNI1x10GEXP_BITMSK_PL4ODP_PPE_MSOPE 0x0004 -#define SUNI1x10GEXP_BITMSK_PL4ODP_ES_OVRE 0x0002 - - -/*---------------------------------------------------------------------------- - * Register 0x2283: PL4ODP Interrupt - * Bit 0 PL4ODP_OUT_DISI - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_PL4ODP_OUT_DISI 0x0001 - - - -#define SUNI1x10GEXP_BITMSK_PL4ODP_PPE_EOPEOBI 0x0080 -#define SUNI1x10GEXP_BITMSK_PL4ODP_PPE_ERREOPI 0x0040 -#define SUNI1x10GEXP_BITMSK_PL4ODP_PPE_MEOPI 0x0008 -#define SUNI1x10GEXP_BITMSK_PL4ODP_PPE_MSOPI 0x0004 -#define SUNI1x10GEXP_BITMSK_PL4ODP_ES_OVRI 0x0002 - -/*---------------------------------------------------------------------------- - * Register 0x2300: PL4IO Lock Detect Status - * Bit 15 PL4IO_OUT_ROOLV - * Bit 12 PL4IO_IS_ROOLV - * Bit 11 PL4IO_DIP2_ERRV - * Bit 8 PL4IO_ID_ROOLV - * Bit 4 PL4IO_IS_DOOLV - * Bit 0 PL4IO_ID_DOOLV - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_PL4IO_OUT_ROOLV 0x8000 -#define SUNI1x10GEXP_BITMSK_PL4IO_IS_ROOLV 0x1000 -#define SUNI1x10GEXP_BITMSK_PL4IO_DIP2_ERRV 0x0800 -#define SUNI1x10GEXP_BITMSK_PL4IO_ID_ROOLV 0x0100 -#define SUNI1x10GEXP_BITMSK_PL4IO_IS_DOOLV 0x0010 -#define SUNI1x10GEXP_BITMSK_PL4IO_ID_DOOLV 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x2301: PL4IO Lock Detect Change - * Bit 15 PL4IO_OUT_ROOLI - * Bit 12 PL4IO_IS_ROOLI - * Bit 11 PL4IO_DIP2_ERRI - * Bit 8 PL4IO_ID_ROOLI - * Bit 4 PL4IO_IS_DOOLI - * Bit 0 PL4IO_ID_DOOLI - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_PL4IO_OUT_ROOLI 0x8000 -#define SUNI1x10GEXP_BITMSK_PL4IO_IS_ROOLI 0x1000 -#define SUNI1x10GEXP_BITMSK_PL4IO_DIP2_ERRI 0x0800 -#define SUNI1x10GEXP_BITMSK_PL4IO_ID_ROOLI 0x0100 -#define SUNI1x10GEXP_BITMSK_PL4IO_IS_DOOLI 0x0010 -#define SUNI1x10GEXP_BITMSK_PL4IO_ID_DOOLI 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x2302: PL4IO Lock Detect Mask - * Bit 15 PL4IO_OUT_ROOLE - * Bit 12 PL4IO_IS_ROOLE - * Bit 11 PL4IO_DIP2_ERRE - * Bit 8 PL4IO_ID_ROOLE - * Bit 4 PL4IO_IS_DOOLE - * Bit 0 PL4IO_ID_DOOLE - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_PL4IO_OUT_ROOLE 0x8000 -#define SUNI1x10GEXP_BITMSK_PL4IO_IS_ROOLE 0x1000 -#define SUNI1x10GEXP_BITMSK_PL4IO_DIP2_ERRE 0x0800 -#define SUNI1x10GEXP_BITMSK_PL4IO_ID_ROOLE 0x0100 -#define SUNI1x10GEXP_BITMSK_PL4IO_IS_DOOLE 0x0010 -#define SUNI1x10GEXP_BITMSK_PL4IO_ID_DOOLE 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x2303: PL4IO Lock Detect Limits - * Bit 15-8 PL4IO_REF_LIMIT - * Bit 7-0 PL4IO_TRAN_LIMIT - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_PL4IO_REF_LIMIT 0xFF00 -#define SUNI1x10GEXP_BITOFF_PL4IO_REF_LIMIT 8 -#define SUNI1x10GEXP_BITMSK_PL4IO_TRAN_LIMIT 0x00FF -#define SUNI1x10GEXP_BITOFF_PL4IO_TRAN_LIMIT 0 - -/*---------------------------------------------------------------------------- - * Register 0x2304: PL4IO Calendar Repetitions - * Bit 15-8 PL4IO_IN_MUL - * Bit 7-0 PL4IO_OUT_MUL - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_PL4IO_IN_MUL 0xFF00 -#define SUNI1x10GEXP_BITOFF_PL4IO_IN_MUL 8 -#define SUNI1x10GEXP_BITMSK_PL4IO_OUT_MUL 0x00FF -#define SUNI1x10GEXP_BITOFF_PL4IO_OUT_MUL 0 - -/*---------------------------------------------------------------------------- - * Register 0x2305: PL4IO Configuration - * Bit 15 PL4IO_DIP2_ERR_CHK - * Bit 11 PL4IO_ODAT_DIS - * Bit 10 PL4IO_TRAIN_DIS - * Bit 9 PL4IO_OSTAT_DIS - * Bit 8 PL4IO_ISTAT_DIS - * Bit 7 PL4IO_NO_ISTAT - * Bit 6 PL4IO_STAT_OUTSEL - * Bit 5 PL4IO_INSEL - * Bit 4 PL4IO_DLSEL - * Bit 1-0 PL4IO_OUTSEL - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_PL4IO_DIP2_ERR_CHK 0x8000 -#define SUNI1x10GEXP_BITMSK_PL4IO_ODAT_DIS 0x0800 -#define SUNI1x10GEXP_BITMSK_PL4IO_TRAIN_DIS 0x0400 -#define SUNI1x10GEXP_BITMSK_PL4IO_OSTAT_DIS 0x0200 -#define SUNI1x10GEXP_BITMSK_PL4IO_ISTAT_DIS 0x0100 -#define SUNI1x10GEXP_BITMSK_PL4IO_NO_ISTAT 0x0080 -#define SUNI1x10GEXP_BITMSK_PL4IO_STAT_OUTSEL 0x0040 -#define SUNI1x10GEXP_BITMSK_PL4IO_INSEL 0x0020 -#define SUNI1x10GEXP_BITMSK_PL4IO_DLSEL 0x0010 -#define SUNI1x10GEXP_BITMSK_PL4IO_OUTSEL 0x0003 -#define SUNI1x10GEXP_BITOFF_PL4IO_OUTSEL 0 - -/*---------------------------------------------------------------------------- - * Register 0x3040: TXXG Configuration Register 1 - * Bit 15 TXXG_TXEN0 - * Bit 13 TXXG_HOSTPAUSE - * Bit 12-7 TXXG_IPGT - * Bit 5 TXXG_32BIT_ALIGN - * Bit 4 TXXG_CRCEN - * Bit 3 TXXG_FCTX - * Bit 2 TXXG_FCRX - * Bit 1 TXXG_PADEN - * Bit 0 TXXG_SPRE - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_TXXG_TXEN0 0x8000 -#define SUNI1x10GEXP_BITMSK_TXXG_HOSTPAUSE 0x2000 -#define SUNI1x10GEXP_BITMSK_TXXG_IPGT 0x1F80 -#define SUNI1x10GEXP_BITOFF_TXXG_IPGT 7 -#define SUNI1x10GEXP_BITMSK_TXXG_32BIT_ALIGN 0x0020 -#define SUNI1x10GEXP_BITMSK_TXXG_CRCEN 0x0010 -#define SUNI1x10GEXP_BITMSK_TXXG_FCTX 0x0008 -#define SUNI1x10GEXP_BITMSK_TXXG_FCRX 0x0004 -#define SUNI1x10GEXP_BITMSK_TXXG_PADEN 0x0002 -#define SUNI1x10GEXP_BITMSK_TXXG_SPRE 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x3041: TXXG Configuration Register 2 - * Bit 7-0 TXXG_HDRSIZE - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_TXXG_HDRSIZE 0x00FF - -/*---------------------------------------------------------------------------- - * Register 0x3042: TXXG Configuration Register 3 - * Bit 15 TXXG_FIFO_ERRE - * Bit 14 TXXG_FIFO_UDRE - * Bit 13 TXXG_MAX_LERRE - * Bit 12 TXXG_MIN_LERRE - * Bit 11 TXXG_XFERE - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_TXXG_FIFO_ERRE 0x8000 -#define SUNI1x10GEXP_BITMSK_TXXG_FIFO_UDRE 0x4000 -#define SUNI1x10GEXP_BITMSK_TXXG_MAX_LERRE 0x2000 -#define SUNI1x10GEXP_BITMSK_TXXG_MIN_LERRE 0x1000 -#define SUNI1x10GEXP_BITMSK_TXXG_XFERE 0x0800 - -/*---------------------------------------------------------------------------- - * Register 0x3043: TXXG Interrupt - * Bit 15 TXXG_FIFO_ERRI - * Bit 14 TXXG_FIFO_UDRI - * Bit 13 TXXG_MAX_LERRI - * Bit 12 TXXG_MIN_LERRI - * Bit 11 TXXG_XFERI - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_TXXG_FIFO_ERRI 0x8000 -#define SUNI1x10GEXP_BITMSK_TXXG_FIFO_UDRI 0x4000 -#define SUNI1x10GEXP_BITMSK_TXXG_MAX_LERRI 0x2000 -#define SUNI1x10GEXP_BITMSK_TXXG_MIN_LERRI 0x1000 -#define SUNI1x10GEXP_BITMSK_TXXG_XFERI 0x0800 - -/*---------------------------------------------------------------------------- - * Register 0x3044: TXXG Status Register - * Bit 1 TXXG_TXACTIVE - * Bit 0 TXXG_PAUSED - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_TXXG_TXACTIVE 0x0002 -#define SUNI1x10GEXP_BITMSK_TXXG_PAUSED 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x3046: TXXG TX_MINFR - Transmit Min Frame Size Register - * Bit 7-0 TXXG_TX_MINFR - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_TXXG_TX_MINFR 0x00FF -#define SUNI1x10GEXP_BITOFF_TXXG_TX_MINFR 0 - -/*---------------------------------------------------------------------------- - * Register 0x3052: TXXG Pause Quantum Value Configuration Register - * Bit 7-0 TXXG_FC_PAUSE_QNTM - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_TXXG_FC_PAUSE_QNTM 0x00FF -#define SUNI1x10GEXP_BITOFF_TXXG_FC_PAUSE_QNTM 0 - -/*---------------------------------------------------------------------------- - * Register 0x3080: XTEF Control - * Bit 3-0 XTEF_FORCE_PARITY_ERR - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_XTEF_FORCE_PARITY_ERR 0x000F -#define SUNI1x10GEXP_BITOFF_XTEF_FORCE_PARITY_ERR 0 - -/*---------------------------------------------------------------------------- - * Register 0x3084: XTEF Interrupt Event Register - * Bit 0 XTEF_LOST_SYNCI - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_XTEF_LOST_SYNCI 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x3085: XTEF Interrupt Enable Register - * Bit 0 XTEF_LOST_SYNCE - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_XTEF_LOST_SYNCE 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x3086: XTEF Visibility Register - * Bit 0 XTEF_LOST_SYNCV - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_XTEF_LOST_SYNCV 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x30C0: TXOAM OAM Configuration - * Bit 15 TXOAM_HEC_EN - * Bit 14 TXOAM_EMPTYCODE_EN - * Bit 13 TXOAM_FORCE_IDLE - * Bit 12 TXOAM_IGNORE_IDLE - * Bit 11-6 TXOAM_PX_OVERWRITE - * Bit 5-0 TXOAM_PX_SEL - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_TXOAM_HEC_EN 0x8000 -#define SUNI1x10GEXP_BITMSK_TXOAM_EMPTYCODE_EN 0x4000 -#define SUNI1x10GEXP_BITMSK_TXOAM_FORCE_IDLE 0x2000 -#define SUNI1x10GEXP_BITMSK_TXOAM_IGNORE_IDLE 0x1000 -#define SUNI1x10GEXP_BITMSK_TXOAM_PX_OVERWRITE 0x0FC0 -#define SUNI1x10GEXP_BITOFF_TXOAM_PX_OVERWRITE 6 -#define SUNI1x10GEXP_BITMSK_TXOAM_PX_SEL 0x003F -#define SUNI1x10GEXP_BITOFF_TXOAM_PX_SEL 0 - -/*---------------------------------------------------------------------------- - * Register 0x30C1: TXOAM Mini-Packet Rate Configuration - * Bit 15 TXOAM_MINIDIS - * Bit 14 TXOAM_BUSY - * Bit 13 TXOAM_TRANS_EN - * Bit 10-0 TXOAM_MINIRATE - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_TXOAM_MINIDIS 0x8000 -#define SUNI1x10GEXP_BITMSK_TXOAM_BUSY 0x4000 -#define SUNI1x10GEXP_BITMSK_TXOAM_TRANS_EN 0x2000 -#define SUNI1x10GEXP_BITMSK_TXOAM_MINIRATE 0x07FF - -/*---------------------------------------------------------------------------- - * Register 0x30C2: TXOAM Mini-Packet Gap and FIFO Configuration - * Bit 13-10 TXOAM_FTHRESH - * Bit 9-6 TXOAM_MINIPOST - * Bit 5-0 TXOAM_MINIPRE - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_TXOAM_FTHRESH 0x3C00 -#define SUNI1x10GEXP_BITOFF_TXOAM_FTHRESH 10 -#define SUNI1x10GEXP_BITMSK_TXOAM_MINIPOST 0x03C0 -#define SUNI1x10GEXP_BITOFF_TXOAM_MINIPOST 6 -#define SUNI1x10GEXP_BITMSK_TXOAM_MINIPRE 0x003F - -/*---------------------------------------------------------------------------- - * Register 0x30C6: TXOAM Interrupt Enable - * Bit 2 TXOAM_SOP_ERRE - * Bit 1 TXOAM_OFLE - * Bit 0 TXOAM_ERRE - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_TXOAM_SOP_ERRE 0x0004 -#define SUNI1x10GEXP_BITMSK_TXOAM_OFLE 0x0002 -#define SUNI1x10GEXP_BITMSK_TXOAM_ERRE 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x30C7: TXOAM Interrupt Status - * Bit 2 TXOAM_SOP_ERRI - * Bit 1 TXOAM_OFLI - * Bit 0 TXOAM_ERRI - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_TXOAM_SOP_ERRI 0x0004 -#define SUNI1x10GEXP_BITMSK_TXOAM_OFLI 0x0002 -#define SUNI1x10GEXP_BITMSK_TXOAM_ERRI 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x30CF: TXOAM Coset - * Bit 7-0 TXOAM_COSET - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_TXOAM_COSET 0x00FF - -/*---------------------------------------------------------------------------- - * Register 0x3200: EFLX Global Configuration - * Bit 15 EFLX_ERCU_EN - * Bit 7 EFLX_EN_EDSWT - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_EFLX_ERCU_EN 0x8000 -#define SUNI1x10GEXP_BITMSK_EFLX_EN_EDSWT 0x0080 - -/*---------------------------------------------------------------------------- - * Register 0x3201: EFLX ERCU Global Status - * Bit 13 EFLX_OVF_ERR - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_EFLX_OVF_ERR 0x2000 - -/*---------------------------------------------------------------------------- - * Register 0x3202: EFLX Indirect Channel Address - * Bit 15 EFLX_BUSY - * Bit 14 EFLX_RDWRB - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_EFLX_BUSY 0x8000 -#define SUNI1x10GEXP_BITMSK_EFLX_RDWRB 0x4000 - -/*---------------------------------------------------------------------------- - * Register 0x3203: EFLX Indirect Logical FIFO Low Limit - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_EFLX_LOLIM 0x03FF -#define SUNI1x10GEXP_BITOFF_EFLX_LOLIM 0 - -/*---------------------------------------------------------------------------- - * Register 0x3204: EFLX Indirect Logical FIFO High Limit - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_EFLX_HILIM 0x03FF -#define SUNI1x10GEXP_BITOFF_EFLX_HILIM 0 - -/*---------------------------------------------------------------------------- - * Register 0x3205: EFLX Indirect Full/Almost-Full Status and Limit - * Bit 15 EFLX_FULL - * Bit 14 EFLX_AFULL - * Bit 13-0 EFLX_AFTH - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_EFLX_FULL 0x8000 -#define SUNI1x10GEXP_BITMSK_EFLX_AFULL 0x4000 -#define SUNI1x10GEXP_BITMSK_EFLX_AFTH 0x3FFF -#define SUNI1x10GEXP_BITOFF_EFLX_AFTH 0 - -/*---------------------------------------------------------------------------- - * Register 0x3206: EFLX Indirect Empty/Almost-Empty Status and Limit - * Bit 15 EFLX_EMPTY - * Bit 14 EFLX_AEMPTY - * Bit 13-0 EFLX_AETH - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_EFLX_EMPTY 0x8000 -#define SUNI1x10GEXP_BITMSK_EFLX_AEMPTY 0x4000 -#define SUNI1x10GEXP_BITMSK_EFLX_AETH 0x3FFF -#define SUNI1x10GEXP_BITOFF_EFLX_AETH 0 - -/*---------------------------------------------------------------------------- - * Register 0x3207: EFLX Indirect FIFO Cut-Through Threshold - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_EFLX_CUT_THRU 0x3FFF -#define SUNI1x10GEXP_BITOFF_EFLX_CUT_THRU 0 - -/*---------------------------------------------------------------------------- - * Register 0x320C: EFLX FIFO Overflow Error Enable - * Bit 0 EFLX_OVFE - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_EFLX_OVFE 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x320D: EFLX FIFO Overflow Error Indication - * Bit 0 EFLX_OVFI - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_EFLX_OVFI 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x3210: EFLX Channel Provision - * Bit 0 EFLX_PROV - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_EFLX_PROV 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x3280: PL4IDU Configuration - * Bit 2 PL4IDU_SYNCH_ON_TRAIN - * Bit 1 PL4IDU_EN_PORTS - * Bit 0 PL4IDU_EN_DFWD - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_PL4IDU_SYNCH_ON_TRAIN 0x0004 -#define SUNI1x10GEXP_BITMSK_PL4IDU_EN_PORTS 0x0002 -#define SUNI1x10GEXP_BITMSK_PL4IDU_EN_DFWD 0x0001 - -/*---------------------------------------------------------------------------- - * Register 0x3282: PL4IDU Interrupt Mask - * Bit 1 PL4IDU_DIP4E - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_PL4IDU_DIP4E 0x0002 - -/*---------------------------------------------------------------------------- - * Register 0x3283: PL4IDU Interrupt - * Bit 1 PL4IDU_DIP4I - *----------------------------------------------------------------------------*/ -#define SUNI1x10GEXP_BITMSK_PL4IDU_DIP4I 0x0002 - -#endif /* _CXGB_SUNI1x10GEXP_REGS_H_ */ - diff --git a/drivers/net/chelsio/tp.c b/drivers/net/chelsio/tp.c deleted file mode 100644 index 8bed4a59e65f..000000000000 --- a/drivers/net/chelsio/tp.c +++ /dev/null @@ -1,171 +0,0 @@ -/* $Date: 2006/02/07 04:21:54 $ $RCSfile: tp.c,v $ $Revision: 1.73 $ */ -#include "common.h" -#include "regs.h" -#include "tp.h" -#ifdef CONFIG_CHELSIO_T1_1G -#include "fpga_defs.h" -#endif - -struct petp { - adapter_t *adapter; -}; - -/* Pause deadlock avoidance parameters */ -#define DROP_MSEC 16 -#define DROP_PKTS_CNT 1 - -static void tp_init(adapter_t * ap, const struct tp_params *p, - unsigned int tp_clk) -{ - u32 val; - - if (!t1_is_asic(ap)) - return; - - val = F_TP_IN_CSPI_CPL | F_TP_IN_CSPI_CHECK_IP_CSUM | - F_TP_IN_CSPI_CHECK_TCP_CSUM | F_TP_IN_ESPI_ETHERNET; - if (!p->pm_size) - val |= F_OFFLOAD_DISABLE; - else - val |= F_TP_IN_ESPI_CHECK_IP_CSUM | F_TP_IN_ESPI_CHECK_TCP_CSUM; - writel(val, ap->regs + A_TP_IN_CONFIG); - writel(F_TP_OUT_CSPI_CPL | - F_TP_OUT_ESPI_ETHERNET | - F_TP_OUT_ESPI_GENERATE_IP_CSUM | - F_TP_OUT_ESPI_GENERATE_TCP_CSUM, ap->regs + A_TP_OUT_CONFIG); - writel(V_IP_TTL(64) | - F_PATH_MTU /* IP DF bit */ | - V_5TUPLE_LOOKUP(p->use_5tuple_mode) | - V_SYN_COOKIE_PARAMETER(29), ap->regs + A_TP_GLOBAL_CONFIG); - /* - * Enable pause frame deadlock prevention. - */ - if (is_T2(ap) && ap->params.nports > 1) { - u32 drop_ticks = DROP_MSEC * (tp_clk / 1000); - - writel(F_ENABLE_TX_DROP | F_ENABLE_TX_ERROR | - V_DROP_TICKS_CNT(drop_ticks) | - V_NUM_PKTS_DROPPED(DROP_PKTS_CNT), - ap->regs + A_TP_TX_DROP_CONFIG); - } -} - -void t1_tp_destroy(struct petp *tp) -{ - kfree(tp); -} - -struct petp *__devinit t1_tp_create(adapter_t * adapter, struct tp_params *p) -{ - struct petp *tp = kzalloc(sizeof(*tp), GFP_KERNEL); - - if (!tp) - return NULL; - - tp->adapter = adapter; - - return tp; -} - -void t1_tp_intr_enable(struct petp *tp) -{ - u32 tp_intr = readl(tp->adapter->regs + A_PL_ENABLE); - -#ifdef CONFIG_CHELSIO_T1_1G - if (!t1_is_asic(tp->adapter)) { - /* FPGA */ - writel(0xffffffff, - tp->adapter->regs + FPGA_TP_ADDR_INTERRUPT_ENABLE); - writel(tp_intr | FPGA_PCIX_INTERRUPT_TP, - tp->adapter->regs + A_PL_ENABLE); - } else -#endif - { - /* We don't use any TP interrupts */ - writel(0, tp->adapter->regs + A_TP_INT_ENABLE); - writel(tp_intr | F_PL_INTR_TP, - tp->adapter->regs + A_PL_ENABLE); - } -} - -void t1_tp_intr_disable(struct petp *tp) -{ - u32 tp_intr = readl(tp->adapter->regs + A_PL_ENABLE); - -#ifdef CONFIG_CHELSIO_T1_1G - if (!t1_is_asic(tp->adapter)) { - /* FPGA */ - writel(0, tp->adapter->regs + FPGA_TP_ADDR_INTERRUPT_ENABLE); - writel(tp_intr & ~FPGA_PCIX_INTERRUPT_TP, - tp->adapter->regs + A_PL_ENABLE); - } else -#endif - { - writel(0, tp->adapter->regs + A_TP_INT_ENABLE); - writel(tp_intr & ~F_PL_INTR_TP, - tp->adapter->regs + A_PL_ENABLE); - } -} - -void t1_tp_intr_clear(struct petp *tp) -{ -#ifdef CONFIG_CHELSIO_T1_1G - if (!t1_is_asic(tp->adapter)) { - writel(0xffffffff, - tp->adapter->regs + FPGA_TP_ADDR_INTERRUPT_CAUSE); - writel(FPGA_PCIX_INTERRUPT_TP, tp->adapter->regs + A_PL_CAUSE); - return; - } -#endif - writel(0xffffffff, tp->adapter->regs + A_TP_INT_CAUSE); - writel(F_PL_INTR_TP, tp->adapter->regs + A_PL_CAUSE); -} - -int t1_tp_intr_handler(struct petp *tp) -{ - u32 cause; - -#ifdef CONFIG_CHELSIO_T1_1G - /* FPGA doesn't support TP interrupts. */ - if (!t1_is_asic(tp->adapter)) - return 1; -#endif - - cause = readl(tp->adapter->regs + A_TP_INT_CAUSE); - writel(cause, tp->adapter->regs + A_TP_INT_CAUSE); - return 0; -} - -static void set_csum_offload(struct petp *tp, u32 csum_bit, int enable) -{ - u32 val = readl(tp->adapter->regs + A_TP_GLOBAL_CONFIG); - - if (enable) - val |= csum_bit; - else - val &= ~csum_bit; - writel(val, tp->adapter->regs + A_TP_GLOBAL_CONFIG); -} - -void t1_tp_set_ip_checksum_offload(struct petp *tp, int enable) -{ - set_csum_offload(tp, F_IP_CSUM, enable); -} - -void t1_tp_set_tcp_checksum_offload(struct petp *tp, int enable) -{ - set_csum_offload(tp, F_TCP_CSUM, enable); -} - -/* - * Initialize TP state. tp_params contains initial settings for some TP - * parameters, particularly the one-time PM and CM settings. - */ -int t1_tp_reset(struct petp *tp, struct tp_params *p, unsigned int tp_clk) -{ - adapter_t *adapter = tp->adapter; - - tp_init(adapter, p, tp_clk); - writel(F_TP_RESET, adapter->regs + A_TP_RESET); - return 0; -} diff --git a/drivers/net/chelsio/tp.h b/drivers/net/chelsio/tp.h deleted file mode 100644 index dfd8ce25106a..000000000000 --- a/drivers/net/chelsio/tp.h +++ /dev/null @@ -1,72 +0,0 @@ -/* $Date: 2005/03/07 23:59:05 $ $RCSfile: tp.h,v $ $Revision: 1.20 $ */ -#ifndef CHELSIO_TP_H -#define CHELSIO_TP_H - -#include "common.h" - -#define TP_MAX_RX_COALESCING_SIZE 16224U - -struct tp_mib_statistics { - - /* IP */ - u32 ipInReceive_hi; - u32 ipInReceive_lo; - u32 ipInHdrErrors_hi; - u32 ipInHdrErrors_lo; - u32 ipInAddrErrors_hi; - u32 ipInAddrErrors_lo; - u32 ipInUnknownProtos_hi; - u32 ipInUnknownProtos_lo; - u32 ipInDiscards_hi; - u32 ipInDiscards_lo; - u32 ipInDelivers_hi; - u32 ipInDelivers_lo; - u32 ipOutRequests_hi; - u32 ipOutRequests_lo; - u32 ipOutDiscards_hi; - u32 ipOutDiscards_lo; - u32 ipOutNoRoutes_hi; - u32 ipOutNoRoutes_lo; - u32 ipReasmTimeout; - u32 ipReasmReqds; - u32 ipReasmOKs; - u32 ipReasmFails; - - u32 reserved[8]; - - /* TCP */ - u32 tcpActiveOpens; - u32 tcpPassiveOpens; - u32 tcpAttemptFails; - u32 tcpEstabResets; - u32 tcpOutRsts; - u32 tcpCurrEstab; - u32 tcpInSegs_hi; - u32 tcpInSegs_lo; - u32 tcpOutSegs_hi; - u32 tcpOutSegs_lo; - u32 tcpRetransSeg_hi; - u32 tcpRetransSeg_lo; - u32 tcpInErrs_hi; - u32 tcpInErrs_lo; - u32 tcpRtoMin; - u32 tcpRtoMax; -}; - -struct petp; -struct tp_params; - -struct petp *t1_tp_create(adapter_t *adapter, struct tp_params *p); -void t1_tp_destroy(struct petp *tp); - -void t1_tp_intr_disable(struct petp *tp); -void t1_tp_intr_enable(struct petp *tp); -void t1_tp_intr_clear(struct petp *tp); -int t1_tp_intr_handler(struct petp *tp); - -void t1_tp_get_mib_statistics(adapter_t *adap, struct tp_mib_statistics *tps); -void t1_tp_set_tcp_checksum_offload(struct petp *tp, int enable); -void t1_tp_set_ip_checksum_offload(struct petp *tp, int enable); -int t1_tp_set_coalescing_size(struct petp *tp, unsigned int size); -int t1_tp_reset(struct petp *tp, struct tp_params *p, unsigned int tp_clk); -#endif diff --git a/drivers/net/chelsio/vsc7326.c b/drivers/net/chelsio/vsc7326.c deleted file mode 100644 index b0cb388f5e12..000000000000 --- a/drivers/net/chelsio/vsc7326.c +++ /dev/null @@ -1,730 +0,0 @@ -/* $Date: 2006/04/28 19:20:06 $ $RCSfile: vsc7326.c,v $ $Revision: 1.19 $ */ - -/* Driver for Vitesse VSC7326 (Schaumburg) MAC */ - -#include "gmac.h" -#include "elmer0.h" -#include "vsc7326_reg.h" - -/* Update fast changing statistics every 15 seconds */ -#define STATS_TICK_SECS 15 -/* 30 minutes for full statistics update */ -#define MAJOR_UPDATE_TICKS (1800 / STATS_TICK_SECS) - -#define MAX_MTU 9600 - -/* The egress WM value 0x01a01fff should be used only when the - * interface is down (MAC port disabled). This is a workaround - * for disabling the T2/MAC flow-control. When the interface is - * enabled, the WM value should be set to 0x014a03F0. - */ -#define WM_DISABLE 0x01a01fff -#define WM_ENABLE 0x014a03F0 - -struct init_table { - u32 addr; - u32 data; -}; - -struct _cmac_instance { - u32 index; - u32 ticks; -}; - -#define INITBLOCK_SLEEP 0xffffffff - -static void vsc_read(adapter_t *adapter, u32 addr, u32 *val) -{ - u32 status, vlo, vhi; - int i; - - spin_lock_bh(&adapter->mac_lock); - t1_tpi_read(adapter, (addr << 2) + 4, &vlo); - i = 0; - do { - t1_tpi_read(adapter, (REG_LOCAL_STATUS << 2) + 4, &vlo); - t1_tpi_read(adapter, REG_LOCAL_STATUS << 2, &vhi); - status = (vhi << 16) | vlo; - i++; - } while (((status & 1) == 0) && (i < 50)); - if (i == 50) - pr_err("Invalid tpi read from MAC, breaking loop.\n"); - - t1_tpi_read(adapter, (REG_LOCAL_DATA << 2) + 4, &vlo); - t1_tpi_read(adapter, REG_LOCAL_DATA << 2, &vhi); - - *val = (vhi << 16) | vlo; - - /* pr_err("rd: block: 0x%x sublock: 0x%x reg: 0x%x data: 0x%x\n", - ((addr&0xe000)>>13), ((addr&0x1e00)>>9), - ((addr&0x01fe)>>1), *val); */ - spin_unlock_bh(&adapter->mac_lock); -} - -static void vsc_write(adapter_t *adapter, u32 addr, u32 data) -{ - spin_lock_bh(&adapter->mac_lock); - t1_tpi_write(adapter, (addr << 2) + 4, data & 0xFFFF); - t1_tpi_write(adapter, addr << 2, (data >> 16) & 0xFFFF); - /* pr_err("wr: block: 0x%x sublock: 0x%x reg: 0x%x data: 0x%x\n", - ((addr&0xe000)>>13), ((addr&0x1e00)>>9), - ((addr&0x01fe)>>1), data); */ - spin_unlock_bh(&adapter->mac_lock); -} - -/* Hard reset the MAC. This wipes out *all* configuration. */ -static void vsc7326_full_reset(adapter_t* adapter) -{ - u32 val; - u32 result = 0xffff; - - t1_tpi_read(adapter, A_ELMER0_GPO, &val); - val &= ~1; - t1_tpi_write(adapter, A_ELMER0_GPO, val); - udelay(2); - val |= 0x1; /* Enable mac MAC itself */ - val |= 0x800; /* Turn off the red LED */ - t1_tpi_write(adapter, A_ELMER0_GPO, val); - mdelay(1); - vsc_write(adapter, REG_SW_RESET, 0x80000001); - do { - mdelay(1); - vsc_read(adapter, REG_SW_RESET, &result); - } while (result != 0x0); -} - -static struct init_table vsc7326_reset[] = { - { REG_IFACE_MODE, 0x00000000 }, - { REG_CRC_CFG, 0x00000020 }, - { REG_PLL_CLK_SPEED, 0x00050c00 }, - { REG_PLL_CLK_SPEED, 0x00050c00 }, - { REG_MSCH, 0x00002f14 }, - { REG_SPI4_MISC, 0x00040409 }, - { REG_SPI4_DESKEW, 0x00080000 }, - { REG_SPI4_ING_SETUP2, 0x08080004 }, - { REG_SPI4_ING_SETUP0, 0x04111004 }, - { REG_SPI4_EGR_SETUP0, 0x80001a04 }, - { REG_SPI4_ING_SETUP1, 0x02010000 }, - { REG_AGE_INC(0), 0x00000000 }, - { REG_AGE_INC(1), 0x00000000 }, - { REG_ING_CONTROL, 0x0a200011 }, - { REG_EGR_CONTROL, 0xa0010091 }, -}; - -static struct init_table vsc7326_portinit[4][22] = { - { /* Port 0 */ - /* FIFO setup */ - { REG_DBG(0), 0x000004f0 }, - { REG_HDX(0), 0x00073101 }, - { REG_TEST(0,0), 0x00000022 }, - { REG_TEST(1,0), 0x00000022 }, - { REG_TOP_BOTTOM(0,0), 0x003f0000 }, - { REG_TOP_BOTTOM(1,0), 0x00120000 }, - { REG_HIGH_LOW_WM(0,0), 0x07460757 }, - { REG_HIGH_LOW_WM(1,0), WM_DISABLE }, - { REG_CT_THRHLD(0,0), 0x00000000 }, - { REG_CT_THRHLD(1,0), 0x00000000 }, - { REG_BUCKE(0), 0x0002ffff }, - { REG_BUCKI(0), 0x0002ffff }, - { REG_TEST(0,0), 0x00000020 }, - { REG_TEST(1,0), 0x00000020 }, - /* Port config */ - { REG_MAX_LEN(0), 0x00002710 }, - { REG_PORT_FAIL(0), 0x00000002 }, - { REG_NORMALIZER(0), 0x00000a64 }, - { REG_DENORM(0), 0x00000010 }, - { REG_STICK_BIT(0), 0x03baa370 }, - { REG_DEV_SETUP(0), 0x00000083 }, - { REG_DEV_SETUP(0), 0x00000082 }, - { REG_MODE_CFG(0), 0x0200259f }, - }, - { /* Port 1 */ - /* FIFO setup */ - { REG_DBG(1), 0x000004f0 }, - { REG_HDX(1), 0x00073101 }, - { REG_TEST(0,1), 0x00000022 }, - { REG_TEST(1,1), 0x00000022 }, - { REG_TOP_BOTTOM(0,1), 0x007e003f }, - { REG_TOP_BOTTOM(1,1), 0x00240012 }, - { REG_HIGH_LOW_WM(0,1), 0x07460757 }, - { REG_HIGH_LOW_WM(1,1), WM_DISABLE }, - { REG_CT_THRHLD(0,1), 0x00000000 }, - { REG_CT_THRHLD(1,1), 0x00000000 }, - { REG_BUCKE(1), 0x0002ffff }, - { REG_BUCKI(1), 0x0002ffff }, - { REG_TEST(0,1), 0x00000020 }, - { REG_TEST(1,1), 0x00000020 }, - /* Port config */ - { REG_MAX_LEN(1), 0x00002710 }, - { REG_PORT_FAIL(1), 0x00000002 }, - { REG_NORMALIZER(1), 0x00000a64 }, - { REG_DENORM(1), 0x00000010 }, - { REG_STICK_BIT(1), 0x03baa370 }, - { REG_DEV_SETUP(1), 0x00000083 }, - { REG_DEV_SETUP(1), 0x00000082 }, - { REG_MODE_CFG(1), 0x0200259f }, - }, - { /* Port 2 */ - /* FIFO setup */ - { REG_DBG(2), 0x000004f0 }, - { REG_HDX(2), 0x00073101 }, - { REG_TEST(0,2), 0x00000022 }, - { REG_TEST(1,2), 0x00000022 }, - { REG_TOP_BOTTOM(0,2), 0x00bd007e }, - { REG_TOP_BOTTOM(1,2), 0x00360024 }, - { REG_HIGH_LOW_WM(0,2), 0x07460757 }, - { REG_HIGH_LOW_WM(1,2), WM_DISABLE }, - { REG_CT_THRHLD(0,2), 0x00000000 }, - { REG_CT_THRHLD(1,2), 0x00000000 }, - { REG_BUCKE(2), 0x0002ffff }, - { REG_BUCKI(2), 0x0002ffff }, - { REG_TEST(0,2), 0x00000020 }, - { REG_TEST(1,2), 0x00000020 }, - /* Port config */ - { REG_MAX_LEN(2), 0x00002710 }, - { REG_PORT_FAIL(2), 0x00000002 }, - { REG_NORMALIZER(2), 0x00000a64 }, - { REG_DENORM(2), 0x00000010 }, - { REG_STICK_BIT(2), 0x03baa370 }, - { REG_DEV_SETUP(2), 0x00000083 }, - { REG_DEV_SETUP(2), 0x00000082 }, - { REG_MODE_CFG(2), 0x0200259f }, - }, - { /* Port 3 */ - /* FIFO setup */ - { REG_DBG(3), 0x000004f0 }, - { REG_HDX(3), 0x00073101 }, - { REG_TEST(0,3), 0x00000022 }, - { REG_TEST(1,3), 0x00000022 }, - { REG_TOP_BOTTOM(0,3), 0x00fc00bd }, - { REG_TOP_BOTTOM(1,3), 0x00480036 }, - { REG_HIGH_LOW_WM(0,3), 0x07460757 }, - { REG_HIGH_LOW_WM(1,3), WM_DISABLE }, - { REG_CT_THRHLD(0,3), 0x00000000 }, - { REG_CT_THRHLD(1,3), 0x00000000 }, - { REG_BUCKE(3), 0x0002ffff }, - { REG_BUCKI(3), 0x0002ffff }, - { REG_TEST(0,3), 0x00000020 }, - { REG_TEST(1,3), 0x00000020 }, - /* Port config */ - { REG_MAX_LEN(3), 0x00002710 }, - { REG_PORT_FAIL(3), 0x00000002 }, - { REG_NORMALIZER(3), 0x00000a64 }, - { REG_DENORM(3), 0x00000010 }, - { REG_STICK_BIT(3), 0x03baa370 }, - { REG_DEV_SETUP(3), 0x00000083 }, - { REG_DEV_SETUP(3), 0x00000082 }, - { REG_MODE_CFG(3), 0x0200259f }, - }, -}; - -static void run_table(adapter_t *adapter, struct init_table *ib, int len) -{ - int i; - - for (i = 0; i < len; i++) { - if (ib[i].addr == INITBLOCK_SLEEP) { - udelay( ib[i].data ); - pr_err("sleep %d us\n",ib[i].data); - } else - vsc_write( adapter, ib[i].addr, ib[i].data ); - } -} - -static int bist_rd(adapter_t *adapter, int moduleid, int address) -{ - int data = 0; - u32 result = 0; - - if ((address != 0x0) && - (address != 0x1) && - (address != 0x2) && - (address != 0xd) && - (address != 0xe)) - pr_err("No bist address: 0x%x\n", address); - - data = ((0x00 << 24) | ((address & 0xff) << 16) | (0x00 << 8) | - ((moduleid & 0xff) << 0)); - vsc_write(adapter, REG_RAM_BIST_CMD, data); - - udelay(10); - - vsc_read(adapter, REG_RAM_BIST_RESULT, &result); - if ((result & (1 << 9)) != 0x0) - pr_err("Still in bist read: 0x%x\n", result); - else if ((result & (1 << 8)) != 0x0) - pr_err("bist read error: 0x%x\n", result); - - return result & 0xff; -} - -static int bist_wr(adapter_t *adapter, int moduleid, int address, int value) -{ - int data = 0; - u32 result = 0; - - if ((address != 0x0) && - (address != 0x1) && - (address != 0x2) && - (address != 0xd) && - (address != 0xe)) - pr_err("No bist address: 0x%x\n", address); - - if (value > 255) - pr_err("Suspicious write out of range value: 0x%x\n", value); - - data = ((0x01 << 24) | ((address & 0xff) << 16) | (value << 8) | - ((moduleid & 0xff) << 0)); - vsc_write(adapter, REG_RAM_BIST_CMD, data); - - udelay(5); - - vsc_read(adapter, REG_RAM_BIST_CMD, &result); - if ((result & (1 << 27)) != 0x0) - pr_err("Still in bist write: 0x%x\n", result); - else if ((result & (1 << 26)) != 0x0) - pr_err("bist write error: 0x%x\n", result); - - return 0; -} - -static int run_bist(adapter_t *adapter, int moduleid) -{ - /*run bist*/ - (void) bist_wr(adapter,moduleid, 0x00, 0x02); - (void) bist_wr(adapter,moduleid, 0x01, 0x01); - - return 0; -} - -static int check_bist(adapter_t *adapter, int moduleid) -{ - int result=0; - int column=0; - /*check bist*/ - result = bist_rd(adapter,moduleid, 0x02); - column = ((bist_rd(adapter,moduleid, 0x0e)<<8) + - (bist_rd(adapter,moduleid, 0x0d))); - if ((result & 3) != 0x3) - pr_err("Result: 0x%x BIST error in ram %d, column: 0x%04x\n", - result, moduleid, column); - return 0; -} - -static int enable_mem(adapter_t *adapter, int moduleid) -{ - /*enable mem*/ - (void) bist_wr(adapter,moduleid, 0x00, 0x00); - return 0; -} - -static int run_bist_all(adapter_t *adapter) -{ - int port = 0; - u32 val = 0; - - vsc_write(adapter, REG_MEM_BIST, 0x5); - vsc_read(adapter, REG_MEM_BIST, &val); - - for (port = 0; port < 12; port++) - vsc_write(adapter, REG_DEV_SETUP(port), 0x0); - - udelay(300); - vsc_write(adapter, REG_SPI4_MISC, 0x00040409); - udelay(300); - - (void) run_bist(adapter,13); - (void) run_bist(adapter,14); - (void) run_bist(adapter,20); - (void) run_bist(adapter,21); - mdelay(200); - (void) check_bist(adapter,13); - (void) check_bist(adapter,14); - (void) check_bist(adapter,20); - (void) check_bist(adapter,21); - udelay(100); - (void) enable_mem(adapter,13); - (void) enable_mem(adapter,14); - (void) enable_mem(adapter,20); - (void) enable_mem(adapter,21); - udelay(300); - vsc_write(adapter, REG_SPI4_MISC, 0x60040400); - udelay(300); - for (port = 0; port < 12; port++) - vsc_write(adapter, REG_DEV_SETUP(port), 0x1); - - udelay(300); - vsc_write(adapter, REG_MEM_BIST, 0x0); - mdelay(10); - return 0; -} - -static int mac_intr_handler(struct cmac *mac) -{ - return 0; -} - -static int mac_intr_enable(struct cmac *mac) -{ - return 0; -} - -static int mac_intr_disable(struct cmac *mac) -{ - return 0; -} - -static int mac_intr_clear(struct cmac *mac) -{ - return 0; -} - -/* Expect MAC address to be in network byte order. */ -static int mac_set_address(struct cmac* mac, u8 addr[6]) -{ - u32 val; - int port = mac->instance->index; - - vsc_write(mac->adapter, REG_MAC_LOW_ADDR(port), - (addr[3] << 16) | (addr[4] << 8) | addr[5]); - vsc_write(mac->adapter, REG_MAC_HIGH_ADDR(port), - (addr[0] << 16) | (addr[1] << 8) | addr[2]); - - vsc_read(mac->adapter, REG_ING_FFILT_UM_EN, &val); - val &= ~0xf0000000; - vsc_write(mac->adapter, REG_ING_FFILT_UM_EN, val | (port << 28)); - - vsc_write(mac->adapter, REG_ING_FFILT_MASK0, - 0xffff0000 | (addr[4] << 8) | addr[5]); - vsc_write(mac->adapter, REG_ING_FFILT_MASK1, - 0xffff0000 | (addr[2] << 8) | addr[3]); - vsc_write(mac->adapter, REG_ING_FFILT_MASK2, - 0xffff0000 | (addr[0] << 8) | addr[1]); - return 0; -} - -static int mac_get_address(struct cmac *mac, u8 addr[6]) -{ - u32 addr_lo, addr_hi; - int port = mac->instance->index; - - vsc_read(mac->adapter, REG_MAC_LOW_ADDR(port), &addr_lo); - vsc_read(mac->adapter, REG_MAC_HIGH_ADDR(port), &addr_hi); - - addr[0] = (u8) (addr_hi >> 16); - addr[1] = (u8) (addr_hi >> 8); - addr[2] = (u8) addr_hi; - addr[3] = (u8) (addr_lo >> 16); - addr[4] = (u8) (addr_lo >> 8); - addr[5] = (u8) addr_lo; - return 0; -} - -/* This is intended to reset a port, not the whole MAC */ -static int mac_reset(struct cmac *mac) -{ - int index = mac->instance->index; - - run_table(mac->adapter, vsc7326_portinit[index], - ARRAY_SIZE(vsc7326_portinit[index])); - - return 0; -} - -static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm) -{ - u32 v; - int port = mac->instance->index; - - vsc_read(mac->adapter, REG_ING_FFILT_UM_EN, &v); - v |= 1 << 12; - - if (t1_rx_mode_promisc(rm)) - v &= ~(1 << (port + 16)); - else - v |= 1 << (port + 16); - - vsc_write(mac->adapter, REG_ING_FFILT_UM_EN, v); - return 0; -} - -static int mac_set_mtu(struct cmac *mac, int mtu) -{ - int port = mac->instance->index; - - if (mtu > MAX_MTU) - return -EINVAL; - - /* max_len includes header and FCS */ - vsc_write(mac->adapter, REG_MAX_LEN(port), mtu + 14 + 4); - return 0; -} - -static int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, - int fc) -{ - u32 v; - int enable, port = mac->instance->index; - - if (speed >= 0 && speed != SPEED_10 && speed != SPEED_100 && - speed != SPEED_1000) - return -1; - if (duplex > 0 && duplex != DUPLEX_FULL) - return -1; - - if (speed >= 0) { - vsc_read(mac->adapter, REG_MODE_CFG(port), &v); - enable = v & 3; /* save tx/rx enables */ - v &= ~0xf; - v |= 4; /* full duplex */ - if (speed == SPEED_1000) - v |= 8; /* GigE */ - enable |= v; - vsc_write(mac->adapter, REG_MODE_CFG(port), v); - - if (speed == SPEED_1000) - v = 0x82; - else if (speed == SPEED_100) - v = 0x84; - else /* SPEED_10 */ - v = 0x86; - vsc_write(mac->adapter, REG_DEV_SETUP(port), v | 1); /* reset */ - vsc_write(mac->adapter, REG_DEV_SETUP(port), v); - vsc_read(mac->adapter, REG_DBG(port), &v); - v &= ~0xff00; - if (speed == SPEED_1000) - v |= 0x400; - else if (speed == SPEED_100) - v |= 0x2000; - else /* SPEED_10 */ - v |= 0xff00; - vsc_write(mac->adapter, REG_DBG(port), v); - - vsc_write(mac->adapter, REG_TX_IFG(port), - speed == SPEED_1000 ? 5 : 0x11); - if (duplex == DUPLEX_HALF) - enable = 0x0; /* 100 or 10 */ - else if (speed == SPEED_1000) - enable = 0xc; - else /* SPEED_100 or 10 */ - enable = 0x4; - enable |= 0x9 << 10; /* IFG1 */ - enable |= 0x6 << 6; /* IFG2 */ - enable |= 0x1 << 4; /* VLAN */ - enable |= 0x3; /* RX/TX EN */ - vsc_write(mac->adapter, REG_MODE_CFG(port), enable); - - } - - vsc_read(mac->adapter, REG_PAUSE_CFG(port), &v); - v &= 0xfff0ffff; - v |= 0x20000; /* xon/xoff */ - if (fc & PAUSE_RX) - v |= 0x40000; - if (fc & PAUSE_TX) - v |= 0x80000; - if (fc == (PAUSE_RX | PAUSE_TX)) - v |= 0x10000; - vsc_write(mac->adapter, REG_PAUSE_CFG(port), v); - return 0; -} - -static int mac_enable(struct cmac *mac, int which) -{ - u32 val; - int port = mac->instance->index; - - /* Write the correct WM value when the port is enabled. */ - vsc_write(mac->adapter, REG_HIGH_LOW_WM(1,port), WM_ENABLE); - - vsc_read(mac->adapter, REG_MODE_CFG(port), &val); - if (which & MAC_DIRECTION_RX) - val |= 0x2; - if (which & MAC_DIRECTION_TX) - val |= 1; - vsc_write(mac->adapter, REG_MODE_CFG(port), val); - return 0; -} - -static int mac_disable(struct cmac *mac, int which) -{ - u32 val; - int i, port = mac->instance->index; - - /* Reset the port, this also writes the correct WM value */ - mac_reset(mac); - - vsc_read(mac->adapter, REG_MODE_CFG(port), &val); - if (which & MAC_DIRECTION_RX) - val &= ~0x2; - if (which & MAC_DIRECTION_TX) - val &= ~0x1; - vsc_write(mac->adapter, REG_MODE_CFG(port), val); - vsc_read(mac->adapter, REG_MODE_CFG(port), &val); - - /* Clear stats */ - for (i = 0; i <= 0x3a; ++i) - vsc_write(mac->adapter, CRA(4, port, i), 0); - - /* Clear software counters */ - memset(&mac->stats, 0, sizeof(struct cmac_statistics)); - - return 0; -} - -static void rmon_update(struct cmac *mac, unsigned int addr, u64 *stat) -{ - u32 v, lo; - - vsc_read(mac->adapter, addr, &v); - lo = *stat; - *stat = *stat - lo + v; - - if (v == 0) - return; - - if (v < lo) - *stat += (1ULL << 32); -} - -static void port_stats_update(struct cmac *mac) -{ - struct { - unsigned int reg; - unsigned int offset; - } hw_stats[] = { - -#define HW_STAT(reg, stat_name) \ - { reg, (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL } - - /* Rx stats */ - HW_STAT(RxUnicast, RxUnicastFramesOK), - HW_STAT(RxMulticast, RxMulticastFramesOK), - HW_STAT(RxBroadcast, RxBroadcastFramesOK), - HW_STAT(Crc, RxFCSErrors), - HW_STAT(RxAlignment, RxAlignErrors), - HW_STAT(RxOversize, RxFrameTooLongErrors), - HW_STAT(RxPause, RxPauseFrames), - HW_STAT(RxJabbers, RxJabberErrors), - HW_STAT(RxFragments, RxRuntErrors), - HW_STAT(RxUndersize, RxRuntErrors), - HW_STAT(RxSymbolCarrier, RxSymbolErrors), - HW_STAT(RxSize1519ToMax, RxJumboFramesOK), - - /* Tx stats (skip collision stats as we are full-duplex only) */ - HW_STAT(TxUnicast, TxUnicastFramesOK), - HW_STAT(TxMulticast, TxMulticastFramesOK), - HW_STAT(TxBroadcast, TxBroadcastFramesOK), - HW_STAT(TxPause, TxPauseFrames), - HW_STAT(TxUnderrun, TxUnderrun), - HW_STAT(TxSize1519ToMax, TxJumboFramesOK), - }, *p = hw_stats; - unsigned int port = mac->instance->index; - u64 *stats = (u64 *)&mac->stats; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(hw_stats); i++) - rmon_update(mac, CRA(0x4, port, p->reg), stats + p->offset); - - rmon_update(mac, REG_TX_OK_BYTES(port), &mac->stats.TxOctetsOK); - rmon_update(mac, REG_RX_OK_BYTES(port), &mac->stats.RxOctetsOK); - rmon_update(mac, REG_RX_BAD_BYTES(port), &mac->stats.RxOctetsBad); -} - -/* - * This function is called periodically to accumulate the current values of the - * RMON counters into the port statistics. Since the counters are only 32 bits - * some of them can overflow in less than a minute at GigE speeds, so this - * function should be called every 30 seconds or so. - * - * To cut down on reading costs we update only the octet counters at each tick - * and do a full update at major ticks, which can be every 30 minutes or more. - */ -static const struct cmac_statistics *mac_update_statistics(struct cmac *mac, - int flag) -{ - if (flag == MAC_STATS_UPDATE_FULL || - mac->instance->ticks >= MAJOR_UPDATE_TICKS) { - port_stats_update(mac); - mac->instance->ticks = 0; - } else { - int port = mac->instance->index; - - rmon_update(mac, REG_RX_OK_BYTES(port), - &mac->stats.RxOctetsOK); - rmon_update(mac, REG_RX_BAD_BYTES(port), - &mac->stats.RxOctetsBad); - rmon_update(mac, REG_TX_OK_BYTES(port), - &mac->stats.TxOctetsOK); - mac->instance->ticks++; - } - return &mac->stats; -} - -static void mac_destroy(struct cmac *mac) -{ - kfree(mac); -} - -static struct cmac_ops vsc7326_ops = { - .destroy = mac_destroy, - .reset = mac_reset, - .interrupt_handler = mac_intr_handler, - .interrupt_enable = mac_intr_enable, - .interrupt_disable = mac_intr_disable, - .interrupt_clear = mac_intr_clear, - .enable = mac_enable, - .disable = mac_disable, - .set_mtu = mac_set_mtu, - .set_rx_mode = mac_set_rx_mode, - .set_speed_duplex_fc = mac_set_speed_duplex_fc, - .statistics_update = mac_update_statistics, - .macaddress_get = mac_get_address, - .macaddress_set = mac_set_address, -}; - -static struct cmac *vsc7326_mac_create(adapter_t *adapter, int index) -{ - struct cmac *mac; - u32 val; - int i; - - mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL); - if (!mac) - return NULL; - - mac->ops = &vsc7326_ops; - mac->instance = (cmac_instance *)(mac + 1); - mac->adapter = adapter; - - mac->instance->index = index; - mac->instance->ticks = 0; - - i = 0; - do { - u32 vhi, vlo; - - vhi = vlo = 0; - t1_tpi_read(adapter, (REG_LOCAL_STATUS << 2) + 4, &vlo); - udelay(1); - t1_tpi_read(adapter, REG_LOCAL_STATUS << 2, &vhi); - udelay(5); - val = (vhi << 16) | vlo; - } while ((++i < 10000) && (val == 0xffffffff)); - - return mac; -} - -static int vsc7326_mac_reset(adapter_t *adapter) -{ - vsc7326_full_reset(adapter); - (void) run_bist_all(adapter); - run_table(adapter, vsc7326_reset, ARRAY_SIZE(vsc7326_reset)); - return 0; -} - -const struct gmac t1_vsc7326_ops = { - .stats_update_period = STATS_TICK_SECS, - .create = vsc7326_mac_create, - .reset = vsc7326_mac_reset, -}; diff --git a/drivers/net/chelsio/vsc7326_reg.h b/drivers/net/chelsio/vsc7326_reg.h deleted file mode 100644 index 479edbcabe68..000000000000 --- a/drivers/net/chelsio/vsc7326_reg.h +++ /dev/null @@ -1,297 +0,0 @@ -/* $Date: 2006/04/28 19:20:17 $ $RCSfile: vsc7326_reg.h,v $ $Revision: 1.5 $ */ -#ifndef _VSC7321_REG_H_ -#define _VSC7321_REG_H_ - -/* Register definitions for Vitesse VSC7321 (Meigs II) MAC - * - * Straight off the data sheet, VMDS-10038 Rev 2.0 and - * PD0011-01-14-Meigs-II 2002-12-12 - */ - -/* Just 'cause it's in here doesn't mean it's used. */ - -#define CRA(blk,sub,adr) ((((blk) & 0x7) << 13) | (((sub) & 0xf) << 9) | (((adr) & 0xff) << 1)) - -/* System and CPU comm's registers */ -#define REG_CHIP_ID CRA(0x7,0xf,0x00) /* Chip ID */ -#define REG_BLADE_ID CRA(0x7,0xf,0x01) /* Blade ID */ -#define REG_SW_RESET CRA(0x7,0xf,0x02) /* Global Soft Reset */ -#define REG_MEM_BIST CRA(0x7,0xf,0x04) /* mem */ -#define REG_IFACE_MODE CRA(0x7,0xf,0x07) /* Interface mode */ -#define REG_MSCH CRA(0x7,0x2,0x06) /* CRC error count */ -#define REG_CRC_CNT CRA(0x7,0x2,0x0a) /* CRC error count */ -#define REG_CRC_CFG CRA(0x7,0x2,0x0b) /* CRC config */ -#define REG_SI_TRANSFER_SEL CRA(0x7,0xf,0x18) /* SI Transfer Select */ -#define REG_PLL_CLK_SPEED CRA(0x7,0xf,0x19) /* Clock Speed Selection */ -#define REG_SYS_CLK_SELECT CRA(0x7,0xf,0x1c) /* System Clock Select */ -#define REG_GPIO_CTRL CRA(0x7,0xf,0x1d) /* GPIO Control */ -#define REG_GPIO_OUT CRA(0x7,0xf,0x1e) /* GPIO Out */ -#define REG_GPIO_IN CRA(0x7,0xf,0x1f) /* GPIO In */ -#define REG_CPU_TRANSFER_SEL CRA(0x7,0xf,0x20) /* CPU Transfer Select */ -#define REG_LOCAL_DATA CRA(0x7,0xf,0xfe) /* Local CPU Data Register */ -#define REG_LOCAL_STATUS CRA(0x7,0xf,0xff) /* Local CPU Status Register */ - -/* Aggregator registers */ -#define REG_AGGR_SETUP CRA(0x7,0x1,0x00) /* Aggregator Setup */ -#define REG_PMAP_TABLE CRA(0x7,0x1,0x01) /* Port map table */ -#define REG_MPLS_BIT0 CRA(0x7,0x1,0x08) /* MPLS bit0 position */ -#define REG_MPLS_BIT1 CRA(0x7,0x1,0x09) /* MPLS bit1 position */ -#define REG_MPLS_BIT2 CRA(0x7,0x1,0x0a) /* MPLS bit2 position */ -#define REG_MPLS_BIT3 CRA(0x7,0x1,0x0b) /* MPLS bit3 position */ -#define REG_MPLS_BITMASK CRA(0x7,0x1,0x0c) /* MPLS bit mask */ -#define REG_PRE_BIT0POS CRA(0x7,0x1,0x10) /* Preamble bit0 position */ -#define REG_PRE_BIT1POS CRA(0x7,0x1,0x11) /* Preamble bit1 position */ -#define REG_PRE_BIT2POS CRA(0x7,0x1,0x12) /* Preamble bit2 position */ -#define REG_PRE_BIT3POS CRA(0x7,0x1,0x13) /* Preamble bit3 position */ -#define REG_PRE_ERR_CNT CRA(0x7,0x1,0x14) /* Preamble parity error count */ - -/* BIST registers */ -/*#define REG_RAM_BIST_CMD CRA(0x7,0x2,0x00)*/ /* RAM BIST Command Register */ -/*#define REG_RAM_BIST_RESULT CRA(0x7,0x2,0x01)*/ /* RAM BIST Read Status/Result */ -#define REG_RAM_BIST_CMD CRA(0x7,0x1,0x00) /* RAM BIST Command Register */ -#define REG_RAM_BIST_RESULT CRA(0x7,0x1,0x01) /* RAM BIST Read Status/Result */ -#define BIST_PORT_SELECT 0x00 /* BIST port select */ -#define BIST_COMMAND 0x01 /* BIST enable/disable */ -#define BIST_STATUS 0x02 /* BIST operation status */ -#define BIST_ERR_CNT_LSB 0x03 /* BIST error count lo 8b */ -#define BIST_ERR_CNT_MSB 0x04 /* BIST error count hi 8b */ -#define BIST_ERR_SEL_LSB 0x05 /* BIST error select lo 8b */ -#define BIST_ERR_SEL_MSB 0x06 /* BIST error select hi 8b */ -#define BIST_ERROR_STATE 0x07 /* BIST engine internal state */ -#define BIST_ERR_ADR0 0x08 /* BIST error address lo 8b */ -#define BIST_ERR_ADR1 0x09 /* BIST error address lomid 8b */ -#define BIST_ERR_ADR2 0x0a /* BIST error address himid 8b */ -#define BIST_ERR_ADR3 0x0b /* BIST error address hi 8b */ - -/* FIFO registers - * ie = 0 for ingress, 1 for egress - * fn = FIFO number, 0-9 - */ -#define REG_TEST(ie,fn) CRA(0x2,ie&1,0x00+fn) /* Mode & Test Register */ -#define REG_TOP_BOTTOM(ie,fn) CRA(0x2,ie&1,0x10+fn) /* FIFO Buffer Top & Bottom */ -#define REG_TAIL(ie,fn) CRA(0x2,ie&1,0x20+fn) /* FIFO Write Pointer */ -#define REG_HEAD(ie,fn) CRA(0x2,ie&1,0x30+fn) /* FIFO Read Pointer */ -#define REG_HIGH_LOW_WM(ie,fn) CRA(0x2,ie&1,0x40+fn) /* Flow Control Water Marks */ -#define REG_CT_THRHLD(ie,fn) CRA(0x2,ie&1,0x50+fn) /* Cut Through Threshold */ -#define REG_FIFO_DROP_CNT(ie,fn) CRA(0x2,ie&1,0x60+fn) /* Drop & CRC Error Counter */ -#define REG_DEBUG_BUF_CNT(ie,fn) CRA(0x2,ie&1,0x70+fn) /* Input Side Debug Counter */ -#define REG_BUCKI(fn) CRA(0x2,2,0x20+fn) /* Input Side Debug Counter */ -#define REG_BUCKE(fn) CRA(0x2,3,0x20+fn) /* Input Side Debug Counter */ - -/* Traffic shaper buckets - * ie = 0 for ingress, 1 for egress - * bn = bucket number 0-10 (yes, 11 buckets) - */ -/* OK, this one's kinda ugly. Some hardware designers are perverse. */ -#define REG_TRAFFIC_SHAPER_BUCKET(ie,bn) CRA(0x2,ie&1,0x0a + (bn>7) | ((bn&7)<<4)) -#define REG_TRAFFIC_SHAPER_CONTROL(ie) CRA(0x2,ie&1,0x3b) - -#define REG_SRAM_ADR(ie) CRA(0x2,ie&1,0x0e) /* FIFO SRAM address */ -#define REG_SRAM_WR_STRB(ie) CRA(0x2,ie&1,0x1e) /* FIFO SRAM write strobe */ -#define REG_SRAM_RD_STRB(ie) CRA(0x2,ie&1,0x2e) /* FIFO SRAM read strobe */ -#define REG_SRAM_DATA_0(ie) CRA(0x2,ie&1,0x3e) /* FIFO SRAM data lo 8b */ -#define REG_SRAM_DATA_1(ie) CRA(0x2,ie&1,0x4e) /* FIFO SRAM data lomid 8b */ -#define REG_SRAM_DATA_2(ie) CRA(0x2,ie&1,0x5e) /* FIFO SRAM data himid 8b */ -#define REG_SRAM_DATA_3(ie) CRA(0x2,ie&1,0x6e) /* FIFO SRAM data hi 8b */ -#define REG_SRAM_DATA_BLK_TYPE(ie) CRA(0x2,ie&1,0x7e) /* FIFO SRAM tag */ -/* REG_ING_CONTROL equals REG_CONTROL with ie = 0, likewise REG_EGR_CONTROL is ie = 1 */ -#define REG_CONTROL(ie) CRA(0x2,ie&1,0x0f) /* FIFO control */ -#define REG_ING_CONTROL CRA(0x2,0x0,0x0f) /* Ingress control (alias) */ -#define REG_EGR_CONTROL CRA(0x2,0x1,0x0f) /* Egress control (alias) */ -#define REG_AGE_TIMER(ie) CRA(0x2,ie&1,0x1f) /* Aging timer */ -#define REG_AGE_INC(ie) CRA(0x2,ie&1,0x2f) /* Aging increment */ -#define DEBUG_OUT(ie) CRA(0x2,ie&1,0x3f) /* Output debug counter control */ -#define DEBUG_CNT(ie) CRA(0x2,ie&1,0x4f) /* Output debug counter */ - -/* SPI4 interface */ -#define REG_SPI4_MISC CRA(0x5,0x0,0x00) /* Misc Register */ -#define REG_SPI4_STATUS CRA(0x5,0x0,0x01) /* CML Status */ -#define REG_SPI4_ING_SETUP0 CRA(0x5,0x0,0x02) /* Ingress Status Channel Setup */ -#define REG_SPI4_ING_SETUP1 CRA(0x5,0x0,0x03) /* Ingress Data Training Setup */ -#define REG_SPI4_ING_SETUP2 CRA(0x5,0x0,0x04) /* Ingress Data Burst Size Setup */ -#define REG_SPI4_EGR_SETUP0 CRA(0x5,0x0,0x05) /* Egress Status Channel Setup */ -#define REG_SPI4_DBG_CNT(n) CRA(0x5,0x0,0x10+n) /* Debug counters 0-9 */ -#define REG_SPI4_DBG_SETUP CRA(0x5,0x0,0x1A) /* Debug counters setup */ -#define REG_SPI4_TEST CRA(0x5,0x0,0x20) /* Test Setup Register */ -#define REG_TPGEN_UP0 CRA(0x5,0x0,0x21) /* Test Pattern generator user pattern 0 */ -#define REG_TPGEN_UP1 CRA(0x5,0x0,0x22) /* Test Pattern generator user pattern 1 */ -#define REG_TPCHK_UP0 CRA(0x5,0x0,0x23) /* Test Pattern checker user pattern 0 */ -#define REG_TPCHK_UP1 CRA(0x5,0x0,0x24) /* Test Pattern checker user pattern 1 */ -#define REG_TPSAM_P0 CRA(0x5,0x0,0x25) /* Sampled pattern 0 */ -#define REG_TPSAM_P1 CRA(0x5,0x0,0x26) /* Sampled pattern 1 */ -#define REG_TPERR_CNT CRA(0x5,0x0,0x27) /* Pattern checker error counter */ -#define REG_SPI4_STICKY CRA(0x5,0x0,0x30) /* Sticky bits register */ -#define REG_SPI4_DBG_INH CRA(0x5,0x0,0x31) /* Core egress & ingress inhibit */ -#define REG_SPI4_DBG_STATUS CRA(0x5,0x0,0x32) /* Sampled ingress status */ -#define REG_SPI4_DBG_GRANT CRA(0x5,0x0,0x33) /* Ingress cranted credit value */ - -#define REG_SPI4_DESKEW CRA(0x5,0x0,0x43) /* Ingress cranted credit value */ - -/* 10GbE MAC Block Registers */ -/* Note that those registers that are exactly the same for 10GbE as for - * tri-speed are only defined with the version that needs a port number. - * Pass 0xa in those cases. - * - * Also note that despite the presence of a MAC address register, this part - * does no ingress MAC address filtering. That register is used only for - * pause frame detection and generation. - */ -/* 10GbE specific, and different from tri-speed */ -#define REG_MISC_10G CRA(0x1,0xa,0x00) /* Misc 10GbE setup */ -#define REG_PAUSE_10G CRA(0x1,0xa,0x01) /* Pause register */ -#define REG_NORMALIZER_10G CRA(0x1,0xa,0x05) /* 10G normalizer */ -#define REG_STICKY_RX CRA(0x1,0xa,0x06) /* RX debug register */ -#define REG_DENORM_10G CRA(0x1,0xa,0x07) /* Denormalizer */ -#define REG_STICKY_TX CRA(0x1,0xa,0x08) /* TX sticky bits */ -#define REG_MAX_RXHIGH CRA(0x1,0xa,0x0a) /* XGMII lane 0-3 debug */ -#define REG_MAX_RXLOW CRA(0x1,0xa,0x0b) /* XGMII lane 4-7 debug */ -#define REG_MAC_TX_STICKY CRA(0x1,0xa,0x0c) /* MAC Tx state sticky debug */ -#define REG_MAC_TX_RUNNING CRA(0x1,0xa,0x0d) /* MAC Tx state running debug */ -#define REG_TX_ABORT_AGE CRA(0x1,0xa,0x14) /* Aged Tx frames discarded */ -#define REG_TX_ABORT_SHORT CRA(0x1,0xa,0x15) /* Short Tx frames discarded */ -#define REG_TX_ABORT_TAXI CRA(0x1,0xa,0x16) /* Taxi error frames discarded */ -#define REG_TX_ABORT_UNDERRUN CRA(0x1,0xa,0x17) /* Tx Underrun abort counter */ -#define REG_TX_DENORM_DISCARD CRA(0x1,0xa,0x18) /* Tx denormalizer discards */ -#define REG_XAUI_STAT_A CRA(0x1,0xa,0x20) /* XAUI status A */ -#define REG_XAUI_STAT_B CRA(0x1,0xa,0x21) /* XAUI status B */ -#define REG_XAUI_STAT_C CRA(0x1,0xa,0x22) /* XAUI status C */ -#define REG_XAUI_CONF_A CRA(0x1,0xa,0x23) /* XAUI configuration A */ -#define REG_XAUI_CONF_B CRA(0x1,0xa,0x24) /* XAUI configuration B */ -#define REG_XAUI_CODE_GRP_CNT CRA(0x1,0xa,0x25) /* XAUI code group error count */ -#define REG_XAUI_CONF_TEST_A CRA(0x1,0xa,0x26) /* XAUI test register A */ -#define REG_PDERRCNT CRA(0x1,0xa,0x27) /* XAUI test register B */ - -/* pn = port number 0-9 for tri-speed, 10 for 10GbE */ -/* Both tri-speed and 10GbE */ -#define REG_MAX_LEN(pn) CRA(0x1,pn,0x02) /* Max length */ -#define REG_MAC_HIGH_ADDR(pn) CRA(0x1,pn,0x03) /* Upper 24 bits of MAC addr */ -#define REG_MAC_LOW_ADDR(pn) CRA(0x1,pn,0x04) /* Lower 24 bits of MAC addr */ - -/* tri-speed only - * pn = port number, 0-9 - */ -#define REG_MODE_CFG(pn) CRA(0x1,pn,0x00) /* Mode configuration */ -#define REG_PAUSE_CFG(pn) CRA(0x1,pn,0x01) /* Pause configuration */ -#define REG_NORMALIZER(pn) CRA(0x1,pn,0x05) /* Normalizer */ -#define REG_TBI_STATUS(pn) CRA(0x1,pn,0x06) /* TBI status */ -#define REG_PCS_STATUS_DBG(pn) CRA(0x1,pn,0x07) /* PCS status debug */ -#define REG_PCS_CTRL(pn) CRA(0x1,pn,0x08) /* PCS control */ -#define REG_TBI_CONFIG(pn) CRA(0x1,pn,0x09) /* TBI configuration */ -#define REG_STICK_BIT(pn) CRA(0x1,pn,0x0a) /* Sticky bits */ -#define REG_DEV_SETUP(pn) CRA(0x1,pn,0x0b) /* MAC clock/reset setup */ -#define REG_DROP_CNT(pn) CRA(0x1,pn,0x0c) /* Drop counter */ -#define REG_PORT_POS(pn) CRA(0x1,pn,0x0d) /* Preamble port position */ -#define REG_PORT_FAIL(pn) CRA(0x1,pn,0x0e) /* Preamble port position */ -#define REG_SERDES_CONF(pn) CRA(0x1,pn,0x0f) /* SerDes configuration */ -#define REG_SERDES_TEST(pn) CRA(0x1,pn,0x10) /* SerDes test */ -#define REG_SERDES_STAT(pn) CRA(0x1,pn,0x11) /* SerDes status */ -#define REG_SERDES_COM_CNT(pn) CRA(0x1,pn,0x12) /* SerDes comma counter */ -#define REG_DENORM(pn) CRA(0x1,pn,0x15) /* Frame denormalization */ -#define REG_DBG(pn) CRA(0x1,pn,0x16) /* Device 1G debug */ -#define REG_TX_IFG(pn) CRA(0x1,pn,0x18) /* Tx IFG config */ -#define REG_HDX(pn) CRA(0x1,pn,0x19) /* Half-duplex config */ - -/* Statistics */ -/* CRA(0x4,pn,reg) */ -/* reg below */ -/* pn = port number, 0-a, a = 10GbE */ - -enum { - RxInBytes = 0x00, // # Rx in octets - RxSymbolCarrier = 0x01, // Frames w/ symbol errors - RxPause = 0x02, // # pause frames received - RxUnsupOpcode = 0x03, // # control frames with unsupported opcode - RxOkBytes = 0x04, // # octets in good frames - RxBadBytes = 0x05, // # octets in bad frames - RxUnicast = 0x06, // # good unicast frames - RxMulticast = 0x07, // # good multicast frames - RxBroadcast = 0x08, // # good broadcast frames - Crc = 0x09, // # frames w/ bad CRC only - RxAlignment = 0x0a, // # frames w/ alignment err - RxUndersize = 0x0b, // # frames undersize - RxFragments = 0x0c, // # frames undersize w/ crc err - RxInRangeLengthError = 0x0d, // # frames with length error - RxOutOfRangeError = 0x0e, // # frames with illegal length field - RxOversize = 0x0f, // # frames oversize - RxJabbers = 0x10, // # frames oversize w/ crc err - RxSize64 = 0x11, // # frames 64 octets long - RxSize65To127 = 0x12, // # frames 65-127 octets - RxSize128To255 = 0x13, // # frames 128-255 - RxSize256To511 = 0x14, // # frames 256-511 - RxSize512To1023 = 0x15, // # frames 512-1023 - RxSize1024To1518 = 0x16, // # frames 1024-1518 - RxSize1519ToMax = 0x17, // # frames 1519-max - - TxOutBytes = 0x18, // # octets tx - TxPause = 0x19, // # pause frames sent - TxOkBytes = 0x1a, // # octets tx OK - TxUnicast = 0x1b, // # frames unicast - TxMulticast = 0x1c, // # frames multicast - TxBroadcast = 0x1d, // # frames broadcast - TxMultipleColl = 0x1e, // # frames tx after multiple collisions - TxLateColl = 0x1f, // # late collisions detected - TxXcoll = 0x20, // # frames lost, excessive collisions - TxDefer = 0x21, // # frames deferred on first tx attempt - TxXdefer = 0x22, // # frames excessively deferred - TxCsense = 0x23, // carrier sense errors at frame end - TxSize64 = 0x24, // # frames 64 octets long - TxSize65To127 = 0x25, // # frames 65-127 octets - TxSize128To255 = 0x26, // # frames 128-255 - TxSize256To511 = 0x27, // # frames 256-511 - TxSize512To1023 = 0x28, // # frames 512-1023 - TxSize1024To1518 = 0x29, // # frames 1024-1518 - TxSize1519ToMax = 0x2a, // # frames 1519-max - TxSingleColl = 0x2b, // # frames tx after single collision - TxBackoff2 = 0x2c, // # frames tx ok after 2 backoffs/collisions - TxBackoff3 = 0x2d, // after 3 backoffs/collisions - TxBackoff4 = 0x2e, // after 4 - TxBackoff5 = 0x2f, // after 5 - TxBackoff6 = 0x30, // after 6 - TxBackoff7 = 0x31, // after 7 - TxBackoff8 = 0x32, // after 8 - TxBackoff9 = 0x33, // after 9 - TxBackoff10 = 0x34, // after 10 - TxBackoff11 = 0x35, // after 11 - TxBackoff12 = 0x36, // after 12 - TxBackoff13 = 0x37, // after 13 - TxBackoff14 = 0x38, // after 14 - TxBackoff15 = 0x39, // after 15 - TxUnderrun = 0x3a, // # frames dropped from underrun - // Hole. See REG_RX_XGMII_PROT_ERR below. - RxIpgShrink = 0x3c, // # of IPG shrinks detected - // Duplicate. See REG_STAT_STICKY10G below. - StatSticky1G = 0x3e, // tri-speed sticky bits - StatInit = 0x3f // Clear all statistics -}; - -#define REG_RX_XGMII_PROT_ERR CRA(0x4,0xa,0x3b) /* # protocol errors detected on XGMII interface */ -#define REG_STAT_STICKY10G CRA(0x4,0xa,StatSticky1G) /* 10GbE sticky bits */ - -#define REG_RX_OK_BYTES(pn) CRA(0x4,pn,RxOkBytes) -#define REG_RX_BAD_BYTES(pn) CRA(0x4,pn,RxBadBytes) -#define REG_TX_OK_BYTES(pn) CRA(0x4,pn,TxOkBytes) - -/* MII-Management Block registers */ -/* These are for MII-M interface 0, which is the bidirectional LVTTL one. If - * we hooked up to the one with separate directions, the middle 0x0 needs to - * change to 0x1. And the current errata states that MII-M 1 doesn't work. - */ - -#define REG_MIIM_STATUS CRA(0x3,0x0,0x00) /* MII-M Status */ -#define REG_MIIM_CMD CRA(0x3,0x0,0x01) /* MII-M Command */ -#define REG_MIIM_DATA CRA(0x3,0x0,0x02) /* MII-M Data */ -#define REG_MIIM_PRESCALE CRA(0x3,0x0,0x03) /* MII-M MDC Prescale */ - -#define REG_ING_FFILT_UM_EN CRA(0x2, 0, 0xd) -#define REG_ING_FFILT_BE_EN CRA(0x2, 0, 0x1d) -#define REG_ING_FFILT_VAL0 CRA(0x2, 0, 0x2d) -#define REG_ING_FFILT_VAL1 CRA(0x2, 0, 0x3d) -#define REG_ING_FFILT_MASK0 CRA(0x2, 0, 0x4d) -#define REG_ING_FFILT_MASK1 CRA(0x2, 0, 0x5d) -#define REG_ING_FFILT_MASK2 CRA(0x2, 0, 0x6d) -#define REG_ING_FFILT_ETYPE CRA(0x2, 0, 0x7d) - - -/* Whew. */ - -#endif diff --git a/drivers/net/cxgb3/Makefile b/drivers/net/cxgb3/Makefile deleted file mode 100644 index 29aff78c7820..000000000000 --- a/drivers/net/cxgb3/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Chelsio T3 driver -# - -obj-$(CONFIG_CHELSIO_T3) += cxgb3.o - -cxgb3-objs := cxgb3_main.o ael1002.o vsc8211.o t3_hw.o mc5.o \ - xgmac.o sge.o l2t.o cxgb3_offload.o aq100x.o diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h deleted file mode 100644 index 8b395b537330..000000000000 --- a/drivers/net/cxgb3/adapter.h +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* This file should not be included directly. Include common.h instead. */ - -#ifndef __T3_ADAPTER_H__ -#define __T3_ADAPTER_H__ - -#include -#include -#include -#include -#include -#include -#include -#include "t3cdev.h" -#include - -struct adapter; -struct sge_qset; -struct port_info; - -enum mac_idx_types { - LAN_MAC_IDX = 0, - SAN_MAC_IDX, - - MAX_MAC_IDX -}; - -struct iscsi_config { - __u8 mac_addr[ETH_ALEN]; - __u32 flags; - int (*send)(struct port_info *pi, struct sk_buff **skb); - int (*recv)(struct port_info *pi, struct sk_buff *skb); -}; - -struct port_info { - struct adapter *adapter; - struct sge_qset *qs; - u8 port_id; - u8 nqsets; - u8 first_qset; - struct cphy phy; - struct cmac mac; - struct link_config link_config; - struct net_device_stats netstats; - int activity; - __be32 iscsi_ipv4addr; - struct iscsi_config iscsic; - - int link_fault; /* link fault was detected */ -}; - -enum { /* adapter flags */ - FULL_INIT_DONE = (1 << 0), - USING_MSI = (1 << 1), - USING_MSIX = (1 << 2), - QUEUES_BOUND = (1 << 3), - TP_PARITY_INIT = (1 << 4), - NAPI_INIT = (1 << 5), -}; - -struct fl_pg_chunk { - struct page *page; - void *va; - unsigned int offset; - unsigned long *p_cnt; - dma_addr_t mapping; -}; - -struct rx_desc; -struct rx_sw_desc; - -struct sge_fl { /* SGE per free-buffer list state */ - unsigned int buf_size; /* size of each Rx buffer */ - unsigned int credits; /* # of available Rx buffers */ - unsigned int pend_cred; /* new buffers since last FL DB ring */ - unsigned int size; /* capacity of free list */ - unsigned int cidx; /* consumer index */ - unsigned int pidx; /* producer index */ - unsigned int gen; /* free list generation */ - struct fl_pg_chunk pg_chunk;/* page chunk cache */ - unsigned int use_pages; /* whether FL uses pages or sk_buffs */ - unsigned int order; /* order of page allocations */ - unsigned int alloc_size; /* size of allocated buffer */ - struct rx_desc *desc; /* address of HW Rx descriptor ring */ - struct rx_sw_desc *sdesc; /* address of SW Rx descriptor ring */ - dma_addr_t phys_addr; /* physical address of HW ring start */ - unsigned int cntxt_id; /* SGE context id for the free list */ - unsigned long empty; /* # of times queue ran out of buffers */ - unsigned long alloc_failed; /* # of times buffer allocation failed */ -}; - -/* - * Bundle size for grouping offload RX packets for delivery to the stack. - * Don't make this too big as we do prefetch on each packet in a bundle. - */ -# define RX_BUNDLE_SIZE 8 - -struct rsp_desc; - -struct sge_rspq { /* state for an SGE response queue */ - unsigned int credits; /* # of pending response credits */ - unsigned int size; /* capacity of response queue */ - unsigned int cidx; /* consumer index */ - unsigned int gen; /* current generation bit */ - unsigned int polling; /* is the queue serviced through NAPI? */ - unsigned int holdoff_tmr; /* interrupt holdoff timer in 100ns */ - unsigned int next_holdoff; /* holdoff time for next interrupt */ - unsigned int rx_recycle_buf; /* whether recycling occurred - within current sop-eop */ - struct rsp_desc *desc; /* address of HW response ring */ - dma_addr_t phys_addr; /* physical address of the ring */ - unsigned int cntxt_id; /* SGE context id for the response q */ - spinlock_t lock; /* guards response processing */ - struct sk_buff_head rx_queue; /* offload packet receive queue */ - struct sk_buff *pg_skb; /* used to build frag list in napi handler */ - - unsigned long offload_pkts; - unsigned long offload_bundles; - unsigned long eth_pkts; /* # of ethernet packets */ - unsigned long pure_rsps; /* # of pure (non-data) responses */ - unsigned long imm_data; /* responses with immediate data */ - unsigned long rx_drops; /* # of packets dropped due to no mem */ - unsigned long async_notif; /* # of asynchronous notification events */ - unsigned long empty; /* # of times queue ran out of credits */ - unsigned long nomem; /* # of responses deferred due to no mem */ - unsigned long unhandled_irqs; /* # of spurious intrs */ - unsigned long starved; - unsigned long restarted; -}; - -struct tx_desc; -struct tx_sw_desc; - -struct sge_txq { /* state for an SGE Tx queue */ - unsigned long flags; /* HW DMA fetch status */ - unsigned int in_use; /* # of in-use Tx descriptors */ - unsigned int size; /* # of descriptors */ - unsigned int processed; /* total # of descs HW has processed */ - unsigned int cleaned; /* total # of descs SW has reclaimed */ - unsigned int stop_thres; /* SW TX queue suspend threshold */ - unsigned int cidx; /* consumer index */ - unsigned int pidx; /* producer index */ - unsigned int gen; /* current value of generation bit */ - unsigned int unacked; /* Tx descriptors used since last COMPL */ - struct tx_desc *desc; /* address of HW Tx descriptor ring */ - struct tx_sw_desc *sdesc; /* address of SW Tx descriptor ring */ - spinlock_t lock; /* guards enqueueing of new packets */ - unsigned int token; /* WR token */ - dma_addr_t phys_addr; /* physical address of the ring */ - struct sk_buff_head sendq; /* List of backpressured offload packets */ - struct tasklet_struct qresume_tsk; /* restarts the queue */ - unsigned int cntxt_id; /* SGE context id for the Tx q */ - unsigned long stops; /* # of times q has been stopped */ - unsigned long restarts; /* # of queue restarts */ -}; - -enum { /* per port SGE statistics */ - SGE_PSTAT_TSO, /* # of TSO requests */ - SGE_PSTAT_RX_CSUM_GOOD, /* # of successful RX csum offloads */ - SGE_PSTAT_TX_CSUM, /* # of TX checksum offloads */ - SGE_PSTAT_VLANEX, /* # of VLAN tag extractions */ - SGE_PSTAT_VLANINS, /* # of VLAN tag insertions */ - - SGE_PSTAT_MAX /* must be last */ -}; - -struct napi_gro_fraginfo; - -struct sge_qset { /* an SGE queue set */ - struct adapter *adap; - struct napi_struct napi; - struct sge_rspq rspq; - struct sge_fl fl[SGE_RXQ_PER_SET]; - struct sge_txq txq[SGE_TXQ_PER_SET]; - int nomem; - void *lro_va; - struct net_device *netdev; - struct netdev_queue *tx_q; /* associated netdev TX queue */ - unsigned long txq_stopped; /* which Tx queues are stopped */ - struct timer_list tx_reclaim_timer; /* reclaims TX buffers */ - struct timer_list rx_reclaim_timer; /* reclaims RX buffers */ - unsigned long port_stats[SGE_PSTAT_MAX]; -} ____cacheline_aligned; - -struct sge { - struct sge_qset qs[SGE_QSETS]; - spinlock_t reg_lock; /* guards non-atomic SGE registers (eg context) */ -}; - -struct adapter { - struct t3cdev tdev; - struct list_head adapter_list; - void __iomem *regs; - struct pci_dev *pdev; - unsigned long registered_device_map; - unsigned long open_device_map; - unsigned long flags; - - const char *name; - int msg_enable; - unsigned int mmio_len; - - struct adapter_params params; - unsigned int slow_intr_mask; - unsigned long irq_stats[IRQ_NUM_STATS]; - - int msix_nvectors; - struct { - unsigned short vec; - char desc[22]; - } msix_info[SGE_QSETS + 1]; - - /* T3 modules */ - struct sge sge; - struct mc7 pmrx; - struct mc7 pmtx; - struct mc7 cm; - struct mc5 mc5; - - struct net_device *port[MAX_NPORTS]; - unsigned int check_task_cnt; - struct delayed_work adap_check_task; - struct work_struct ext_intr_handler_task; - struct work_struct fatal_error_handler_task; - struct work_struct link_fault_handler_task; - - struct work_struct db_full_task; - struct work_struct db_empty_task; - struct work_struct db_drop_task; - - struct dentry *debugfs_root; - - struct mutex mdio_lock; - spinlock_t stats_lock; - spinlock_t work_lock; - - struct sk_buff *nofail_skb; -}; - -static inline u32 t3_read_reg(struct adapter *adapter, u32 reg_addr) -{ - u32 val = readl(adapter->regs + reg_addr); - - CH_DBG(adapter, MMIO, "read register 0x%x value 0x%x\n", reg_addr, val); - return val; -} - -static inline void t3_write_reg(struct adapter *adapter, u32 reg_addr, u32 val) -{ - CH_DBG(adapter, MMIO, "setting register 0x%x to 0x%x\n", reg_addr, val); - writel(val, adapter->regs + reg_addr); -} - -static inline struct port_info *adap2pinfo(struct adapter *adap, int idx) -{ - return netdev_priv(adap->port[idx]); -} - -static inline int phy2portid(struct cphy *phy) -{ - struct adapter *adap = phy->adapter; - struct port_info *port0 = adap2pinfo(adap, 0); - - return &port0->phy == phy ? 0 : 1; -} - -#define OFFLOAD_DEVMAP_BIT 15 - -#define tdev2adap(d) container_of(d, struct adapter, tdev) - -static inline int offload_running(struct adapter *adapter) -{ - return test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map); -} - -int t3_offload_tx(struct t3cdev *tdev, struct sk_buff *skb); - -void t3_os_ext_intr_handler(struct adapter *adapter); -void t3_os_link_changed(struct adapter *adapter, int port_id, int link_status, - int speed, int duplex, int fc); -void t3_os_phymod_changed(struct adapter *adap, int port_id); -void t3_os_link_fault(struct adapter *adapter, int port_id, int state); -void t3_os_link_fault_handler(struct adapter *adapter, int port_id); - -void t3_sge_start(struct adapter *adap); -void t3_sge_stop(struct adapter *adap); -void t3_start_sge_timers(struct adapter *adap); -void t3_stop_sge_timers(struct adapter *adap); -void t3_free_sge_resources(struct adapter *adap); -void t3_sge_err_intr_handler(struct adapter *adapter); -irq_handler_t t3_intr_handler(struct adapter *adap, int polling); -netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev); -int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb); -void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p); -int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, - int irq_vec_idx, const struct qset_params *p, - int ntxq, struct net_device *dev, - struct netdev_queue *netdevq); -extern struct workqueue_struct *cxgb3_wq; - -int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size); - -#endif /* __T3_ADAPTER_H__ */ diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c deleted file mode 100644 index 2028da95afa1..000000000000 --- a/drivers/net/cxgb3/ael1002.c +++ /dev/null @@ -1,941 +0,0 @@ -/* - * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#include "common.h" -#include "regs.h" - -enum { - AEL100X_TX_CONFIG1 = 0xc002, - AEL1002_PWR_DOWN_HI = 0xc011, - AEL1002_PWR_DOWN_LO = 0xc012, - AEL1002_XFI_EQL = 0xc015, - AEL1002_LB_EN = 0xc017, - AEL_OPT_SETTINGS = 0xc017, - AEL_I2C_CTRL = 0xc30a, - AEL_I2C_DATA = 0xc30b, - AEL_I2C_STAT = 0xc30c, - AEL2005_GPIO_CTRL = 0xc214, - AEL2005_GPIO_STAT = 0xc215, - - AEL2020_GPIO_INTR = 0xc103, /* Latch High (LH) */ - AEL2020_GPIO_CTRL = 0xc108, /* Store Clear (SC) */ - AEL2020_GPIO_STAT = 0xc10c, /* Read Only (RO) */ - AEL2020_GPIO_CFG = 0xc110, /* Read Write (RW) */ - - AEL2020_GPIO_SDA = 0, /* IN: i2c serial data */ - AEL2020_GPIO_MODDET = 1, /* IN: Module Detect */ - AEL2020_GPIO_0 = 3, /* IN: unassigned */ - AEL2020_GPIO_1 = 2, /* OUT: unassigned */ - AEL2020_GPIO_LSTAT = AEL2020_GPIO_1, /* wired to link status LED */ -}; - -enum { edc_none, edc_sr, edc_twinax }; - -/* PHY module I2C device address */ -enum { - MODULE_DEV_ADDR = 0xa0, - SFF_DEV_ADDR = 0xa2, -}; - -/* PHY transceiver type */ -enum { - phy_transtype_unknown = 0, - phy_transtype_sfp = 3, - phy_transtype_xfp = 6, -}; - -#define AEL2005_MODDET_IRQ 4 - -struct reg_val { - unsigned short mmd_addr; - unsigned short reg_addr; - unsigned short clear_bits; - unsigned short set_bits; -}; - -static int set_phy_regs(struct cphy *phy, const struct reg_val *rv) -{ - int err; - - for (err = 0; rv->mmd_addr && !err; rv++) { - if (rv->clear_bits == 0xffff) - err = t3_mdio_write(phy, rv->mmd_addr, rv->reg_addr, - rv->set_bits); - else - err = t3_mdio_change_bits(phy, rv->mmd_addr, - rv->reg_addr, rv->clear_bits, - rv->set_bits); - } - return err; -} - -static void ael100x_txon(struct cphy *phy) -{ - int tx_on_gpio = - phy->mdio.prtad == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL; - - msleep(100); - t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio); - msleep(30); -} - -/* - * Read an 8-bit word from a device attached to the PHY's i2c bus. - */ -static int ael_i2c_rd(struct cphy *phy, int dev_addr, int word_addr) -{ - int i, err; - unsigned int stat, data; - - err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL_I2C_CTRL, - (dev_addr << 8) | (1 << 8) | word_addr); - if (err) - return err; - - for (i = 0; i < 200; i++) { - msleep(1); - err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_STAT, &stat); - if (err) - return err; - if ((stat & 3) == 1) { - err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_DATA, - &data); - if (err) - return err; - return data >> 8; - } - } - CH_WARN(phy->adapter, "PHY %u i2c read of dev.addr %#x.%#x timed out\n", - phy->mdio.prtad, dev_addr, word_addr); - return -ETIMEDOUT; -} - -static int ael1002_power_down(struct cphy *phy, int enable) -{ - int err; - - err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, MDIO_PMA_TXDIS, !!enable); - if (!err) - err = mdio_set_flag(&phy->mdio, phy->mdio.prtad, - MDIO_MMD_PMAPMD, MDIO_CTRL1, - MDIO_CTRL1_LPOWER, enable); - return err; -} - -static int ael1002_reset(struct cphy *phy, int wait) -{ - int err; - - if ((err = ael1002_power_down(phy, 0)) || - (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL100X_TX_CONFIG1, 1)) || - (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL1002_PWR_DOWN_HI, 0)) || - (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL1002_PWR_DOWN_LO, 0)) || - (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL1002_XFI_EQL, 0x18)) || - (err = t3_mdio_change_bits(phy, MDIO_MMD_PMAPMD, AEL1002_LB_EN, - 0, 1 << 5))) - return err; - return 0; -} - -static int ael1002_intr_noop(struct cphy *phy) -{ - return 0; -} - -/* - * Get link status for a 10GBASE-R device. - */ -static int get_link_status_r(struct cphy *phy, int *link_ok, int *speed, - int *duplex, int *fc) -{ - if (link_ok) { - unsigned int stat0, stat1, stat2; - int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, - MDIO_PMA_RXDET, &stat0); - - if (!err) - err = t3_mdio_read(phy, MDIO_MMD_PCS, - MDIO_PCS_10GBRT_STAT1, &stat1); - if (!err) - err = t3_mdio_read(phy, MDIO_MMD_PHYXS, - MDIO_PHYXS_LNSTAT, &stat2); - if (err) - return err; - *link_ok = (stat0 & stat1 & (stat2 >> 12)) & 1; - } - if (speed) - *speed = SPEED_10000; - if (duplex) - *duplex = DUPLEX_FULL; - return 0; -} - -static struct cphy_ops ael1002_ops = { - .reset = ael1002_reset, - .intr_enable = ael1002_intr_noop, - .intr_disable = ael1002_intr_noop, - .intr_clear = ael1002_intr_noop, - .intr_handler = ael1002_intr_noop, - .get_link_status = get_link_status_r, - .power_down = ael1002_power_down, - .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, -}; - -int t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter, - int phy_addr, const struct mdio_ops *mdio_ops) -{ - cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops, - SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE, - "10GBASE-R"); - ael100x_txon(phy); - return 0; -} - -static int ael1006_reset(struct cphy *phy, int wait) -{ - return t3_phy_reset(phy, MDIO_MMD_PMAPMD, wait); -} - -static struct cphy_ops ael1006_ops = { - .reset = ael1006_reset, - .intr_enable = t3_phy_lasi_intr_enable, - .intr_disable = t3_phy_lasi_intr_disable, - .intr_clear = t3_phy_lasi_intr_clear, - .intr_handler = t3_phy_lasi_intr_handler, - .get_link_status = get_link_status_r, - .power_down = ael1002_power_down, - .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, -}; - -int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter, - int phy_addr, const struct mdio_ops *mdio_ops) -{ - cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops, - SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE, - "10GBASE-SR"); - ael100x_txon(phy); - return 0; -} - -/* - * Decode our module type. - */ -static int ael2xxx_get_module_type(struct cphy *phy, int delay_ms) -{ - int v; - - if (delay_ms) - msleep(delay_ms); - - /* see SFF-8472 for below */ - v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 3); - if (v < 0) - return v; - - if (v == 0x10) - return phy_modtype_sr; - if (v == 0x20) - return phy_modtype_lr; - if (v == 0x40) - return phy_modtype_lrm; - - v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 6); - if (v < 0) - return v; - if (v != 4) - goto unknown; - - v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 10); - if (v < 0) - return v; - - if (v & 0x80) { - v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 0x12); - if (v < 0) - return v; - return v > 10 ? phy_modtype_twinax_long : phy_modtype_twinax; - } -unknown: - return phy_modtype_unknown; -} - -/* - * Code to support the Aeluros/NetLogic 2005 10Gb PHY. - */ -static int ael2005_setup_sr_edc(struct cphy *phy) -{ - static const struct reg_val regs[] = { - { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x181 }, - { MDIO_MMD_PMAPMD, 0xc010, 0xffff, 0x448a }, - { MDIO_MMD_PMAPMD, 0xc04a, 0xffff, 0x5200 }, - { 0, 0, 0, 0 } - }; - - int i, err; - - err = set_phy_regs(phy, regs); - if (err) - return err; - - msleep(50); - - if (phy->priv != edc_sr) - err = t3_get_edc_fw(phy, EDC_OPT_AEL2005, - EDC_OPT_AEL2005_SIZE); - if (err) - return err; - - for (i = 0; i < EDC_OPT_AEL2005_SIZE / sizeof(u16) && !err; i += 2) - err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, - phy->phy_cache[i], - phy->phy_cache[i + 1]); - if (!err) - phy->priv = edc_sr; - return err; -} - -static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype) -{ - static const struct reg_val regs[] = { - { MDIO_MMD_PMAPMD, 0xc04a, 0xffff, 0x5a00 }, - { 0, 0, 0, 0 } - }; - static const struct reg_val preemphasis[] = { - { MDIO_MMD_PMAPMD, 0xc014, 0xffff, 0xfe16 }, - { MDIO_MMD_PMAPMD, 0xc015, 0xffff, 0xa000 }, - { 0, 0, 0, 0 } - }; - int i, err; - - err = set_phy_regs(phy, regs); - if (!err && modtype == phy_modtype_twinax_long) - err = set_phy_regs(phy, preemphasis); - if (err) - return err; - - msleep(50); - - if (phy->priv != edc_twinax) - err = t3_get_edc_fw(phy, EDC_TWX_AEL2005, - EDC_TWX_AEL2005_SIZE); - if (err) - return err; - - for (i = 0; i < EDC_TWX_AEL2005_SIZE / sizeof(u16) && !err; i += 2) - err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, - phy->phy_cache[i], - phy->phy_cache[i + 1]); - if (!err) - phy->priv = edc_twinax; - return err; -} - -static int ael2005_get_module_type(struct cphy *phy, int delay_ms) -{ - int v; - unsigned int stat; - - v = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, &stat); - if (v) - return v; - - if (stat & (1 << 8)) /* module absent */ - return phy_modtype_none; - - return ael2xxx_get_module_type(phy, delay_ms); -} - -static int ael2005_intr_enable(struct cphy *phy) -{ - int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, 0x200); - return err ? err : t3_phy_lasi_intr_enable(phy); -} - -static int ael2005_intr_disable(struct cphy *phy) -{ - int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, 0x100); - return err ? err : t3_phy_lasi_intr_disable(phy); -} - -static int ael2005_intr_clear(struct cphy *phy) -{ - int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, 0xd00); - return err ? err : t3_phy_lasi_intr_clear(phy); -} - -static int ael2005_reset(struct cphy *phy, int wait) -{ - static const struct reg_val regs0[] = { - { MDIO_MMD_PMAPMD, 0xc001, 0, 1 << 5 }, - { MDIO_MMD_PMAPMD, 0xc017, 0, 1 << 5 }, - { MDIO_MMD_PMAPMD, 0xc013, 0xffff, 0xf341 }, - { MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0x8000 }, - { MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0x8100 }, - { MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0x8000 }, - { MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0 }, - { 0, 0, 0, 0 } - }; - static const struct reg_val regs1[] = { - { MDIO_MMD_PMAPMD, 0xca00, 0xffff, 0x0080 }, - { MDIO_MMD_PMAPMD, 0xca12, 0xffff, 0 }, - { 0, 0, 0, 0 } - }; - - int err; - unsigned int lasi_ctrl; - - err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, - &lasi_ctrl); - if (err) - return err; - - err = t3_phy_reset(phy, MDIO_MMD_PMAPMD, 0); - if (err) - return err; - - msleep(125); - phy->priv = edc_none; - err = set_phy_regs(phy, regs0); - if (err) - return err; - - msleep(50); - - err = ael2005_get_module_type(phy, 0); - if (err < 0) - return err; - phy->modtype = err; - - if (err == phy_modtype_twinax || err == phy_modtype_twinax_long) - err = ael2005_setup_twinax_edc(phy, err); - else - err = ael2005_setup_sr_edc(phy); - if (err) - return err; - - err = set_phy_regs(phy, regs1); - if (err) - return err; - - /* reset wipes out interrupts, reenable them if they were on */ - if (lasi_ctrl & 1) - err = ael2005_intr_enable(phy); - return err; -} - -static int ael2005_intr_handler(struct cphy *phy) -{ - unsigned int stat; - int ret, edc_needed, cause = 0; - - ret = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_STAT, &stat); - if (ret) - return ret; - - if (stat & AEL2005_MODDET_IRQ) { - ret = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, - 0xd00); - if (ret) - return ret; - - /* modules have max 300 ms init time after hot plug */ - ret = ael2005_get_module_type(phy, 300); - if (ret < 0) - return ret; - - phy->modtype = ret; - if (ret == phy_modtype_none) - edc_needed = phy->priv; /* on unplug retain EDC */ - else if (ret == phy_modtype_twinax || - ret == phy_modtype_twinax_long) - edc_needed = edc_twinax; - else - edc_needed = edc_sr; - - if (edc_needed != phy->priv) { - ret = ael2005_reset(phy, 0); - return ret ? ret : cphy_cause_module_change; - } - cause = cphy_cause_module_change; - } - - ret = t3_phy_lasi_intr_handler(phy); - if (ret < 0) - return ret; - - ret |= cause; - return ret ? ret : cphy_cause_link_change; -} - -static struct cphy_ops ael2005_ops = { - .reset = ael2005_reset, - .intr_enable = ael2005_intr_enable, - .intr_disable = ael2005_intr_disable, - .intr_clear = ael2005_intr_clear, - .intr_handler = ael2005_intr_handler, - .get_link_status = get_link_status_r, - .power_down = ael1002_power_down, - .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, -}; - -int t3_ael2005_phy_prep(struct cphy *phy, struct adapter *adapter, - int phy_addr, const struct mdio_ops *mdio_ops) -{ - cphy_init(phy, adapter, phy_addr, &ael2005_ops, mdio_ops, - SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE | - SUPPORTED_IRQ, "10GBASE-R"); - msleep(125); - return t3_mdio_change_bits(phy, MDIO_MMD_PMAPMD, AEL_OPT_SETTINGS, 0, - 1 << 5); -} - -/* - * Setup EDC and other parameters for operation with an optical module. - */ -static int ael2020_setup_sr_edc(struct cphy *phy) -{ - static const struct reg_val regs[] = { - /* set CDR offset to 10 */ - { MDIO_MMD_PMAPMD, 0xcc01, 0xffff, 0x488a }, - - /* adjust 10G RX bias current */ - { MDIO_MMD_PMAPMD, 0xcb1b, 0xffff, 0x0200 }, - { MDIO_MMD_PMAPMD, 0xcb1c, 0xffff, 0x00f0 }, - { MDIO_MMD_PMAPMD, 0xcc06, 0xffff, 0x00e0 }, - - /* end */ - { 0, 0, 0, 0 } - }; - int err; - - err = set_phy_regs(phy, regs); - msleep(50); - if (err) - return err; - - phy->priv = edc_sr; - return 0; -} - -/* - * Setup EDC and other parameters for operation with an TWINAX module. - */ -static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype) -{ - /* set uC to 40MHz */ - static const struct reg_val uCclock40MHz[] = { - { MDIO_MMD_PMAPMD, 0xff28, 0xffff, 0x4001 }, - { MDIO_MMD_PMAPMD, 0xff2a, 0xffff, 0x0002 }, - { 0, 0, 0, 0 } - }; - - /* activate uC clock */ - static const struct reg_val uCclockActivate[] = { - { MDIO_MMD_PMAPMD, 0xd000, 0xffff, 0x5200 }, - { 0, 0, 0, 0 } - }; - - /* set PC to start of SRAM and activate uC */ - static const struct reg_val uCactivate[] = { - { MDIO_MMD_PMAPMD, 0xd080, 0xffff, 0x0100 }, - { MDIO_MMD_PMAPMD, 0xd092, 0xffff, 0x0000 }, - { 0, 0, 0, 0 } - }; - int i, err; - - /* set uC clock and activate it */ - err = set_phy_regs(phy, uCclock40MHz); - msleep(500); - if (err) - return err; - err = set_phy_regs(phy, uCclockActivate); - msleep(500); - if (err) - return err; - - if (phy->priv != edc_twinax) - err = t3_get_edc_fw(phy, EDC_TWX_AEL2020, - EDC_TWX_AEL2020_SIZE); - if (err) - return err; - - for (i = 0; i < EDC_TWX_AEL2020_SIZE / sizeof(u16) && !err; i += 2) - err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, - phy->phy_cache[i], - phy->phy_cache[i + 1]); - /* activate uC */ - err = set_phy_regs(phy, uCactivate); - if (!err) - phy->priv = edc_twinax; - return err; -} - -/* - * Return Module Type. - */ -static int ael2020_get_module_type(struct cphy *phy, int delay_ms) -{ - int v; - unsigned int stat; - - v = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_STAT, &stat); - if (v) - return v; - - if (stat & (0x1 << (AEL2020_GPIO_MODDET*4))) { - /* module absent */ - return phy_modtype_none; - } - - return ael2xxx_get_module_type(phy, delay_ms); -} - -/* - * Enable PHY interrupts. We enable "Module Detection" interrupts (on any - * state transition) and then generic Link Alarm Status Interrupt (LASI). - */ -static int ael2020_intr_enable(struct cphy *phy) -{ - static const struct reg_val regs[] = { - /* output Module's Loss Of Signal (LOS) to LED */ - { MDIO_MMD_PMAPMD, AEL2020_GPIO_CFG+AEL2020_GPIO_LSTAT, - 0xffff, 0x4 }, - { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, - 0xffff, 0x8 << (AEL2020_GPIO_LSTAT*4) }, - - /* enable module detect status change interrupts */ - { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, - 0xffff, 0x2 << (AEL2020_GPIO_MODDET*4) }, - - /* end */ - { 0, 0, 0, 0 } - }; - int err, link_ok = 0; - - /* set up "link status" LED and enable module change interrupts */ - err = set_phy_regs(phy, regs); - if (err) - return err; - - err = get_link_status_r(phy, &link_ok, NULL, NULL, NULL); - if (err) - return err; - if (link_ok) - t3_link_changed(phy->adapter, - phy2portid(phy)); - - err = t3_phy_lasi_intr_enable(phy); - if (err) - return err; - - return 0; -} - -/* - * Disable PHY interrupts. The mirror of the above ... - */ -static int ael2020_intr_disable(struct cphy *phy) -{ - static const struct reg_val regs[] = { - /* reset "link status" LED to "off" */ - { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, - 0xffff, 0xb << (AEL2020_GPIO_LSTAT*4) }, - - /* disable module detect status change interrupts */ - { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, - 0xffff, 0x1 << (AEL2020_GPIO_MODDET*4) }, - - /* end */ - { 0, 0, 0, 0 } - }; - int err; - - /* turn off "link status" LED and disable module change interrupts */ - err = set_phy_regs(phy, regs); - if (err) - return err; - - return t3_phy_lasi_intr_disable(phy); -} - -/* - * Clear PHY interrupt state. - */ -static int ael2020_intr_clear(struct cphy *phy) -{ - /* - * The GPIO Interrupt register on the AEL2020 is a "Latching High" - * (LH) register which is cleared to the current state when it's read. - * Thus, we simply read the register and discard the result. - */ - unsigned int stat; - int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_INTR, &stat); - return err ? err : t3_phy_lasi_intr_clear(phy); -} - -static const struct reg_val ael2020_reset_regs[] = { - /* Erratum #2: CDRLOL asserted, causing PMA link down status */ - { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x3101 }, - - /* force XAUI to send LF when RX_LOS is asserted */ - { MDIO_MMD_PMAPMD, 0xcd40, 0xffff, 0x0001 }, - - /* allow writes to transceiver module EEPROM on i2c bus */ - { MDIO_MMD_PMAPMD, 0xff02, 0xffff, 0x0023 }, - { MDIO_MMD_PMAPMD, 0xff03, 0xffff, 0x0000 }, - { MDIO_MMD_PMAPMD, 0xff04, 0xffff, 0x0000 }, - - /* end */ - { 0, 0, 0, 0 } -}; -/* - * Reset the PHY and put it into a canonical operating state. - */ -static int ael2020_reset(struct cphy *phy, int wait) -{ - int err; - unsigned int lasi_ctrl; - - /* grab current interrupt state */ - err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, - &lasi_ctrl); - if (err) - return err; - - err = t3_phy_reset(phy, MDIO_MMD_PMAPMD, 125); - if (err) - return err; - msleep(100); - - /* basic initialization for all module types */ - phy->priv = edc_none; - err = set_phy_regs(phy, ael2020_reset_regs); - if (err) - return err; - - /* determine module type and perform appropriate initialization */ - err = ael2020_get_module_type(phy, 0); - if (err < 0) - return err; - phy->modtype = (u8)err; - if (err == phy_modtype_twinax || err == phy_modtype_twinax_long) - err = ael2020_setup_twinax_edc(phy, err); - else - err = ael2020_setup_sr_edc(phy); - if (err) - return err; - - /* reset wipes out interrupts, reenable them if they were on */ - if (lasi_ctrl & 1) - err = ael2005_intr_enable(phy); - return err; -} - -/* - * Handle a PHY interrupt. - */ -static int ael2020_intr_handler(struct cphy *phy) -{ - unsigned int stat; - int ret, edc_needed, cause = 0; - - ret = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_INTR, &stat); - if (ret) - return ret; - - if (stat & (0x1 << AEL2020_GPIO_MODDET)) { - /* modules have max 300 ms init time after hot plug */ - ret = ael2020_get_module_type(phy, 300); - if (ret < 0) - return ret; - - phy->modtype = (u8)ret; - if (ret == phy_modtype_none) - edc_needed = phy->priv; /* on unplug retain EDC */ - else if (ret == phy_modtype_twinax || - ret == phy_modtype_twinax_long) - edc_needed = edc_twinax; - else - edc_needed = edc_sr; - - if (edc_needed != phy->priv) { - ret = ael2020_reset(phy, 0); - return ret ? ret : cphy_cause_module_change; - } - cause = cphy_cause_module_change; - } - - ret = t3_phy_lasi_intr_handler(phy); - if (ret < 0) - return ret; - - ret |= cause; - return ret ? ret : cphy_cause_link_change; -} - -static struct cphy_ops ael2020_ops = { - .reset = ael2020_reset, - .intr_enable = ael2020_intr_enable, - .intr_disable = ael2020_intr_disable, - .intr_clear = ael2020_intr_clear, - .intr_handler = ael2020_intr_handler, - .get_link_status = get_link_status_r, - .power_down = ael1002_power_down, - .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, -}; - -int t3_ael2020_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, - const struct mdio_ops *mdio_ops) -{ - int err; - - cphy_init(phy, adapter, phy_addr, &ael2020_ops, mdio_ops, - SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE | - SUPPORTED_IRQ, "10GBASE-R"); - msleep(125); - - err = set_phy_regs(phy, ael2020_reset_regs); - if (err) - return err; - return 0; -} - -/* - * Get link status for a 10GBASE-X device. - */ -static int get_link_status_x(struct cphy *phy, int *link_ok, int *speed, - int *duplex, int *fc) -{ - if (link_ok) { - unsigned int stat0, stat1, stat2; - int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, - MDIO_PMA_RXDET, &stat0); - - if (!err) - err = t3_mdio_read(phy, MDIO_MMD_PCS, - MDIO_PCS_10GBX_STAT1, &stat1); - if (!err) - err = t3_mdio_read(phy, MDIO_MMD_PHYXS, - MDIO_PHYXS_LNSTAT, &stat2); - if (err) - return err; - *link_ok = (stat0 & (stat1 >> 12) & (stat2 >> 12)) & 1; - } - if (speed) - *speed = SPEED_10000; - if (duplex) - *duplex = DUPLEX_FULL; - return 0; -} - -static struct cphy_ops qt2045_ops = { - .reset = ael1006_reset, - .intr_enable = t3_phy_lasi_intr_enable, - .intr_disable = t3_phy_lasi_intr_disable, - .intr_clear = t3_phy_lasi_intr_clear, - .intr_handler = t3_phy_lasi_intr_handler, - .get_link_status = get_link_status_x, - .power_down = ael1002_power_down, - .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, -}; - -int t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, - int phy_addr, const struct mdio_ops *mdio_ops) -{ - unsigned int stat; - - cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops, - SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP, - "10GBASE-CX4"); - - /* - * Some cards where the PHY is supposed to be at address 0 actually - * have it at 1. - */ - if (!phy_addr && - !t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_STAT1, &stat) && - stat == 0xffff) - phy->mdio.prtad = 1; - return 0; -} - -static int xaui_direct_reset(struct cphy *phy, int wait) -{ - return 0; -} - -static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok, - int *speed, int *duplex, int *fc) -{ - if (link_ok) { - unsigned int status; - int prtad = phy->mdio.prtad; - - status = t3_read_reg(phy->adapter, - XGM_REG(A_XGM_SERDES_STAT0, prtad)) | - t3_read_reg(phy->adapter, - XGM_REG(A_XGM_SERDES_STAT1, prtad)) | - t3_read_reg(phy->adapter, - XGM_REG(A_XGM_SERDES_STAT2, prtad)) | - t3_read_reg(phy->adapter, - XGM_REG(A_XGM_SERDES_STAT3, prtad)); - *link_ok = !(status & F_LOWSIG0); - } - if (speed) - *speed = SPEED_10000; - if (duplex) - *duplex = DUPLEX_FULL; - return 0; -} - -static int xaui_direct_power_down(struct cphy *phy, int enable) -{ - return 0; -} - -static struct cphy_ops xaui_direct_ops = { - .reset = xaui_direct_reset, - .intr_enable = ael1002_intr_noop, - .intr_disable = ael1002_intr_noop, - .intr_clear = ael1002_intr_noop, - .intr_handler = ael1002_intr_noop, - .get_link_status = xaui_direct_get_link_status, - .power_down = xaui_direct_power_down, -}; - -int t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter, - int phy_addr, const struct mdio_ops *mdio_ops) -{ - cphy_init(phy, adapter, phy_addr, &xaui_direct_ops, mdio_ops, - SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP, - "10GBASE-CX4"); - return 0; -} diff --git a/drivers/net/cxgb3/aq100x.c b/drivers/net/cxgb3/aq100x.c deleted file mode 100644 index 341b7ef1508f..000000000000 --- a/drivers/net/cxgb3/aq100x.c +++ /dev/null @@ -1,354 +0,0 @@ -/* - * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "common.h" -#include "regs.h" - -enum { - /* MDIO_DEV_PMA_PMD registers */ - AQ_LINK_STAT = 0xe800, - AQ_IMASK_PMA = 0xf000, - - /* MDIO_DEV_XGXS registers */ - AQ_XAUI_RX_CFG = 0xc400, - AQ_XAUI_TX_CFG = 0xe400, - - /* MDIO_DEV_ANEG registers */ - AQ_1G_CTRL = 0xc400, - AQ_ANEG_STAT = 0xc800, - - /* MDIO_DEV_VEND1 registers */ - AQ_FW_VERSION = 0x0020, - AQ_IFLAG_GLOBAL = 0xfc00, - AQ_IMASK_GLOBAL = 0xff00, -}; - -enum { - IMASK_PMA = 1 << 2, - IMASK_GLOBAL = 1 << 15, - ADV_1G_FULL = 1 << 15, - ADV_1G_HALF = 1 << 14, - ADV_10G_FULL = 1 << 12, - AQ_RESET = (1 << 14) | (1 << 15), - AQ_LOWPOWER = 1 << 12, -}; - -static int aq100x_reset(struct cphy *phy, int wait) -{ - /* - * Ignore the caller specified wait time; always wait for the reset to - * complete. Can take up to 3s. - */ - int err = t3_phy_reset(phy, MDIO_MMD_VEND1, 3000); - - if (err) - CH_WARN(phy->adapter, "PHY%d: reset failed (0x%x).\n", - phy->mdio.prtad, err); - - return err; -} - -static int aq100x_intr_enable(struct cphy *phy) -{ - int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AQ_IMASK_PMA, IMASK_PMA); - if (err) - return err; - - err = t3_mdio_write(phy, MDIO_MMD_VEND1, AQ_IMASK_GLOBAL, IMASK_GLOBAL); - return err; -} - -static int aq100x_intr_disable(struct cphy *phy) -{ - return t3_mdio_write(phy, MDIO_MMD_VEND1, AQ_IMASK_GLOBAL, 0); -} - -static int aq100x_intr_clear(struct cphy *phy) -{ - unsigned int v; - - t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_IFLAG_GLOBAL, &v); - t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_STAT1, &v); - - return 0; -} - -static int aq100x_intr_handler(struct cphy *phy) -{ - int err; - unsigned int cause, v; - - err = t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_IFLAG_GLOBAL, &cause); - if (err) - return err; - - /* Read (and reset) the latching version of the status */ - t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_STAT1, &v); - - return cphy_cause_link_change; -} - -static int aq100x_power_down(struct cphy *phy, int off) -{ - return mdio_set_flag(&phy->mdio, phy->mdio.prtad, - MDIO_MMD_PMAPMD, MDIO_CTRL1, - MDIO_CTRL1_LPOWER, off); -} - -static int aq100x_autoneg_enable(struct cphy *phy) -{ - int err; - - err = aq100x_power_down(phy, 0); - if (!err) - err = mdio_set_flag(&phy->mdio, phy->mdio.prtad, - MDIO_MMD_AN, MDIO_CTRL1, - BMCR_ANENABLE | BMCR_ANRESTART, 1); - - return err; -} - -static int aq100x_autoneg_restart(struct cphy *phy) -{ - int err; - - err = aq100x_power_down(phy, 0); - if (!err) - err = mdio_set_flag(&phy->mdio, phy->mdio.prtad, - MDIO_MMD_AN, MDIO_CTRL1, - BMCR_ANENABLE | BMCR_ANRESTART, 1); - - return err; -} - -static int aq100x_advertise(struct cphy *phy, unsigned int advertise_map) -{ - unsigned int adv; - int err; - - /* 10G advertisement */ - adv = 0; - if (advertise_map & ADVERTISED_10000baseT_Full) - adv |= ADV_10G_FULL; - err = t3_mdio_change_bits(phy, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL, - ADV_10G_FULL, adv); - if (err) - return err; - - /* 1G advertisement */ - adv = 0; - if (advertise_map & ADVERTISED_1000baseT_Full) - adv |= ADV_1G_FULL; - if (advertise_map & ADVERTISED_1000baseT_Half) - adv |= ADV_1G_HALF; - err = t3_mdio_change_bits(phy, MDIO_MMD_AN, AQ_1G_CTRL, - ADV_1G_FULL | ADV_1G_HALF, adv); - if (err) - return err; - - /* 100M, pause advertisement */ - adv = 0; - if (advertise_map & ADVERTISED_100baseT_Half) - adv |= ADVERTISE_100HALF; - if (advertise_map & ADVERTISED_100baseT_Full) - adv |= ADVERTISE_100FULL; - if (advertise_map & ADVERTISED_Pause) - adv |= ADVERTISE_PAUSE_CAP; - if (advertise_map & ADVERTISED_Asym_Pause) - adv |= ADVERTISE_PAUSE_ASYM; - err = t3_mdio_change_bits(phy, MDIO_MMD_AN, MDIO_AN_ADVERTISE, - 0xfe0, adv); - - return err; -} - -static int aq100x_set_loopback(struct cphy *phy, int mmd, int dir, int enable) -{ - return mdio_set_flag(&phy->mdio, phy->mdio.prtad, - MDIO_MMD_PMAPMD, MDIO_CTRL1, - BMCR_LOOPBACK, enable); -} - -static int aq100x_set_speed_duplex(struct cphy *phy, int speed, int duplex) -{ - /* no can do */ - return -1; -} - -static int aq100x_get_link_status(struct cphy *phy, int *link_ok, - int *speed, int *duplex, int *fc) -{ - int err; - unsigned int v; - - if (link_ok) { - err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AQ_LINK_STAT, &v); - if (err) - return err; - - *link_ok = v & 1; - if (!*link_ok) - return 0; - } - - err = t3_mdio_read(phy, MDIO_MMD_AN, AQ_ANEG_STAT, &v); - if (err) - return err; - - if (speed) { - switch (v & 0x6) { - case 0x6: - *speed = SPEED_10000; - break; - case 0x4: - *speed = SPEED_1000; - break; - case 0x2: - *speed = SPEED_100; - break; - case 0x0: - *speed = SPEED_10; - break; - } - } - - if (duplex) - *duplex = v & 1 ? DUPLEX_FULL : DUPLEX_HALF; - - return 0; -} - -static struct cphy_ops aq100x_ops = { - .reset = aq100x_reset, - .intr_enable = aq100x_intr_enable, - .intr_disable = aq100x_intr_disable, - .intr_clear = aq100x_intr_clear, - .intr_handler = aq100x_intr_handler, - .autoneg_enable = aq100x_autoneg_enable, - .autoneg_restart = aq100x_autoneg_restart, - .advertise = aq100x_advertise, - .set_loopback = aq100x_set_loopback, - .set_speed_duplex = aq100x_set_speed_duplex, - .get_link_status = aq100x_get_link_status, - .power_down = aq100x_power_down, - .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, -}; - -int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, - const struct mdio_ops *mdio_ops) -{ - unsigned int v, v2, gpio, wait; - int err; - - cphy_init(phy, adapter, phy_addr, &aq100x_ops, mdio_ops, - SUPPORTED_1000baseT_Full | SUPPORTED_10000baseT_Full | - SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_AUI, - "1000/10GBASE-T"); - - /* - * The PHY has been out of reset ever since the system powered up. So - * we do a hard reset over here. - */ - gpio = phy_addr ? F_GPIO10_OUT_VAL : F_GPIO6_OUT_VAL; - t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, 0); - msleep(1); - t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, gpio); - - /* - * Give it enough time to load the firmware and get ready for mdio. - */ - msleep(1000); - wait = 500; /* in 10ms increments */ - do { - err = t3_mdio_read(phy, MDIO_MMD_VEND1, MDIO_CTRL1, &v); - if (err || v == 0xffff) { - - /* Allow prep_adapter to succeed when ffff is read */ - - CH_WARN(adapter, "PHY%d: reset failed (0x%x, 0x%x).\n", - phy_addr, err, v); - goto done; - } - - v &= AQ_RESET; - if (v) - msleep(10); - } while (v && --wait); - if (v) { - CH_WARN(adapter, "PHY%d: reset timed out (0x%x).\n", - phy_addr, v); - - goto done; /* let prep_adapter succeed */ - } - - /* Datasheet says 3s max but this has been observed */ - wait = (500 - wait) * 10 + 1000; - if (wait > 3000) - CH_WARN(adapter, "PHY%d: reset took %ums\n", phy_addr, wait); - - /* Firmware version check. */ - t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_FW_VERSION, &v); - if (v != 101) - CH_WARN(adapter, "PHY%d: unsupported firmware %d\n", - phy_addr, v); - - /* - * The PHY should start in really-low-power mode. Prepare it for normal - * operations. - */ - err = t3_mdio_read(phy, MDIO_MMD_VEND1, MDIO_CTRL1, &v); - if (err) - return err; - if (v & AQ_LOWPOWER) { - err = t3_mdio_change_bits(phy, MDIO_MMD_VEND1, MDIO_CTRL1, - AQ_LOWPOWER, 0); - if (err) - return err; - msleep(10); - } else - CH_WARN(adapter, "PHY%d does not start in low power mode.\n", - phy_addr); - - /* - * Verify XAUI settings, but let prep succeed no matter what. - */ - v = v2 = 0; - t3_mdio_read(phy, MDIO_MMD_PHYXS, AQ_XAUI_RX_CFG, &v); - t3_mdio_read(phy, MDIO_MMD_PHYXS, AQ_XAUI_TX_CFG, &v2); - if (v != 0x1b || v2 != 0x1b) - CH_WARN(adapter, - "PHY%d: incorrect XAUI settings (0x%x, 0x%x).\n", - phy_addr, v, v2); - -done: - return err; -} diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h deleted file mode 100644 index df01b6343241..000000000000 --- a/drivers/net/cxgb3/common.h +++ /dev/null @@ -1,775 +0,0 @@ -/* - * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef __CHELSIO_COMMON_H -#define __CHELSIO_COMMON_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include "version.h" - -#define CH_ERR(adap, fmt, ...) dev_err(&adap->pdev->dev, fmt, ## __VA_ARGS__) -#define CH_WARN(adap, fmt, ...) dev_warn(&adap->pdev->dev, fmt, ## __VA_ARGS__) -#define CH_ALERT(adap, fmt, ...) \ - dev_printk(KERN_ALERT, &adap->pdev->dev, fmt, ## __VA_ARGS__) - -/* - * More powerful macro that selectively prints messages based on msg_enable. - * For info and debugging messages. - */ -#define CH_MSG(adapter, level, category, fmt, ...) do { \ - if ((adapter)->msg_enable & NETIF_MSG_##category) \ - dev_printk(KERN_##level, &adapter->pdev->dev, fmt, \ - ## __VA_ARGS__); \ -} while (0) - -#ifdef DEBUG -# define CH_DBG(adapter, category, fmt, ...) \ - CH_MSG(adapter, DEBUG, category, fmt, ## __VA_ARGS__) -#else -# define CH_DBG(adapter, category, fmt, ...) -#endif - -/* Additional NETIF_MSG_* categories */ -#define NETIF_MSG_MMIO 0x8000000 - -enum { - MAX_NPORTS = 2, /* max # of ports */ - MAX_FRAME_SIZE = 10240, /* max MAC frame size, including header + FCS */ - EEPROMSIZE = 8192, /* Serial EEPROM size */ - SERNUM_LEN = 16, /* Serial # length */ - 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 */ - PROTO_SRAM_LINES = 128, /* size of TP sram */ -}; - -#define MAX_RX_COALESCING_LEN 12288U - -enum { - PAUSE_RX = 1 << 0, - PAUSE_TX = 1 << 1, - PAUSE_AUTONEG = 1 << 2 -}; - -enum { - SUPPORTED_IRQ = 1 << 24 -}; - -enum { /* adapter interrupt-maintained statistics */ - STAT_ULP_CH0_PBL_OOB, - STAT_ULP_CH1_PBL_OOB, - STAT_PCI_CORR_ECC, - - IRQ_NUM_STATS /* keep last */ -}; - -#define TP_VERSION_MAJOR 1 -#define TP_VERSION_MINOR 1 -#define TP_VERSION_MICRO 0 - -#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 { - SGE_QSETS = 8, /* # of SGE Tx/Rx/RspQ sets */ - SGE_RXQ_PER_SET = 2, /* # of Rx queues per set */ - SGE_TXQ_PER_SET = 3 /* # of Tx queues per set */ -}; - -enum sge_context_type { /* SGE egress context types */ - SGE_CNTXT_RDMA = 0, - SGE_CNTXT_ETH = 2, - SGE_CNTXT_OFLD = 4, - SGE_CNTXT_CTRL = 5 -}; - -enum { - AN_PKT_SIZE = 32, /* async notification packet size */ - IMMED_PKT_SIZE = 48 /* packet size for immediate data */ -}; - -struct sg_ent { /* SGE scatter/gather entry */ - __be32 len[2]; - __be64 addr[2]; -}; - -#ifndef SGE_NUM_GENBITS -/* Must be 1 or 2 */ -# define SGE_NUM_GENBITS 2 -#endif - -#define TX_DESC_FLITS 16U -#define WR_FLITS (TX_DESC_FLITS + 1 - SGE_NUM_GENBITS) - -struct cphy; -struct adapter; - -struct mdio_ops { - int (*read)(struct net_device *dev, int phy_addr, int mmd_addr, - u16 reg_addr); - int (*write)(struct net_device *dev, int phy_addr, int mmd_addr, - u16 reg_addr, u16 val); - unsigned mode_support; -}; - -struct adapter_info { - 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 int gpio_out; /* GPIO output settings */ - unsigned char gpio_intr[MAX_NPORTS]; /* GPIO PHY IRQ pins */ - unsigned long caps; /* adapter capabilities */ - const struct mdio_ops *mdio_ops; /* MDIO operations */ - const char *desc; /* product description */ -}; - -struct mc5_stats { - unsigned long parity_err; - unsigned long active_rgn_full; - unsigned long nfa_srch_err; - unsigned long unknown_cmd; - unsigned long reqq_parity_err; - unsigned long dispq_parity_err; - unsigned long del_act_empty; -}; - -struct mc7_stats { - unsigned long corr_err; - unsigned long uncorr_err; - unsigned long parity_err; - unsigned long addr_err; -}; - -struct mac_stats { - u64 tx_octets; /* total # of octets in good frames */ - u64 tx_octets_bad; /* total # of octets in error frames */ - u64 tx_frames; /* all good frames */ - u64 tx_mcast_frames; /* good multicast frames */ - u64 tx_bcast_frames; /* good broadcast frames */ - u64 tx_pause; /* # of transmitted pause frames */ - u64 tx_deferred; /* frames with deferred transmissions */ - u64 tx_late_collisions; /* # of late collisions */ - u64 tx_total_collisions; /* # of total collisions */ - u64 tx_excess_collisions; /* frame errors from excessive collissions */ - u64 tx_underrun; /* # of Tx FIFO underruns */ - u64 tx_len_errs; /* # of Tx length errors */ - u64 tx_mac_internal_errs; /* # of internal MAC errors on Tx */ - u64 tx_excess_deferral; /* # of frames with excessive deferral */ - u64 tx_fcs_errs; /* # of frames with bad FCS */ - - u64 tx_frames_64; /* # of Tx frames in a particular range */ - u64 tx_frames_65_127; - u64 tx_frames_128_255; - u64 tx_frames_256_511; - u64 tx_frames_512_1023; - u64 tx_frames_1024_1518; - u64 tx_frames_1519_max; - - u64 rx_octets; /* total # of octets in good frames */ - u64 rx_octets_bad; /* total # of octets in error frames */ - u64 rx_frames; /* all good frames */ - u64 rx_mcast_frames; /* good multicast frames */ - u64 rx_bcast_frames; /* good broadcast frames */ - u64 rx_pause; /* # of received pause frames */ - u64 rx_fcs_errs; /* # of received frames with bad FCS */ - u64 rx_align_errs; /* alignment errors */ - u64 rx_symbol_errs; /* symbol errors */ - u64 rx_data_errs; /* data errors */ - u64 rx_sequence_errs; /* sequence errors */ - u64 rx_runt; /* # of runt frames */ - u64 rx_jabber; /* # of jabber frames */ - u64 rx_short; /* # of short frames */ - u64 rx_too_long; /* # of oversized frames */ - u64 rx_mac_internal_errs; /* # of internal MAC errors on Rx */ - - u64 rx_frames_64; /* # of Rx frames in a particular range */ - u64 rx_frames_65_127; - u64 rx_frames_128_255; - u64 rx_frames_256_511; - u64 rx_frames_512_1023; - u64 rx_frames_1024_1518; - u64 rx_frames_1519_max; - - u64 rx_cong_drops; /* # of Rx drops due to SGE congestion */ - - unsigned long tx_fifo_parity_err; - unsigned long rx_fifo_parity_err; - unsigned long tx_fifo_urun; - unsigned long rx_fifo_ovfl; - unsigned long serdes_signal_loss; - unsigned long xaui_pcs_ctc_err; - unsigned long xaui_pcs_align_change; - - unsigned long num_toggled; /* # times toggled TxEn due to stuck TX */ - unsigned long num_resets; /* # times reset due to stuck TX */ - - unsigned long link_faults; /* # detected link faults */ -}; - -struct tp_mib_stats { - u32 ipInReceive_hi; - u32 ipInReceive_lo; - u32 ipInHdrErrors_hi; - u32 ipInHdrErrors_lo; - u32 ipInAddrErrors_hi; - u32 ipInAddrErrors_lo; - u32 ipInUnknownProtos_hi; - u32 ipInUnknownProtos_lo; - u32 ipInDiscards_hi; - u32 ipInDiscards_lo; - u32 ipInDelivers_hi; - u32 ipInDelivers_lo; - u32 ipOutRequests_hi; - u32 ipOutRequests_lo; - u32 ipOutDiscards_hi; - u32 ipOutDiscards_lo; - u32 ipOutNoRoutes_hi; - u32 ipOutNoRoutes_lo; - u32 ipReasmTimeout; - u32 ipReasmReqds; - u32 ipReasmOKs; - u32 ipReasmFails; - - u32 reserved[8]; - - u32 tcpActiveOpens; - u32 tcpPassiveOpens; - u32 tcpAttemptFails; - u32 tcpEstabResets; - u32 tcpOutRsts; - u32 tcpCurrEstab; - u32 tcpInSegs_hi; - u32 tcpInSegs_lo; - u32 tcpOutSegs_hi; - u32 tcpOutSegs_lo; - u32 tcpRetransSeg_hi; - u32 tcpRetransSeg_lo; - u32 tcpInErrs_hi; - u32 tcpInErrs_lo; - u32 tcpRtoMin; - u32 tcpRtoMax; -}; - -struct tp_params { - unsigned int nchan; /* # of channels */ - unsigned int pmrx_size; /* total PMRX capacity */ - unsigned int pmtx_size; /* total PMTX capacity */ - unsigned int cm_size; /* total CM capacity */ - unsigned int chan_rx_size; /* per channel Rx size */ - unsigned int chan_tx_size; /* per channel Tx size */ - unsigned int rx_pg_size; /* Rx page size */ - unsigned int tx_pg_size; /* Tx page size */ - unsigned int rx_num_pgs; /* # of Rx pages */ - unsigned int tx_num_pgs; /* # of Tx pages */ - unsigned int ntimer_qs; /* # of timer queues */ -}; - -struct qset_params { /* SGE queue set parameters */ - unsigned int polling; /* polling/interrupt service for rspq */ - unsigned int coalesce_usecs; /* irq coalescing timer */ - unsigned int rspq_size; /* # of entries in response queue */ - unsigned int fl_size; /* # of entries in regular free list */ - unsigned int jumbo_size; /* # of entries in jumbo free list */ - unsigned int txq_size[SGE_TXQ_PER_SET]; /* Tx queue sizes */ - unsigned int cong_thres; /* FL congestion threshold */ - unsigned int vector; /* Interrupt (line or vector) number */ -}; - -struct sge_params { - unsigned int max_pkt_size; /* max offload pkt size */ - struct qset_params qset[SGE_QSETS]; -}; - -struct mc5_params { - unsigned int mode; /* selects MC5 width */ - unsigned int nservers; /* size of server region */ - unsigned int nfilters; /* size of filter region */ - unsigned int nroutes; /* size of routing region */ -}; - -/* Default MC5 region sizes */ -enum { - DEFAULT_NSERVERS = 512, - DEFAULT_NFILTERS = 128 -}; - -/* MC5 modes, these must be non-0 */ -enum { - MC5_MODE_144_BIT = 1, - MC5_MODE_72_BIT = 2 -}; - -/* MC5 min active region size */ -enum { MC5_MIN_TIDS = 16 }; - -struct vpd_params { - unsigned int cclk; - unsigned int mclk; - unsigned int uclk; - unsigned int mdc; - unsigned int mem_timing; - u8 sn[SERNUM_LEN + 1]; - u8 eth_base[6]; - u8 port_type[MAX_NPORTS]; - unsigned short xauicfg[2]; -}; - -struct pci_params { - unsigned int vpd_cap_addr; - unsigned short speed; - unsigned char width; - unsigned char variant; -}; - -enum { - PCI_VARIANT_PCI, - PCI_VARIANT_PCIX_MODE1_PARITY, - PCI_VARIANT_PCIX_MODE1_ECC, - PCI_VARIANT_PCIX_266_MODE2, - PCI_VARIANT_PCIE -}; - -struct adapter_params { - struct sge_params sge; - struct mc5_params mc5; - struct tp_params tp; - struct vpd_params vpd; - struct pci_params pci; - - const struct adapter_info *info; - - unsigned short mtus[NMTUS]; - unsigned short a_wnd[NCCTRL_WIN]; - unsigned short b_wnd[NCCTRL_WIN]; - - 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 */ - unsigned int offload; -}; - -enum { /* chip revisions */ - T3_REV_A = 0, - T3_REV_B = 2, - T3_REV_B2 = 3, - T3_REV_C = 4, -}; - -struct trace_params { - u32 sip; - u32 sip_mask; - u32 dip; - u32 dip_mask; - u16 sport; - u16 sport_mask; - u16 dport; - u16 dport_mask; - u32 vlan:12; - u32 vlan_mask:12; - u32 intf:4; - u32 intf_mask:4; - u8 proto; - u8 proto_mask; -}; - -struct link_config { - unsigned int supported; /* link capabilities */ - unsigned int advertising; /* advertised capabilities */ - unsigned short requested_speed; /* speed user has requested */ - unsigned short speed; /* actual link speed */ - unsigned char requested_duplex; /* duplex user has requested */ - unsigned char duplex; /* actual link duplex */ - unsigned char requested_fc; /* flow control user has requested */ - unsigned char fc; /* actual link flow control */ - unsigned char autoneg; /* autonegotiating? */ - unsigned int link_ok; /* link up? */ -}; - -#define SPEED_INVALID 0xffff -#define DUPLEX_INVALID 0xff - -struct mc5 { - struct adapter *adapter; - unsigned int tcam_size; - unsigned char part_type; - unsigned char parity_enabled; - unsigned char mode; - struct mc5_stats stats; -}; - -static inline unsigned int t3_mc5_size(const struct mc5 *p) -{ - return p->tcam_size; -} - -struct mc7 { - struct adapter *adapter; /* backpointer to adapter */ - unsigned int size; /* memory size in bytes */ - unsigned int width; /* MC7 interface width */ - unsigned int offset; /* register address offset for MC7 instance */ - const char *name; /* name of MC7 instance */ - struct mc7_stats stats; /* MC7 statistics */ -}; - -static inline unsigned int t3_mc7_size(const struct mc7 *p) -{ - return p->size; -} - -struct cmac { - struct adapter *adapter; - unsigned int offset; - unsigned int nucast; /* # of address filters for unicast MACs */ - unsigned int tx_tcnt; - 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; - u64 rx_pause; - struct mac_stats stats; -}; - -enum { - MAC_DIRECTION_RX = 1, - MAC_DIRECTION_TX = 2, - MAC_RXFIFO_SIZE = 32768 -}; - -/* PHY loopback direction */ -enum { - PHY_LOOPBACK_TX = 1, - PHY_LOOPBACK_RX = 2 -}; - -/* PHY interrupt types */ -enum { - cphy_cause_link_change = 1, - cphy_cause_fifo_error = 2, - cphy_cause_module_change = 4, -}; - -/* PHY module types */ -enum { - phy_modtype_none, - phy_modtype_sr, - phy_modtype_lr, - phy_modtype_lrm, - phy_modtype_twinax, - phy_modtype_twinax_long, - phy_modtype_unknown -}; - -/* PHY operations */ -struct cphy_ops { - int (*reset)(struct cphy *phy, int wait); - - int (*intr_enable)(struct cphy *phy); - int (*intr_disable)(struct cphy *phy); - int (*intr_clear)(struct cphy *phy); - int (*intr_handler)(struct cphy *phy); - - int (*autoneg_enable)(struct cphy *phy); - int (*autoneg_restart)(struct cphy *phy); - - int (*advertise)(struct cphy *phy, unsigned int advertise_map); - int (*set_loopback)(struct cphy *phy, int mmd, int dir, int enable); - int (*set_speed_duplex)(struct cphy *phy, int speed, int duplex); - int (*get_link_status)(struct cphy *phy, int *link_ok, int *speed, - int *duplex, int *fc); - int (*power_down)(struct cphy *phy, int enable); - - u32 mmds; -}; -enum { - EDC_OPT_AEL2005 = 0, - EDC_OPT_AEL2005_SIZE = 1084, - EDC_TWX_AEL2005 = 1, - EDC_TWX_AEL2005_SIZE = 1464, - EDC_TWX_AEL2020 = 2, - EDC_TWX_AEL2020_SIZE = 1628, - EDC_MAX_SIZE = EDC_TWX_AEL2020_SIZE, /* Max cache size */ -}; - -/* A PHY instance */ -struct cphy { - u8 modtype; /* PHY module type */ - short priv; /* scratch pad */ - unsigned int caps; /* PHY capabilities */ - struct adapter *adapter; /* associated adapter */ - const char *desc; /* PHY description */ - unsigned long fifo_errors; /* FIFO over/under-flows */ - const struct cphy_ops *ops; /* PHY operations */ - struct mdio_if_info mdio; - u16 phy_cache[EDC_MAX_SIZE]; /* EDC cache */ -}; - -/* Convenience MDIO read/write wrappers */ -static inline int t3_mdio_read(struct cphy *phy, int mmd, int reg, - unsigned int *valp) -{ - int rc = phy->mdio.mdio_read(phy->mdio.dev, phy->mdio.prtad, mmd, reg); - *valp = (rc >= 0) ? rc : -1; - return (rc >= 0) ? 0 : rc; -} - -static inline int t3_mdio_write(struct cphy *phy, int mmd, int reg, - unsigned int val) -{ - return phy->mdio.mdio_write(phy->mdio.dev, phy->mdio.prtad, mmd, - reg, val); -} - -/* Convenience initializer */ -static inline void cphy_init(struct cphy *phy, struct adapter *adapter, - int phy_addr, struct cphy_ops *phy_ops, - const struct mdio_ops *mdio_ops, - unsigned int caps, const char *desc) -{ - phy->caps = caps; - phy->adapter = adapter; - phy->desc = desc; - phy->ops = phy_ops; - if (mdio_ops) { - phy->mdio.prtad = phy_addr; - phy->mdio.mmds = phy_ops->mmds; - phy->mdio.mode_support = mdio_ops->mode_support; - phy->mdio.mdio_read = mdio_ops->read; - phy->mdio.mdio_write = mdio_ops->write; - } -} - -/* Accumulate MAC statistics every 180 seconds. For 1G we multiply by 10. */ -#define MAC_STATS_ACCUM_SECS 180 - -#define XGM_REG(reg_addr, idx) \ - ((reg_addr) + (idx) * (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR)) - -struct addr_val_pair { - unsigned int reg_addr; - unsigned int val; -}; - -#include "adapter.h" - -#ifndef PCI_VENDOR_ID_CHELSIO -# define PCI_VENDOR_ID_CHELSIO 0x1425 -#endif - -#define for_each_port(adapter, iter) \ - for (iter = 0; iter < (adapter)->params.nports; ++iter) - -#define adapter_info(adap) ((adap)->params.info) - -static inline int uses_xaui(const struct adapter *adap) -{ - return adapter_info(adap)->caps & SUPPORTED_AUI; -} - -static inline int is_10G(const struct adapter *adap) -{ - return adapter_info(adap)->caps & SUPPORTED_10000baseT_Full; -} - -static inline int is_offload(const struct adapter *adap) -{ - return adap->params.offload; -} - -static inline unsigned int core_ticks_per_usec(const struct adapter *adap) -{ - return adap->params.vpd.cclk / 1000; -} - -static inline unsigned int is_pcie(const struct adapter *adap) -{ - return adap->params.pci.variant == PCI_VARIANT_PCIE; -} - -void t3_set_reg_field(struct adapter *adap, unsigned int addr, u32 mask, - u32 val); -void t3_write_regs(struct adapter *adapter, const struct addr_val_pair *p, - int n, unsigned int offset); -int t3_wait_op_done_val(struct adapter *adapter, int reg, u32 mask, - int polarity, int attempts, int delay, u32 *valp); -static inline int t3_wait_op_done(struct adapter *adapter, int reg, u32 mask, - int polarity, int attempts, int delay) -{ - return t3_wait_op_done_val(adapter, reg, mask, polarity, attempts, - delay, NULL); -} -int t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear, - unsigned int set); -int t3_phy_reset(struct cphy *phy, int mmd, int wait); -int t3_phy_advertise(struct cphy *phy, unsigned int advert); -int t3_phy_advertise_fiber(struct cphy *phy, unsigned int advert); -int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex); -int t3_phy_lasi_intr_enable(struct cphy *phy); -int t3_phy_lasi_intr_disable(struct cphy *phy); -int t3_phy_lasi_intr_clear(struct cphy *phy); -int t3_phy_lasi_intr_handler(struct cphy *phy); - -void t3_intr_enable(struct adapter *adapter); -void t3_intr_disable(struct adapter *adapter); -void t3_intr_clear(struct adapter *adapter); -void t3_xgm_intr_enable(struct adapter *adapter, int idx); -void t3_xgm_intr_disable(struct adapter *adapter, int idx); -void t3_port_intr_enable(struct adapter *adapter, int idx); -void t3_port_intr_disable(struct adapter *adapter, int idx); -int t3_slow_intr_handler(struct adapter *adapter); -int t3_phy_intr_handler(struct adapter *adapter); - -void t3_link_changed(struct adapter *adapter, int port_id); -void t3_link_fault(struct adapter *adapter, int port_id); -int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc); -const struct adapter_info *t3_get_adapter_info(unsigned int board_id); -int t3_seeprom_read(struct adapter *adapter, u32 addr, __le32 *data); -int t3_seeprom_write(struct adapter *adapter, u32 addr, __le32 data); -int t3_seeprom_wp(struct adapter *adapter, int enable); -int t3_get_tp_version(struct adapter *adapter, u32 *vers); -int t3_check_tpsram_version(struct adapter *adapter); -int t3_check_tpsram(struct adapter *adapter, const u8 *tp_ram, - unsigned int size); -int t3_set_proto_sram(struct adapter *adap, const u8 *data); -int t3_load_fw(struct adapter *adapter, const u8 * fw_data, unsigned int size); -int t3_get_fw_version(struct adapter *adapter, u32 *vers); -int t3_check_fw_version(struct adapter *adapter); -int t3_init_hw(struct adapter *adapter, u32 fw_params); -int t3_reset_adapter(struct adapter *adapter); -int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai, - int reset); -int t3_replay_prep_adapter(struct adapter *adapter); -void t3_led_ready(struct adapter *adapter); -void t3_fatal_err(struct adapter *adapter); -void t3_set_vlan_accel(struct adapter *adapter, unsigned int ports, int on); -void t3_config_rss(struct adapter *adapter, unsigned int rss_config, - const u8 * cpus, const u16 *rspq); -int t3_cim_ctl_blk_read(struct adapter *adap, unsigned int addr, - unsigned int n, unsigned int *valp); -int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n, - u64 *buf); - -int t3_mac_reset(struct cmac *mac); -void t3b_pcs_reset(struct cmac *mac); -void t3_mac_disable_exact_filters(struct cmac *mac); -void t3_mac_enable_exact_filters(struct cmac *mac); -int t3_mac_enable(struct cmac *mac, int which); -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 net_device *dev); -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); -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); -int t3b2_mac_watchdog_task(struct cmac *mac); - -void t3_mc5_prep(struct adapter *adapter, struct mc5 *mc5, int mode); -int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters, - unsigned int nroutes); -void t3_mc5_intr_handler(struct mc5 *mc5); - -void t3_tp_set_offload_mode(struct adapter *adap, int enable); -void t3_tp_get_mib_stats(struct adapter *adap, struct tp_mib_stats *tps); -void t3_load_mtus(struct adapter *adap, unsigned short mtus[NMTUS], - unsigned short alpha[NCCTRL_WIN], - unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap); -void t3_config_trace_filter(struct adapter *adapter, - const struct trace_params *tp, int filter_index, - int invert, int enable); -int t3_config_sched(struct adapter *adap, unsigned int kbps, int sched); - -void t3_sge_prep(struct adapter *adap, struct sge_params *p); -void t3_sge_init(struct adapter *adap, struct sge_params *p); -int t3_sge_init_ecntxt(struct adapter *adapter, unsigned int id, int gts_enable, - enum sge_context_type type, int respq, u64 base_addr, - unsigned int size, unsigned int token, int gen, - unsigned int cidx); -int t3_sge_init_flcntxt(struct adapter *adapter, unsigned int id, - int gts_enable, u64 base_addr, unsigned int size, - unsigned int esize, unsigned int cong_thres, int gen, - unsigned int cidx); -int t3_sge_init_rspcntxt(struct adapter *adapter, unsigned int id, - int irq_vec_idx, u64 base_addr, unsigned int size, - unsigned int fl_thres, int gen, unsigned int cidx); -int t3_sge_init_cqcntxt(struct adapter *adapter, unsigned int id, u64 base_addr, - unsigned int size, int rspq, int ovfl_mode, - unsigned int credits, unsigned int credit_thres); -int t3_sge_enable_ecntxt(struct adapter *adapter, unsigned int id, int enable); -int t3_sge_disable_fl(struct adapter *adapter, unsigned int id); -int t3_sge_disable_rspcntxt(struct adapter *adapter, unsigned int id); -int t3_sge_disable_cqcntxt(struct adapter *adapter, unsigned int id); -int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op, - unsigned int credits); - -int t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter, - int phy_addr, const struct mdio_ops *mdio_ops); -int t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter, - int phy_addr, const struct mdio_ops *mdio_ops); -int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter, - int phy_addr, const struct mdio_ops *mdio_ops); -int t3_ael2005_phy_prep(struct cphy *phy, struct adapter *adapter, - int phy_addr, const struct mdio_ops *mdio_ops); -int t3_ael2020_phy_prep(struct cphy *phy, struct adapter *adapter, - int phy_addr, const struct mdio_ops *mdio_ops); -int t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, - const struct mdio_ops *mdio_ops); -int t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter, - int phy_addr, const struct mdio_ops *mdio_ops); -int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter, - int phy_addr, const struct mdio_ops *mdio_ops); -#endif /* __CHELSIO_COMMON_H */ diff --git a/drivers/net/cxgb3/cxgb3_ctl_defs.h b/drivers/net/cxgb3/cxgb3_ctl_defs.h deleted file mode 100644 index 369fe711fd7f..000000000000 --- a/drivers/net/cxgb3/cxgb3_ctl_defs.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _CXGB3_OFFLOAD_CTL_DEFS_H -#define _CXGB3_OFFLOAD_CTL_DEFS_H - -enum { - GET_MAX_OUTSTANDING_WR = 0, - GET_TX_MAX_CHUNK = 1, - GET_TID_RANGE = 2, - GET_STID_RANGE = 3, - GET_RTBL_RANGE = 4, - GET_L2T_CAPACITY = 5, - GET_MTUS = 6, - GET_WR_LEN = 7, - GET_IFF_FROM_MAC = 8, - GET_DDP_PARAMS = 9, - GET_PORTS = 10, - - ULP_ISCSI_GET_PARAMS = 11, - ULP_ISCSI_SET_PARAMS = 12, - - RDMA_GET_PARAMS = 13, - RDMA_CQ_OP = 14, - RDMA_CQ_SETUP = 15, - RDMA_CQ_DISABLE = 16, - RDMA_CTRL_QP_SETUP = 17, - RDMA_GET_MEM = 18, - RDMA_GET_MIB = 19, - - GET_RX_PAGE_INFO = 50, - GET_ISCSI_IPV4ADDR = 51, - - GET_EMBEDDED_INFO = 70, -}; - -/* - * Structure used to describe a TID range. Valid TIDs are [base, base+num). - */ -struct tid_range { - unsigned int base; /* first TID */ - unsigned int num; /* number of TIDs in range */ -}; - -/* - * Structure used to request the size and contents of the MTU table. - */ -struct mtutab { - unsigned int size; /* # of entries in the MTU table */ - const unsigned short *mtus; /* the MTU table values */ -}; - -struct net_device; - -/* - * Structure used to request the adapter net_device owning a given MAC address. - */ -struct iff_mac { - struct net_device *dev; /* the net_device */ - const unsigned char *mac_addr; /* MAC address to lookup */ - u16 vlan_tag; -}; - -/* Structure used to request a port's iSCSI IPv4 address */ -struct iscsi_ipv4addr { - struct net_device *dev; /* the net_device */ - __be32 ipv4addr; /* the return iSCSI IPv4 address */ -}; - -struct pci_dev; - -/* - * Structure used to request the TCP DDP parameters. - */ -struct ddp_params { - unsigned int llimit; /* TDDP region start address */ - unsigned int ulimit; /* TDDP region end address */ - unsigned int tag_mask; /* TDDP tag mask */ - struct pci_dev *pdev; -}; - -struct adap_ports { - unsigned int nports; /* number of ports on this adapter */ - struct net_device *lldevs[2]; -}; - -/* - * Structure used to return information to the iscsi layer. - */ -struct ulp_iscsi_info { - unsigned int offset; - unsigned int llimit; - unsigned int ulimit; - unsigned int tagmask; - u8 pgsz_factor[4]; - unsigned int max_rxsz; - unsigned int max_txsz; - struct pci_dev *pdev; -}; - -/* - * Structure used to return information to the RDMA layer. - */ -struct rdma_info { - unsigned int tpt_base; /* TPT base address */ - unsigned int tpt_top; /* TPT last entry address */ - unsigned int pbl_base; /* PBL base address */ - unsigned int pbl_top; /* PBL last entry address */ - unsigned int rqt_base; /* RQT base address */ - unsigned int rqt_top; /* RQT last entry address */ - unsigned int udbell_len; /* user doorbell region length */ - unsigned long udbell_physbase; /* user doorbell physical start addr */ - void __iomem *kdb_addr; /* kernel doorbell register address */ - struct pci_dev *pdev; /* associated PCI device */ -}; - -/* - * Structure used to request an operation on an RDMA completion queue. - */ -struct rdma_cq_op { - unsigned int id; - unsigned int op; - unsigned int credits; -}; - -/* - * Structure used to setup RDMA completion queues. - */ -struct rdma_cq_setup { - unsigned int id; - unsigned long long base_addr; - unsigned int size; - unsigned int credits; - unsigned int credit_thres; - unsigned int ovfl_mode; -}; - -/* - * Structure used to setup the RDMA control egress context. - */ -struct rdma_ctrlqp_setup { - unsigned long long base_addr; - unsigned int size; -}; - -/* - * 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 get firmware and protocol engine versions. - */ -struct ch_embedded_info { - u32 fw_vers; - u32 tp_vers; -}; -#endif /* _CXGB3_OFFLOAD_CTL_DEFS_H */ diff --git a/drivers/net/cxgb3/cxgb3_defs.h b/drivers/net/cxgb3/cxgb3_defs.h deleted file mode 100644 index 920d918ed193..000000000000 --- a/drivers/net/cxgb3/cxgb3_defs.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2006-2008 Chelsio, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _CHELSIO_DEFS_H -#define _CHELSIO_DEFS_H - -#include -#include - -#include "t3cdev.h" - -#include "cxgb3_offload.h" - -#define VALIDATE_TID 1 - -void *cxgb_alloc_mem(unsigned long size); -void cxgb_free_mem(void *addr); - -/* - * Map an ATID or STID to their entries in the corresponding TID tables. - */ -static inline union active_open_entry *atid2entry(const struct tid_info *t, - unsigned int atid) -{ - return &t->atid_tab[atid - t->atid_base]; -} - -static inline union listen_entry *stid2entry(const struct tid_info *t, - unsigned int stid) -{ - return &t->stid_tab[stid - t->stid_base]; -} - -/* - * Find the connection corresponding to a TID. - */ -static inline struct t3c_tid_entry *lookup_tid(const struct tid_info *t, - unsigned int tid) -{ - struct t3c_tid_entry *t3c_tid = tid < t->ntids ? - &(t->tid_tab[tid]) : NULL; - - return (t3c_tid && t3c_tid->client) ? t3c_tid : NULL; -} - -/* - * Find the connection corresponding to a server TID. - */ -static inline struct t3c_tid_entry *lookup_stid(const struct tid_info *t, - unsigned int tid) -{ - union listen_entry *e; - - if (tid < t->stid_base || tid >= t->stid_base + t->nstids) - return NULL; - - e = stid2entry(t, tid); - if ((void *)e->next >= (void *)t->tid_tab && - (void *)e->next < (void *)&t->atid_tab[t->natids]) - return NULL; - - return &e->t3c_tid; -} - -/* - * Find the connection corresponding to an active-open TID. - */ -static inline struct t3c_tid_entry *lookup_atid(const struct tid_info *t, - unsigned int tid) -{ - union active_open_entry *e; - - if (tid < t->atid_base || tid >= t->atid_base + t->natids) - return NULL; - - e = atid2entry(t, tid); - if ((void *)e->next >= (void *)t->tid_tab && - (void *)e->next < (void *)&t->atid_tab[t->natids]) - return NULL; - - return &e->t3c_tid; -} - -int attach_t3cdev(struct t3cdev *dev); -void detach_t3cdev(struct t3cdev *dev); -#endif diff --git a/drivers/net/cxgb3/cxgb3_ioctl.h b/drivers/net/cxgb3/cxgb3_ioctl.h deleted file mode 100644 index b19e4376ba76..000000000000 --- a/drivers/net/cxgb3/cxgb3_ioctl.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef __CHIOCTL_H__ -#define __CHIOCTL_H__ - -/* - * Ioctl commands specific to this driver. - */ -enum { - CHELSIO_GETMTUTAB = 1029, - CHELSIO_SETMTUTAB = 1030, - CHELSIO_SET_PM = 1032, - CHELSIO_GET_PM = 1033, - CHELSIO_GET_MEM = 1038, - CHELSIO_LOAD_FW = 1041, - CHELSIO_SET_TRACE_FILTER = 1044, - CHELSIO_SET_QSET_PARAMS = 1045, - CHELSIO_GET_QSET_PARAMS = 1046, - CHELSIO_SET_QSET_NUM = 1047, - CHELSIO_GET_QSET_NUM = 1048, -}; - -struct ch_reg { - uint32_t cmd; - uint32_t addr; - uint32_t val; -}; - -struct ch_cntxt { - uint32_t cmd; - uint32_t cntxt_type; - uint32_t cntxt_id; - uint32_t data[4]; -}; - -/* context types */ -enum { CNTXT_TYPE_EGRESS, CNTXT_TYPE_FL, CNTXT_TYPE_RSP, CNTXT_TYPE_CQ }; - -struct ch_desc { - uint32_t cmd; - uint32_t queue_num; - uint32_t idx; - uint32_t size; - uint8_t data[128]; -}; - -struct ch_mem_range { - uint32_t cmd; - uint32_t mem_id; - uint32_t addr; - uint32_t len; - uint32_t version; - uint8_t buf[0]; -}; - -struct ch_qset_params { - uint32_t cmd; - uint32_t qset_idx; - int32_t txq_size[3]; - int32_t rspq_size; - int32_t fl_size[2]; - int32_t intr_lat; - int32_t polling; - int32_t lro; - int32_t cong_thres; - int32_t vector; - int32_t qnum; -}; - -struct ch_pktsched_params { - uint32_t cmd; - uint8_t sched; - uint8_t idx; - uint8_t min; - uint8_t max; - uint8_t binding; -}; - -#ifndef TCB_SIZE -# define TCB_SIZE 128 -#endif - -/* TCB size in 32-bit words */ -#define TCB_WORDS (TCB_SIZE / 4) - -enum { MEM_CM, MEM_PMRX, MEM_PMTX }; /* ch_mem_range.mem_id values */ - -struct ch_mtus { - uint32_t cmd; - uint32_t nmtus; - uint16_t mtus[NMTUS]; -}; - -struct ch_pm { - uint32_t cmd; - uint32_t tx_pg_sz; - uint32_t tx_num_pg; - uint32_t rx_pg_sz; - uint32_t rx_num_pg; - uint32_t pm_total; -}; - -struct ch_tcam { - uint32_t cmd; - uint32_t tcam_size; - uint32_t nservers; - uint32_t nroutes; - uint32_t nfilters; -}; - -struct ch_tcb { - uint32_t cmd; - uint32_t tcb_index; - uint32_t tcb_data[TCB_WORDS]; -}; - -struct ch_tcam_word { - uint32_t cmd; - uint32_t addr; - uint32_t buf[3]; -}; - -struct ch_trace { - uint32_t cmd; - uint32_t sip; - uint32_t sip_mask; - uint32_t dip; - uint32_t dip_mask; - uint16_t sport; - uint16_t sport_mask; - uint16_t dport; - uint16_t dport_mask; - uint32_t vlan:12; - uint32_t vlan_mask:12; - uint32_t intf:4; - uint32_t intf_mask:4; - uint8_t proto; - uint8_t proto_mask; - uint8_t invert_match:1; - uint8_t config_tx:1; - uint8_t config_rx:1; - uint8_t trace_tx:1; - uint8_t trace_rx:1; -}; - -#define SIOCCHIOCTL SIOCDEVPRIVATE - -#endif diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c deleted file mode 100644 index 93b41a7ac175..000000000000 --- a/drivers/net/cxgb3/cxgb3_main.c +++ /dev/null @@ -1,3448 +0,0 @@ -/* - * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "common.h" -#include "cxgb3_ioctl.h" -#include "regs.h" -#include "cxgb3_offload.h" -#include "version.h" - -#include "cxgb3_ctl_defs.h" -#include "t3_cpl.h" -#include "firmware_exports.h" - -enum { - MAX_TXQ_ENTRIES = 16384, - MAX_CTRL_TXQ_ENTRIES = 1024, - MAX_RSPQ_ENTRIES = 16384, - MAX_RX_BUFFERS = 16384, - MAX_RX_JUMBO_BUFFERS = 16384, - MIN_TXQ_ENTRIES = 4, - MIN_CTRL_TXQ_ENTRIES = 4, - MIN_RSPQ_ENTRIES = 32, - MIN_FL_ENTRIES = 32 -}; - -#define PORT_MASK ((1 << MAX_NPORTS) - 1) - -#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \ - NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\ - NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) - -#define EEPROM_MAGIC 0x38E2F10C - -#define CH_DEVICE(devid, idx) \ - { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, PCI_ANY_ID, 0, 0, idx } - -static DEFINE_PCI_DEVICE_TABLE(cxgb3_pci_tbl) = { - CH_DEVICE(0x20, 0), /* PE9000 */ - CH_DEVICE(0x21, 1), /* T302E */ - CH_DEVICE(0x22, 2), /* T310E */ - CH_DEVICE(0x23, 3), /* T320X */ - CH_DEVICE(0x24, 1), /* T302X */ - CH_DEVICE(0x25, 3), /* T320E */ - CH_DEVICE(0x26, 2), /* T310X */ - CH_DEVICE(0x30, 2), /* T3B10 */ - CH_DEVICE(0x31, 3), /* T3B20 */ - CH_DEVICE(0x32, 1), /* T3B02 */ - CH_DEVICE(0x35, 6), /* T3C20-derived T3C10 */ - CH_DEVICE(0x36, 3), /* S320E-CR */ - CH_DEVICE(0x37, 7), /* N320E-G2 */ - {0,} -}; - -MODULE_DESCRIPTION(DRV_DESC); -MODULE_AUTHOR("Chelsio Communications"); -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_VERSION(DRV_VERSION); -MODULE_DEVICE_TABLE(pci, cxgb3_pci_tbl); - -static int dflt_msg_enable = DFLT_MSG_ENABLE; - -module_param(dflt_msg_enable, int, 0644); -MODULE_PARM_DESC(dflt_msg_enable, "Chelsio T3 default message enable bitmap"); - -/* - * The driver uses the best interrupt scheme available on a platform in the - * order MSI-X, MSI, legacy pin interrupts. This parameter determines which - * of these schemes the driver may consider as follows: - * - * msi = 2: choose from among all three options - * msi = 1: only consider MSI and pin interrupts - * msi = 0: force pin interrupts - */ -static int msi = 2; - -module_param(msi, int, 0644); -MODULE_PARM_DESC(msi, "whether to use MSI or MSI-X"); - -/* - * The driver enables offload as a default. - * To disable it, use ofld_disable = 1. - */ - -static int ofld_disable = 0; - -module_param(ofld_disable, int, 0644); -MODULE_PARM_DESC(ofld_disable, "whether to enable offload at init time or not"); - -/* - * We have work elements that we need to cancel when an interface is taken - * down. Normally the work elements would be executed by keventd but that - * can deadlock because of linkwatch. If our close method takes the rtnl - * lock and linkwatch is ahead of our work elements in keventd, linkwatch - * will block keventd as it needs the rtnl lock, and we'll deadlock waiting - * for our work to complete. Get our own work queue to solve this. - */ -struct workqueue_struct *cxgb3_wq; - -/** - * link_report - show link status and link speed/duplex - * @p: the port whose settings are to be reported - * - * Shows the link status, speed, and duplex of a port. - */ -static void link_report(struct net_device *dev) -{ - if (!netif_carrier_ok(dev)) - printk(KERN_INFO "%s: link down\n", dev->name); - else { - const char *s = "10Mbps"; - const struct port_info *p = netdev_priv(dev); - - switch (p->link_config.speed) { - case SPEED_10000: - s = "10Gbps"; - break; - case SPEED_1000: - s = "1000Mbps"; - break; - case SPEED_100: - s = "100Mbps"; - break; - } - - printk(KERN_INFO "%s: link up, %s, %s-duplex\n", dev->name, s, - p->link_config.duplex == DUPLEX_FULL ? "full" : "half"); - } -} - -static void enable_tx_fifo_drain(struct adapter *adapter, - struct port_info *pi) -{ - t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset, 0, - F_ENDROPPKT); - t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, 0); - t3_write_reg(adapter, A_XGM_TX_CTRL + pi->mac.offset, F_TXEN); - t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, F_RXEN); -} - -static void disable_tx_fifo_drain(struct adapter *adapter, - struct port_info *pi) -{ - t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset, - F_ENDROPPKT, 0); -} - -void t3_os_link_fault(struct adapter *adap, int port_id, int state) -{ - struct net_device *dev = adap->port[port_id]; - struct port_info *pi = netdev_priv(dev); - - if (state == netif_carrier_ok(dev)) - return; - - if (state) { - struct cmac *mac = &pi->mac; - - netif_carrier_on(dev); - - disable_tx_fifo_drain(adap, pi); - - /* Clear local faults */ - t3_xgm_intr_disable(adap, pi->port_id); - t3_read_reg(adap, A_XGM_INT_STATUS + - pi->mac.offset); - t3_write_reg(adap, - A_XGM_INT_CAUSE + pi->mac.offset, - F_XGM_INT); - - t3_set_reg_field(adap, - A_XGM_INT_ENABLE + - pi->mac.offset, - F_XGM_INT, F_XGM_INT); - t3_xgm_intr_enable(adap, pi->port_id); - - t3_mac_enable(mac, MAC_DIRECTION_TX); - } else { - netif_carrier_off(dev); - - /* Flush TX FIFO */ - enable_tx_fifo_drain(adap, pi); - } - link_report(dev); -} - -/** - * t3_os_link_changed - handle link status changes - * @adapter: the adapter associated with the link change - * @port_id: the port index whose limk status has changed - * @link_stat: the new status of the link - * @speed: the new speed setting - * @duplex: the new duplex setting - * @pause: the new flow-control setting - * - * This is the OS-dependent handler for link status changes. The OS - * neutral handler takes care of most of the processing for these events, - * then calls this handler for any OS-specific processing. - */ -void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat, - int speed, int duplex, int pause) -{ - struct net_device *dev = adapter->port[port_id]; - struct port_info *pi = netdev_priv(dev); - struct cmac *mac = &pi->mac; - - /* Skip changes from disabled ports. */ - if (!netif_running(dev)) - return; - - if (link_stat != netif_carrier_ok(dev)) { - if (link_stat) { - disable_tx_fifo_drain(adapter, pi); - - t3_mac_enable(mac, MAC_DIRECTION_RX); - - /* Clear local faults */ - t3_xgm_intr_disable(adapter, pi->port_id); - t3_read_reg(adapter, A_XGM_INT_STATUS + - pi->mac.offset); - t3_write_reg(adapter, - A_XGM_INT_CAUSE + pi->mac.offset, - F_XGM_INT); - - t3_set_reg_field(adapter, - A_XGM_INT_ENABLE + pi->mac.offset, - F_XGM_INT, F_XGM_INT); - t3_xgm_intr_enable(adapter, pi->port_id); - - netif_carrier_on(dev); - } else { - netif_carrier_off(dev); - - t3_xgm_intr_disable(adapter, pi->port_id); - t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset); - t3_set_reg_field(adapter, - A_XGM_INT_ENABLE + pi->mac.offset, - F_XGM_INT, 0); - - if (is_10G(adapter)) - pi->phy.ops->power_down(&pi->phy, 1); - - t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset); - t3_mac_disable(mac, MAC_DIRECTION_RX); - t3_link_start(&pi->phy, mac, &pi->link_config); - - /* Flush TX FIFO */ - enable_tx_fifo_drain(adapter, pi); - } - - link_report(dev); - } -} - -/** - * t3_os_phymod_changed - handle PHY module changes - * @phy: the PHY reporting the module change - * @mod_type: new module type - * - * This is the OS-dependent handler for PHY module changes. It is - * invoked when a PHY module is removed or inserted for any OS-specific - * processing. - */ -void t3_os_phymod_changed(struct adapter *adap, int port_id) -{ - static const char *mod_str[] = { - NULL, "SR", "LR", "LRM", "TWINAX", "TWINAX", "unknown" - }; - - const struct net_device *dev = adap->port[port_id]; - const struct port_info *pi = netdev_priv(dev); - - if (pi->phy.modtype == phy_modtype_none) - printk(KERN_INFO "%s: PHY module unplugged\n", dev->name); - else - printk(KERN_INFO "%s: %s PHY module inserted\n", dev->name, - mod_str[pi->phy.modtype]); -} - -static void cxgb_set_rxmode(struct net_device *dev) -{ - struct port_info *pi = netdev_priv(dev); - - t3_mac_set_rx_mode(&pi->mac, dev); -} - -/** - * link_start - enable a port - * @dev: the device to enable - * - * Performs the MAC and PHY actions needed to enable a port. - */ -static void link_start(struct net_device *dev) -{ - struct port_info *pi = netdev_priv(dev); - struct cmac *mac = &pi->mac; - - t3_mac_reset(mac); - t3_mac_set_num_ucast(mac, MAX_MAC_IDX); - t3_mac_set_mtu(mac, dev->mtu); - t3_mac_set_address(mac, LAN_MAC_IDX, dev->dev_addr); - t3_mac_set_address(mac, SAN_MAC_IDX, pi->iscsic.mac_addr); - t3_mac_set_rx_mode(mac, dev); - t3_link_start(&pi->phy, mac, &pi->link_config); - t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); -} - -static inline void cxgb_disable_msi(struct adapter *adapter) -{ - if (adapter->flags & USING_MSIX) { - pci_disable_msix(adapter->pdev); - adapter->flags &= ~USING_MSIX; - } else if (adapter->flags & USING_MSI) { - pci_disable_msi(adapter->pdev); - adapter->flags &= ~USING_MSI; - } -} - -/* - * Interrupt handler for asynchronous events used with MSI-X. - */ -static irqreturn_t t3_async_intr_handler(int irq, void *cookie) -{ - t3_slow_intr_handler(cookie); - return IRQ_HANDLED; -} - -/* - * Name the MSI-X interrupts. - */ -static void name_msix_vecs(struct adapter *adap) -{ - int i, j, msi_idx = 1, n = sizeof(adap->msix_info[0].desc) - 1; - - snprintf(adap->msix_info[0].desc, n, "%s", adap->name); - adap->msix_info[0].desc[n] = 0; - - for_each_port(adap, j) { - struct net_device *d = adap->port[j]; - const struct port_info *pi = netdev_priv(d); - - for (i = 0; i < pi->nqsets; i++, msi_idx++) { - snprintf(adap->msix_info[msi_idx].desc, n, - "%s-%d", d->name, pi->first_qset + i); - adap->msix_info[msi_idx].desc[n] = 0; - } - } -} - -static int request_msix_data_irqs(struct adapter *adap) -{ - int i, j, err, qidx = 0; - - for_each_port(adap, i) { - int nqsets = adap2pinfo(adap, i)->nqsets; - - for (j = 0; j < nqsets; ++j) { - err = request_irq(adap->msix_info[qidx + 1].vec, - t3_intr_handler(adap, - adap->sge.qs[qidx]. - rspq.polling), 0, - adap->msix_info[qidx + 1].desc, - &adap->sge.qs[qidx]); - if (err) { - while (--qidx >= 0) - free_irq(adap->msix_info[qidx + 1].vec, - &adap->sge.qs[qidx]); - return err; - } - qidx++; - } - } - return 0; -} - -static void free_irq_resources(struct adapter *adapter) -{ - if (adapter->flags & USING_MSIX) { - int i, n = 0; - - free_irq(adapter->msix_info[0].vec, adapter); - for_each_port(adapter, i) - n += adap2pinfo(adapter, i)->nqsets; - - for (i = 0; i < n; ++i) - free_irq(adapter->msix_info[i + 1].vec, - &adapter->sge.qs[i]); - } else - free_irq(adapter->pdev->irq, adapter); -} - -static int await_mgmt_replies(struct adapter *adap, unsigned long init_cnt, - unsigned long n) -{ - int attempts = 10; - - while (adap->sge.qs[0].rspq.offload_pkts < init_cnt + n) { - if (!--attempts) - return -ETIMEDOUT; - msleep(10); - } - return 0; -} - -static int init_tp_parity(struct adapter *adap) -{ - int i; - struct sk_buff *skb; - struct cpl_set_tcb_field *greq; - unsigned long cnt = adap->sge.qs[0].rspq.offload_pkts; - - t3_tp_set_offload_mode(adap, 1); - - for (i = 0; i < 16; i++) { - struct cpl_smt_write_req *req; - - skb = alloc_skb(sizeof(*req), GFP_KERNEL); - if (!skb) - skb = adap->nofail_skb; - if (!skb) - goto alloc_skb_fail; - - req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req)); - memset(req, 0, sizeof(*req)); - req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); - OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i)); - req->mtu_idx = NMTUS - 1; - req->iff = i; - t3_mgmt_tx(adap, skb); - if (skb == adap->nofail_skb) { - await_mgmt_replies(adap, cnt, i + 1); - adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL); - if (!adap->nofail_skb) - goto alloc_skb_fail; - } - } - - for (i = 0; i < 2048; i++) { - struct cpl_l2t_write_req *req; - - skb = alloc_skb(sizeof(*req), GFP_KERNEL); - if (!skb) - skb = adap->nofail_skb; - if (!skb) - goto alloc_skb_fail; - - req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req)); - memset(req, 0, sizeof(*req)); - req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); - OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i)); - req->params = htonl(V_L2T_W_IDX(i)); - t3_mgmt_tx(adap, skb); - if (skb == adap->nofail_skb) { - await_mgmt_replies(adap, cnt, 16 + i + 1); - adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL); - if (!adap->nofail_skb) - goto alloc_skb_fail; - } - } - - for (i = 0; i < 2048; i++) { - struct cpl_rte_write_req *req; - - skb = alloc_skb(sizeof(*req), GFP_KERNEL); - if (!skb) - skb = adap->nofail_skb; - if (!skb) - goto alloc_skb_fail; - - req = (struct cpl_rte_write_req *)__skb_put(skb, sizeof(*req)); - memset(req, 0, sizeof(*req)); - req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); - OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i)); - req->l2t_idx = htonl(V_L2T_W_IDX(i)); - t3_mgmt_tx(adap, skb); - if (skb == adap->nofail_skb) { - await_mgmt_replies(adap, cnt, 16 + 2048 + i + 1); - adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL); - if (!adap->nofail_skb) - goto alloc_skb_fail; - } - } - - skb = alloc_skb(sizeof(*greq), GFP_KERNEL); - if (!skb) - skb = adap->nofail_skb; - if (!skb) - goto alloc_skb_fail; - - greq = (struct cpl_set_tcb_field *)__skb_put(skb, sizeof(*greq)); - memset(greq, 0, sizeof(*greq)); - greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); - OPCODE_TID(greq) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, 0)); - greq->mask = cpu_to_be64(1); - t3_mgmt_tx(adap, skb); - - i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1); - if (skb == adap->nofail_skb) { - i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1); - adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL); - } - - t3_tp_set_offload_mode(adap, 0); - return i; - -alloc_skb_fail: - t3_tp_set_offload_mode(adap, 0); - return -ENOMEM; -} - -/** - * setup_rss - configure RSS - * @adap: the adapter - * - * Sets up RSS to distribute packets to multiple receive queues. We - * configure the RSS CPU lookup table to distribute to the number of HW - * receive queues, and the response queue lookup table to narrow that - * down to the response queues actually configured for each port. - * We always configure the RSS mapping for two ports since the mapping - * table has plenty of entries. - */ -static void setup_rss(struct adapter *adap) -{ - int i; - unsigned int nq0 = adap2pinfo(adap, 0)->nqsets; - unsigned int nq1 = adap->port[1] ? adap2pinfo(adap, 1)->nqsets : 1; - u8 cpus[SGE_QSETS + 1]; - u16 rspq_map[RSS_TABLE_SIZE]; - - for (i = 0; i < SGE_QSETS; ++i) - cpus[i] = i; - cpus[SGE_QSETS] = 0xff; /* terminator */ - - for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) { - rspq_map[i] = i % nq0; - rspq_map[i + RSS_TABLE_SIZE / 2] = (i % nq1) + nq0; - } - - t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN | - F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN | - V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ, cpus, rspq_map); -} - -static void ring_dbs(struct adapter *adap) -{ - int i, j; - - for (i = 0; i < SGE_QSETS; i++) { - struct sge_qset *qs = &adap->sge.qs[i]; - - if (qs->adap) - for (j = 0; j < SGE_TXQ_PER_SET; j++) - t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX | V_EGRCNTX(qs->txq[j].cntxt_id)); - } -} - -static void init_napi(struct adapter *adap) -{ - int i; - - for (i = 0; i < SGE_QSETS; i++) { - struct sge_qset *qs = &adap->sge.qs[i]; - - if (qs->adap) - netif_napi_add(qs->netdev, &qs->napi, qs->napi.poll, - 64); - } - - /* - * netif_napi_add() can be called only once per napi_struct because it - * adds each new napi_struct to a list. Be careful not to call it a - * second time, e.g., during EEH recovery, by making a note of it. - */ - adap->flags |= NAPI_INIT; -} - -/* - * Wait until all NAPI handlers are descheduled. This includes the handlers of - * both netdevices representing interfaces and the dummy ones for the extra - * queues. - */ -static void quiesce_rx(struct adapter *adap) -{ - int i; - - for (i = 0; i < SGE_QSETS; i++) - if (adap->sge.qs[i].adap) - napi_disable(&adap->sge.qs[i].napi); -} - -static void enable_all_napi(struct adapter *adap) -{ - int i; - for (i = 0; i < SGE_QSETS; i++) - if (adap->sge.qs[i].adap) - napi_enable(&adap->sge.qs[i].napi); -} - -/** - * setup_sge_qsets - configure SGE Tx/Rx/response queues - * @adap: the adapter - * - * Determines how many sets of SGE queues to use and initializes them. - * We support multiple queue sets per port if we have MSI-X, otherwise - * just one queue set per port. - */ -static int setup_sge_qsets(struct adapter *adap) -{ - int i, j, err, irq_idx = 0, qset_idx = 0; - unsigned int ntxq = SGE_TXQ_PER_SET; - - if (adap->params.rev > 0 && !(adap->flags & USING_MSI)) - irq_idx = -1; - - for_each_port(adap, i) { - struct net_device *dev = adap->port[i]; - struct port_info *pi = netdev_priv(dev); - - pi->qs = &adap->sge.qs[pi->first_qset]; - for (j = 0; j < pi->nqsets; ++j, ++qset_idx) { - err = t3_sge_alloc_qset(adap, qset_idx, 1, - (adap->flags & USING_MSIX) ? qset_idx + 1 : - irq_idx, - &adap->params.sge.qset[qset_idx], ntxq, dev, - netdev_get_tx_queue(dev, j)); - if (err) { - t3_free_sge_resources(adap); - return err; - } - } - } - - return 0; -} - -static ssize_t attr_show(struct device *d, char *buf, - ssize_t(*format) (struct net_device *, char *)) -{ - ssize_t len; - - /* Synchronize with ioctls that may shut down the device */ - rtnl_lock(); - len = (*format) (to_net_dev(d), buf); - rtnl_unlock(); - return len; -} - -static ssize_t attr_store(struct device *d, - const char *buf, size_t len, - ssize_t(*set) (struct net_device *, unsigned int), - unsigned int min_val, unsigned int max_val) -{ - char *endp; - ssize_t ret; - unsigned int val; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - val = simple_strtoul(buf, &endp, 0); - if (endp == buf || val < min_val || val > max_val) - return -EINVAL; - - rtnl_lock(); - ret = (*set) (to_net_dev(d), val); - if (!ret) - ret = len; - rtnl_unlock(); - return ret; -} - -#define CXGB3_SHOW(name, val_expr) \ -static ssize_t format_##name(struct net_device *dev, char *buf) \ -{ \ - struct port_info *pi = netdev_priv(dev); \ - struct adapter *adap = pi->adapter; \ - return sprintf(buf, "%u\n", val_expr); \ -} \ -static ssize_t show_##name(struct device *d, struct device_attribute *attr, \ - char *buf) \ -{ \ - return attr_show(d, buf, format_##name); \ -} - -static ssize_t set_nfilters(struct net_device *dev, unsigned int val) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adap = pi->adapter; - int min_tids = is_offload(adap) ? MC5_MIN_TIDS : 0; - - if (adap->flags & FULL_INIT_DONE) - return -EBUSY; - if (val && adap->params.rev == 0) - return -EINVAL; - if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers - - min_tids) - return -EINVAL; - adap->params.mc5.nfilters = val; - return 0; -} - -static ssize_t store_nfilters(struct device *d, struct device_attribute *attr, - const char *buf, size_t len) -{ - return attr_store(d, buf, len, set_nfilters, 0, ~0); -} - -static ssize_t set_nservers(struct net_device *dev, unsigned int val) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adap = pi->adapter; - - if (adap->flags & FULL_INIT_DONE) - return -EBUSY; - if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nfilters - - MC5_MIN_TIDS) - return -EINVAL; - adap->params.mc5.nservers = val; - return 0; -} - -static ssize_t store_nservers(struct device *d, struct device_attribute *attr, - const char *buf, size_t len) -{ - return attr_store(d, buf, len, set_nservers, 0, ~0); -} - -#define CXGB3_ATTR_R(name, val_expr) \ -CXGB3_SHOW(name, val_expr) \ -static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) - -#define CXGB3_ATTR_RW(name, val_expr, store_method) \ -CXGB3_SHOW(name, val_expr) \ -static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_method) - -CXGB3_ATTR_R(cam_size, t3_mc5_size(&adap->mc5)); -CXGB3_ATTR_RW(nfilters, adap->params.mc5.nfilters, store_nfilters); -CXGB3_ATTR_RW(nservers, adap->params.mc5.nservers, store_nservers); - -static struct attribute *cxgb3_attrs[] = { - &dev_attr_cam_size.attr, - &dev_attr_nfilters.attr, - &dev_attr_nservers.attr, - NULL -}; - -static struct attribute_group cxgb3_attr_group = {.attrs = cxgb3_attrs }; - -static ssize_t tm_attr_show(struct device *d, - char *buf, int sched) -{ - struct port_info *pi = netdev_priv(to_net_dev(d)); - struct adapter *adap = pi->adapter; - unsigned int v, addr, bpt, cpt; - ssize_t len; - - addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2; - rtnl_lock(); - t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr); - v = t3_read_reg(adap, A_TP_TM_PIO_DATA); - if (sched & 1) - v >>= 16; - bpt = (v >> 8) & 0xff; - cpt = v & 0xff; - if (!cpt) - len = sprintf(buf, "disabled\n"); - else { - v = (adap->params.vpd.cclk * 1000) / cpt; - len = sprintf(buf, "%u Kbps\n", (v * bpt) / 125); - } - rtnl_unlock(); - return len; -} - -static ssize_t tm_attr_store(struct device *d, - const char *buf, size_t len, int sched) -{ - struct port_info *pi = netdev_priv(to_net_dev(d)); - struct adapter *adap = pi->adapter; - unsigned int val; - char *endp; - ssize_t ret; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - val = simple_strtoul(buf, &endp, 0); - if (endp == buf || val > 10000000) - return -EINVAL; - - rtnl_lock(); - ret = t3_config_sched(adap, val, sched); - if (!ret) - ret = len; - rtnl_unlock(); - return ret; -} - -#define TM_ATTR(name, sched) \ -static ssize_t show_##name(struct device *d, struct device_attribute *attr, \ - char *buf) \ -{ \ - return tm_attr_show(d, buf, sched); \ -} \ -static ssize_t store_##name(struct device *d, struct device_attribute *attr, \ - const char *buf, size_t len) \ -{ \ - return tm_attr_store(d, buf, len, sched); \ -} \ -static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name) - -TM_ATTR(sched0, 0); -TM_ATTR(sched1, 1); -TM_ATTR(sched2, 2); -TM_ATTR(sched3, 3); -TM_ATTR(sched4, 4); -TM_ATTR(sched5, 5); -TM_ATTR(sched6, 6); -TM_ATTR(sched7, 7); - -static struct attribute *offload_attrs[] = { - &dev_attr_sched0.attr, - &dev_attr_sched1.attr, - &dev_attr_sched2.attr, - &dev_attr_sched3.attr, - &dev_attr_sched4.attr, - &dev_attr_sched5.attr, - &dev_attr_sched6.attr, - &dev_attr_sched7.attr, - NULL -}; - -static struct attribute_group offload_attr_group = {.attrs = offload_attrs }; - -/* - * Sends an sk_buff to an offload queue driver - * after dealing with any active network taps. - */ -static inline int offload_tx(struct t3cdev *tdev, struct sk_buff *skb) -{ - int ret; - - local_bh_disable(); - ret = t3_offload_tx(tdev, skb); - local_bh_enable(); - return ret; -} - -static int write_smt_entry(struct adapter *adapter, int idx) -{ - struct cpl_smt_write_req *req; - struct port_info *pi = netdev_priv(adapter->port[idx]); - struct sk_buff *skb = alloc_skb(sizeof(*req), GFP_KERNEL); - - if (!skb) - return -ENOMEM; - - req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req)); - req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); - OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx)); - req->mtu_idx = NMTUS - 1; /* should be 0 but there's a T3 bug */ - req->iff = idx; - memcpy(req->src_mac0, adapter->port[idx]->dev_addr, ETH_ALEN); - memcpy(req->src_mac1, pi->iscsic.mac_addr, ETH_ALEN); - skb->priority = 1; - offload_tx(&adapter->tdev, skb); - return 0; -} - -static int init_smt(struct adapter *adapter) -{ - int i; - - for_each_port(adapter, i) - write_smt_entry(adapter, i); - return 0; -} - -static void init_port_mtus(struct adapter *adapter) -{ - unsigned int mtus = adapter->port[0]->mtu; - - if (adapter->port[1]) - mtus |= adapter->port[1]->mtu << 16; - t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus); -} - -static int send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo, - int hi, int port) -{ - struct sk_buff *skb; - struct mngt_pktsched_wr *req; - int ret; - - skb = alloc_skb(sizeof(*req), GFP_KERNEL); - if (!skb) - skb = adap->nofail_skb; - if (!skb) - return -ENOMEM; - - req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req)); - req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT)); - req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET; - req->sched = sched; - req->idx = qidx; - req->min = lo; - req->max = hi; - req->binding = port; - ret = t3_mgmt_tx(adap, skb); - if (skb == adap->nofail_skb) { - adap->nofail_skb = alloc_skb(sizeof(struct cpl_set_tcb_field), - GFP_KERNEL); - if (!adap->nofail_skb) - ret = -ENOMEM; - } - - return ret; -} - -static int bind_qsets(struct adapter *adap) -{ - int i, j, err = 0; - - for_each_port(adap, i) { - const struct port_info *pi = adap2pinfo(adap, i); - - for (j = 0; j < pi->nqsets; ++j) { - int ret = send_pktsched_cmd(adap, 1, - pi->first_qset + j, -1, - -1, i); - if (ret) - err = ret; - } - } - - return err; -} - -#define FW_VERSION __stringify(FW_VERSION_MAJOR) "." \ - __stringify(FW_VERSION_MINOR) "." __stringify(FW_VERSION_MICRO) -#define FW_FNAME "cxgb3/t3fw-" FW_VERSION ".bin" -#define TPSRAM_VERSION __stringify(TP_VERSION_MAJOR) "." \ - __stringify(TP_VERSION_MINOR) "." __stringify(TP_VERSION_MICRO) -#define TPSRAM_NAME "cxgb3/t3%c_psram-" TPSRAM_VERSION ".bin" -#define AEL2005_OPT_EDC_NAME "cxgb3/ael2005_opt_edc.bin" -#define AEL2005_TWX_EDC_NAME "cxgb3/ael2005_twx_edc.bin" -#define AEL2020_TWX_EDC_NAME "cxgb3/ael2020_twx_edc.bin" -MODULE_FIRMWARE(FW_FNAME); -MODULE_FIRMWARE("cxgb3/t3b_psram-" TPSRAM_VERSION ".bin"); -MODULE_FIRMWARE("cxgb3/t3c_psram-" TPSRAM_VERSION ".bin"); -MODULE_FIRMWARE(AEL2005_OPT_EDC_NAME); -MODULE_FIRMWARE(AEL2005_TWX_EDC_NAME); -MODULE_FIRMWARE(AEL2020_TWX_EDC_NAME); - -static inline const char *get_edc_fw_name(int edc_idx) -{ - const char *fw_name = NULL; - - switch (edc_idx) { - case EDC_OPT_AEL2005: - fw_name = AEL2005_OPT_EDC_NAME; - break; - case EDC_TWX_AEL2005: - fw_name = AEL2005_TWX_EDC_NAME; - break; - case EDC_TWX_AEL2020: - fw_name = AEL2020_TWX_EDC_NAME; - break; - } - return fw_name; -} - -int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size) -{ - struct adapter *adapter = phy->adapter; - const struct firmware *fw; - char buf[64]; - u32 csum; - const __be32 *p; - u16 *cache = phy->phy_cache; - int i, ret; - - snprintf(buf, sizeof(buf), get_edc_fw_name(edc_idx)); - - ret = request_firmware(&fw, buf, &adapter->pdev->dev); - if (ret < 0) { - dev_err(&adapter->pdev->dev, - "could not upgrade firmware: unable to load %s\n", - buf); - return ret; - } - - /* check size, take checksum in account */ - if (fw->size > size + 4) { - CH_ERR(adapter, "firmware image too large %u, expected %d\n", - (unsigned int)fw->size, size + 4); - ret = -EINVAL; - } - - /* compute checksum */ - p = (const __be32 *)fw->data; - for (csum = 0, i = 0; i < fw->size / sizeof(csum); i++) - csum += ntohl(p[i]); - - if (csum != 0xffffffff) { - CH_ERR(adapter, "corrupted firmware image, checksum %u\n", - csum); - ret = -EINVAL; - } - - for (i = 0; i < size / 4 ; i++) { - *cache++ = (be32_to_cpu(p[i]) & 0xffff0000) >> 16; - *cache++ = be32_to_cpu(p[i]) & 0xffff; - } - - release_firmware(fw); - - return ret; -} - -static int upgrade_fw(struct adapter *adap) -{ - int ret; - const struct firmware *fw; - struct device *dev = &adap->pdev->dev; - - ret = request_firmware(&fw, FW_FNAME, dev); - if (ret < 0) { - dev_err(dev, "could not upgrade firmware: unable to load %s\n", - FW_FNAME); - return ret; - } - ret = t3_load_fw(adap, fw->data, fw->size); - release_firmware(fw); - - if (ret == 0) - dev_info(dev, "successful upgrade to firmware %d.%d.%d\n", - FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO); - else - dev_err(dev, "failed to upgrade to firmware %d.%d.%d\n", - FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO); - - return ret; -} - -static inline char t3rev2char(struct adapter *adapter) -{ - char rev = 0; - - switch(adapter->params.rev) { - case T3_REV_B: - case T3_REV_B2: - rev = 'b'; - break; - case T3_REV_C: - rev = 'c'; - break; - } - return rev; -} - -static int update_tpsram(struct adapter *adap) -{ - const struct firmware *tpsram; - char buf[64]; - struct device *dev = &adap->pdev->dev; - int ret; - char rev; - - rev = t3rev2char(adap); - if (!rev) - return 0; - - snprintf(buf, sizeof(buf), TPSRAM_NAME, rev); - - ret = request_firmware(&tpsram, buf, dev); - if (ret < 0) { - dev_err(dev, "could not load TP SRAM: unable to load %s\n", - buf); - return ret; - } - - ret = t3_check_tpsram(adap, tpsram->data, tpsram->size); - if (ret) - goto release_tpsram; - - ret = t3_set_proto_sram(adap, tpsram->data); - if (ret == 0) - dev_info(dev, - "successful update of protocol engine " - "to %d.%d.%d\n", - TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO); - else - dev_err(dev, "failed to update of protocol engine %d.%d.%d\n", - TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO); - if (ret) - dev_err(dev, "loading protocol SRAM failed\n"); - -release_tpsram: - release_firmware(tpsram); - - return ret; -} - -/** - * cxgb_up - enable the adapter - * @adapter: adapter being enabled - * - * Called when the first port is enabled, this function performs the - * actions necessary to make an adapter operational, such as completing - * the initialization of HW modules, and enabling interrupts. - * - * Must be called with the rtnl lock held. - */ -static int cxgb_up(struct adapter *adap) -{ - int err; - - if (!(adap->flags & FULL_INIT_DONE)) { - err = t3_check_fw_version(adap); - if (err == -EINVAL) { - err = upgrade_fw(adap); - CH_WARN(adap, "FW upgrade to %d.%d.%d %s\n", - FW_VERSION_MAJOR, FW_VERSION_MINOR, - FW_VERSION_MICRO, err ? "failed" : "succeeded"); - } - - err = t3_check_tpsram_version(adap); - if (err == -EINVAL) { - err = update_tpsram(adap); - CH_WARN(adap, "TP upgrade to %d.%d.%d %s\n", - TP_VERSION_MAJOR, TP_VERSION_MINOR, - TP_VERSION_MICRO, err ? "failed" : "succeeded"); - } - - /* - * Clear interrupts now to catch errors if t3_init_hw fails. - * We clear them again later as initialization may trigger - * conditions that can interrupt. - */ - t3_intr_clear(adap); - - err = t3_init_hw(adap, 0); - if (err) - goto out; - - t3_set_reg_field(adap, A_TP_PARA_REG5, 0, F_RXDDPOFFINIT); - t3_write_reg(adap, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12)); - - err = setup_sge_qsets(adap); - if (err) - goto out; - - setup_rss(adap); - if (!(adap->flags & NAPI_INIT)) - init_napi(adap); - - t3_start_sge_timers(adap); - adap->flags |= FULL_INIT_DONE; - } - - t3_intr_clear(adap); - - if (adap->flags & USING_MSIX) { - name_msix_vecs(adap); - err = request_irq(adap->msix_info[0].vec, - t3_async_intr_handler, 0, - adap->msix_info[0].desc, adap); - if (err) - goto irq_err; - - err = request_msix_data_irqs(adap); - if (err) { - free_irq(adap->msix_info[0].vec, adap); - goto irq_err; - } - } else if ((err = request_irq(adap->pdev->irq, - t3_intr_handler(adap, - adap->sge.qs[0].rspq. - polling), - (adap->flags & USING_MSI) ? - 0 : IRQF_SHARED, - adap->name, adap))) - goto irq_err; - - enable_all_napi(adap); - t3_sge_start(adap); - t3_intr_enable(adap); - - if (adap->params.rev >= T3_REV_C && !(adap->flags & TP_PARITY_INIT) && - is_offload(adap) && init_tp_parity(adap) == 0) - adap->flags |= TP_PARITY_INIT; - - if (adap->flags & TP_PARITY_INIT) { - t3_write_reg(adap, A_TP_INT_CAUSE, - F_CMCACHEPERR | F_ARPLUTPERR); - t3_write_reg(adap, A_TP_INT_ENABLE, 0x7fbfffff); - } - - if (!(adap->flags & QUEUES_BOUND)) { - int ret = bind_qsets(adap); - - if (ret < 0) { - CH_ERR(adap, "failed to bind qsets, err %d\n", ret); - t3_intr_disable(adap); - free_irq_resources(adap); - err = ret; - goto out; - } - adap->flags |= QUEUES_BOUND; - } - -out: - return err; -irq_err: - CH_ERR(adap, "request_irq failed, err %d\n", err); - goto out; -} - -/* - * Release resources when all the ports and offloading have been stopped. - */ -static void cxgb_down(struct adapter *adapter, int on_wq) -{ - t3_sge_stop(adapter); - spin_lock_irq(&adapter->work_lock); /* sync with PHY intr task */ - t3_intr_disable(adapter); - spin_unlock_irq(&adapter->work_lock); - - free_irq_resources(adapter); - quiesce_rx(adapter); - t3_sge_stop(adapter); - if (!on_wq) - flush_workqueue(cxgb3_wq);/* wait for external IRQ handler */ -} - -static void schedule_chk_task(struct adapter *adap) -{ - unsigned int timeo; - - timeo = adap->params.linkpoll_period ? - (HZ * adap->params.linkpoll_period) / 10 : - adap->params.stats_update_period * HZ; - if (timeo) - queue_delayed_work(cxgb3_wq, &adap->adap_check_task, timeo); -} - -static int offload_open(struct net_device *dev) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - struct t3cdev *tdev = dev2t3cdev(dev); - int adap_up = adapter->open_device_map & PORT_MASK; - int err; - - if (test_and_set_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) - return 0; - - if (!adap_up && (err = cxgb_up(adapter)) < 0) - goto out; - - t3_tp_set_offload_mode(adapter, 1); - tdev->lldev = adapter->port[0]; - err = cxgb3_offload_activate(adapter); - if (err) - goto out; - - init_port_mtus(adapter); - t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd, - adapter->params.b_wnd, - adapter->params.rev == 0 ? - adapter->port[0]->mtu : 0xffff); - init_smt(adapter); - - if (sysfs_create_group(&tdev->lldev->dev.kobj, &offload_attr_group)) - dev_dbg(&dev->dev, "cannot create sysfs group\n"); - - /* Call back all registered clients */ - cxgb3_add_clients(tdev); - -out: - /* restore them in case the offload module has changed them */ - if (err) { - t3_tp_set_offload_mode(adapter, 0); - clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map); - cxgb3_set_dummy_ops(tdev); - } - return err; -} - -static int offload_close(struct t3cdev *tdev) -{ - struct adapter *adapter = tdev2adap(tdev); - struct t3c_data *td = T3C_DATA(tdev); - - if (!test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) - return 0; - - /* Call back all registered clients */ - cxgb3_remove_clients(tdev); - - sysfs_remove_group(&tdev->lldev->dev.kobj, &offload_attr_group); - - /* Flush work scheduled while releasing TIDs */ - flush_work_sync(&td->tid_release_task); - - tdev->lldev = NULL; - cxgb3_set_dummy_ops(tdev); - t3_tp_set_offload_mode(adapter, 0); - clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map); - - if (!adapter->open_device_map) - cxgb_down(adapter, 0); - - cxgb3_offload_deactivate(adapter); - return 0; -} - -static int cxgb_open(struct net_device *dev) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - int other_ports = adapter->open_device_map & PORT_MASK; - int err; - - if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0) - return err; - - set_bit(pi->port_id, &adapter->open_device_map); - if (is_offload(adapter) && !ofld_disable) { - err = offload_open(dev); - if (err) - printk(KERN_WARNING - "Could not initialize offload capabilities\n"); - } - - netif_set_real_num_tx_queues(dev, pi->nqsets); - err = netif_set_real_num_rx_queues(dev, pi->nqsets); - if (err) - return err; - link_start(dev); - t3_port_intr_enable(adapter, pi->port_id); - netif_tx_start_all_queues(dev); - if (!other_ports) - schedule_chk_task(adapter); - - cxgb3_event_notify(&adapter->tdev, OFFLOAD_PORT_UP, pi->port_id); - return 0; -} - -static int __cxgb_close(struct net_device *dev, int on_wq) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - - - if (!adapter->open_device_map) - return 0; - - /* Stop link fault interrupts */ - t3_xgm_intr_disable(adapter, pi->port_id); - t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset); - - t3_port_intr_disable(adapter, pi->port_id); - netif_tx_stop_all_queues(dev); - pi->phy.ops->power_down(&pi->phy, 1); - netif_carrier_off(dev); - t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX); - - spin_lock_irq(&adapter->work_lock); /* sync with update task */ - clear_bit(pi->port_id, &adapter->open_device_map); - spin_unlock_irq(&adapter->work_lock); - - if (!(adapter->open_device_map & PORT_MASK)) - cancel_delayed_work_sync(&adapter->adap_check_task); - - if (!adapter->open_device_map) - cxgb_down(adapter, on_wq); - - cxgb3_event_notify(&adapter->tdev, OFFLOAD_PORT_DOWN, pi->port_id); - return 0; -} - -static int cxgb_close(struct net_device *dev) -{ - return __cxgb_close(dev, 0); -} - -static struct net_device_stats *cxgb_get_stats(struct net_device *dev) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - struct net_device_stats *ns = &pi->netstats; - const struct mac_stats *pstats; - - spin_lock(&adapter->stats_lock); - pstats = t3_mac_update_stats(&pi->mac); - spin_unlock(&adapter->stats_lock); - - ns->tx_bytes = pstats->tx_octets; - ns->tx_packets = pstats->tx_frames; - ns->rx_bytes = pstats->rx_octets; - ns->rx_packets = pstats->rx_frames; - ns->multicast = pstats->rx_mcast_frames; - - ns->tx_errors = pstats->tx_underrun; - ns->rx_errors = pstats->rx_symbol_errs + pstats->rx_fcs_errs + - pstats->rx_too_long + pstats->rx_jabber + pstats->rx_short + - pstats->rx_fifo_ovfl; - - /* detailed rx_errors */ - ns->rx_length_errors = pstats->rx_jabber + pstats->rx_too_long; - ns->rx_over_errors = 0; - ns->rx_crc_errors = pstats->rx_fcs_errs; - ns->rx_frame_errors = pstats->rx_symbol_errs; - ns->rx_fifo_errors = pstats->rx_fifo_ovfl; - ns->rx_missed_errors = pstats->rx_cong_drops; - - /* detailed tx_errors */ - ns->tx_aborted_errors = 0; - ns->tx_carrier_errors = 0; - ns->tx_fifo_errors = pstats->tx_underrun; - ns->tx_heartbeat_errors = 0; - ns->tx_window_errors = 0; - return ns; -} - -static u32 get_msglevel(struct net_device *dev) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - - return adapter->msg_enable; -} - -static void set_msglevel(struct net_device *dev, u32 val) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - - adapter->msg_enable = val; -} - -static char stats_strings[][ETH_GSTRING_LEN] = { - "TxOctetsOK ", - "TxFramesOK ", - "TxMulticastFramesOK", - "TxBroadcastFramesOK", - "TxPauseFrames ", - "TxUnderrun ", - "TxExtUnderrun ", - - "TxFrames64 ", - "TxFrames65To127 ", - "TxFrames128To255 ", - "TxFrames256To511 ", - "TxFrames512To1023 ", - "TxFrames1024To1518 ", - "TxFrames1519ToMax ", - - "RxOctetsOK ", - "RxFramesOK ", - "RxMulticastFramesOK", - "RxBroadcastFramesOK", - "RxPauseFrames ", - "RxFCSErrors ", - "RxSymbolErrors ", - "RxShortErrors ", - "RxJabberErrors ", - "RxLengthErrors ", - "RxFIFOoverflow ", - - "RxFrames64 ", - "RxFrames65To127 ", - "RxFrames128To255 ", - "RxFrames256To511 ", - "RxFrames512To1023 ", - "RxFrames1024To1518 ", - "RxFrames1519ToMax ", - - "PhyFIFOErrors ", - "TSO ", - "VLANextractions ", - "VLANinsertions ", - "TxCsumOffload ", - "RxCsumGood ", - "LroAggregated ", - "LroFlushed ", - "LroNoDesc ", - "RxDrops ", - - "CheckTXEnToggled ", - "CheckResets ", - - "LinkFaults ", -}; - -static int get_sset_count(struct net_device *dev, int sset) -{ - switch (sset) { - case ETH_SS_STATS: - return ARRAY_SIZE(stats_strings); - default: - return -EOPNOTSUPP; - } -} - -#define T3_REGMAP_SIZE (3 * 1024) - -static int get_regs_len(struct net_device *dev) -{ - return T3_REGMAP_SIZE; -} - -static int get_eeprom_len(struct net_device *dev) -{ - return EEPROMSIZE; -} - -static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - u32 fw_vers = 0; - u32 tp_vers = 0; - - spin_lock(&adapter->stats_lock); - t3_get_fw_version(adapter, &fw_vers); - t3_get_tp_version(adapter, &tp_vers); - spin_unlock(&adapter->stats_lock); - - strcpy(info->driver, DRV_NAME); - strcpy(info->version, DRV_VERSION); - strcpy(info->bus_info, pci_name(adapter->pdev)); - if (!fw_vers) - strcpy(info->fw_version, "N/A"); - else { - snprintf(info->fw_version, sizeof(info->fw_version), - "%s %u.%u.%u TP %u.%u.%u", - G_FW_VERSION_TYPE(fw_vers) ? "T" : "N", - G_FW_VERSION_MAJOR(fw_vers), - G_FW_VERSION_MINOR(fw_vers), - G_FW_VERSION_MICRO(fw_vers), - G_TP_VERSION_MAJOR(tp_vers), - G_TP_VERSION_MINOR(tp_vers), - G_TP_VERSION_MICRO(tp_vers)); - } -} - -static void get_strings(struct net_device *dev, u32 stringset, u8 * data) -{ - if (stringset == ETH_SS_STATS) - memcpy(data, stats_strings, sizeof(stats_strings)); -} - -static unsigned long collect_sge_port_stats(struct adapter *adapter, - struct port_info *p, int idx) -{ - int i; - unsigned long tot = 0; - - for (i = p->first_qset; i < p->first_qset + p->nqsets; ++i) - tot += adapter->sge.qs[i].port_stats[idx]; - return tot; -} - -static void get_stats(struct net_device *dev, struct ethtool_stats *stats, - u64 *data) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - const struct mac_stats *s; - - spin_lock(&adapter->stats_lock); - s = t3_mac_update_stats(&pi->mac); - spin_unlock(&adapter->stats_lock); - - *data++ = s->tx_octets; - *data++ = s->tx_frames; - *data++ = s->tx_mcast_frames; - *data++ = s->tx_bcast_frames; - *data++ = s->tx_pause; - *data++ = s->tx_underrun; - *data++ = s->tx_fifo_urun; - - *data++ = s->tx_frames_64; - *data++ = s->tx_frames_65_127; - *data++ = s->tx_frames_128_255; - *data++ = s->tx_frames_256_511; - *data++ = s->tx_frames_512_1023; - *data++ = s->tx_frames_1024_1518; - *data++ = s->tx_frames_1519_max; - - *data++ = s->rx_octets; - *data++ = s->rx_frames; - *data++ = s->rx_mcast_frames; - *data++ = s->rx_bcast_frames; - *data++ = s->rx_pause; - *data++ = s->rx_fcs_errs; - *data++ = s->rx_symbol_errs; - *data++ = s->rx_short; - *data++ = s->rx_jabber; - *data++ = s->rx_too_long; - *data++ = s->rx_fifo_ovfl; - - *data++ = s->rx_frames_64; - *data++ = s->rx_frames_65_127; - *data++ = s->rx_frames_128_255; - *data++ = s->rx_frames_256_511; - *data++ = s->rx_frames_512_1023; - *data++ = s->rx_frames_1024_1518; - *data++ = s->rx_frames_1519_max; - - *data++ = pi->phy.fifo_errors; - - *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TSO); - *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANEX); - *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANINS); - *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TX_CSUM); - *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_RX_CSUM_GOOD); - *data++ = 0; - *data++ = 0; - *data++ = 0; - *data++ = s->rx_cong_drops; - - *data++ = s->num_toggled; - *data++ = s->num_resets; - - *data++ = s->link_faults; -} - -static inline void reg_block_dump(struct adapter *ap, void *buf, - unsigned int start, unsigned int end) -{ - u32 *p = buf + start; - - for (; start <= end; start += sizeof(u32)) - *p++ = t3_read_reg(ap, start); -} - -static void get_regs(struct net_device *dev, struct ethtool_regs *regs, - void *buf) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *ap = pi->adapter; - - /* - * Version scheme: - * bits 0..9: chip version - * bits 10..15: chip revision - * bit 31: set for PCIe cards - */ - regs->version = 3 | (ap->params.rev << 10) | (is_pcie(ap) << 31); - - /* - * We skip the MAC statistics registers because they are clear-on-read. - * Also reading multi-register stats would need to synchronize with the - * periodic mac stats accumulation. Hard to justify the complexity. - */ - memset(buf, 0, T3_REGMAP_SIZE); - reg_block_dump(ap, buf, 0, A_SG_RSPQ_CREDIT_RETURN); - reg_block_dump(ap, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT); - reg_block_dump(ap, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE); - reg_block_dump(ap, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA); - reg_block_dump(ap, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3); - reg_block_dump(ap, buf, A_XGM_SERDES_STATUS0, - XGM_REG(A_XGM_SERDES_STAT3, 1)); - reg_block_dump(ap, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1), - XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1)); -} - -static int restart_autoneg(struct net_device *dev) -{ - struct port_info *p = netdev_priv(dev); - - if (!netif_running(dev)) - return -EAGAIN; - if (p->link_config.autoneg != AUTONEG_ENABLE) - return -EINVAL; - p->phy.ops->autoneg_restart(&p->phy); - return 0; -} - -static int set_phys_id(struct net_device *dev, - enum ethtool_phys_id_state state) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - - switch (state) { - case ETHTOOL_ID_ACTIVE: - return 1; /* cycle on/off once per second */ - - case ETHTOOL_ID_OFF: - t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, 0); - break; - - case ETHTOOL_ID_ON: - case ETHTOOL_ID_INACTIVE: - t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, - F_GPIO0_OUT_VAL); - } - - return 0; -} - -static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct port_info *p = netdev_priv(dev); - - cmd->supported = p->link_config.supported; - cmd->advertising = p->link_config.advertising; - - if (netif_carrier_ok(dev)) { - ethtool_cmd_speed_set(cmd, p->link_config.speed); - cmd->duplex = p->link_config.duplex; - } else { - ethtool_cmd_speed_set(cmd, -1); - cmd->duplex = -1; - } - - cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE; - cmd->phy_address = p->phy.mdio.prtad; - cmd->transceiver = XCVR_EXTERNAL; - cmd->autoneg = p->link_config.autoneg; - cmd->maxtxpkt = 0; - cmd->maxrxpkt = 0; - return 0; -} - -static int speed_duplex_to_caps(int speed, int duplex) -{ - int cap = 0; - - switch (speed) { - case SPEED_10: - if (duplex == DUPLEX_FULL) - cap = SUPPORTED_10baseT_Full; - else - cap = SUPPORTED_10baseT_Half; - break; - case SPEED_100: - if (duplex == DUPLEX_FULL) - cap = SUPPORTED_100baseT_Full; - else - cap = SUPPORTED_100baseT_Half; - break; - case SPEED_1000: - if (duplex == DUPLEX_FULL) - cap = SUPPORTED_1000baseT_Full; - else - cap = SUPPORTED_1000baseT_Half; - break; - case SPEED_10000: - if (duplex == DUPLEX_FULL) - cap = SUPPORTED_10000baseT_Full; - } - return cap; -} - -#define ADVERTISED_MASK (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \ - ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \ - ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | \ - ADVERTISED_10000baseT_Full) - -static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct port_info *p = netdev_priv(dev); - struct link_config *lc = &p->link_config; - - if (!(lc->supported & SUPPORTED_Autoneg)) { - /* - * PHY offers a single speed/duplex. See if that's what's - * being requested. - */ - if (cmd->autoneg == AUTONEG_DISABLE) { - u32 speed = ethtool_cmd_speed(cmd); - int cap = speed_duplex_to_caps(speed, cmd->duplex); - if (lc->supported & cap) - return 0; - } - return -EINVAL; - } - - if (cmd->autoneg == AUTONEG_DISABLE) { - u32 speed = ethtool_cmd_speed(cmd); - int cap = speed_duplex_to_caps(speed, cmd->duplex); - - if (!(lc->supported & cap) || (speed == SPEED_1000)) - return -EINVAL; - lc->requested_speed = speed; - lc->requested_duplex = cmd->duplex; - lc->advertising = 0; - } else { - cmd->advertising &= ADVERTISED_MASK; - cmd->advertising &= lc->supported; - if (!cmd->advertising) - return -EINVAL; - lc->requested_speed = SPEED_INVALID; - lc->requested_duplex = DUPLEX_INVALID; - lc->advertising = cmd->advertising | ADVERTISED_Autoneg; - } - lc->autoneg = cmd->autoneg; - if (netif_running(dev)) - t3_link_start(&p->phy, &p->mac, lc); - return 0; -} - -static void get_pauseparam(struct net_device *dev, - struct ethtool_pauseparam *epause) -{ - struct port_info *p = netdev_priv(dev); - - epause->autoneg = (p->link_config.requested_fc & PAUSE_AUTONEG) != 0; - epause->rx_pause = (p->link_config.fc & PAUSE_RX) != 0; - epause->tx_pause = (p->link_config.fc & PAUSE_TX) != 0; -} - -static int set_pauseparam(struct net_device *dev, - struct ethtool_pauseparam *epause) -{ - struct port_info *p = netdev_priv(dev); - struct link_config *lc = &p->link_config; - - if (epause->autoneg == AUTONEG_DISABLE) - lc->requested_fc = 0; - else if (lc->supported & SUPPORTED_Autoneg) - lc->requested_fc = PAUSE_AUTONEG; - else - return -EINVAL; - - if (epause->rx_pause) - lc->requested_fc |= PAUSE_RX; - if (epause->tx_pause) - lc->requested_fc |= PAUSE_TX; - if (lc->autoneg == AUTONEG_ENABLE) { - if (netif_running(dev)) - t3_link_start(&p->phy, &p->mac, lc); - } else { - lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); - if (netif_running(dev)) - t3_mac_set_speed_duplex_fc(&p->mac, -1, -1, lc->fc); - } - return 0; -} - -static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - const struct qset_params *q = &adapter->params.sge.qset[pi->first_qset]; - - e->rx_max_pending = MAX_RX_BUFFERS; - e->rx_mini_max_pending = 0; - e->rx_jumbo_max_pending = MAX_RX_JUMBO_BUFFERS; - e->tx_max_pending = MAX_TXQ_ENTRIES; - - e->rx_pending = q->fl_size; - e->rx_mini_pending = q->rspq_size; - e->rx_jumbo_pending = q->jumbo_size; - e->tx_pending = q->txq_size[0]; -} - -static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - struct qset_params *q; - int i; - - if (e->rx_pending > MAX_RX_BUFFERS || - e->rx_jumbo_pending > MAX_RX_JUMBO_BUFFERS || - e->tx_pending > MAX_TXQ_ENTRIES || - e->rx_mini_pending > MAX_RSPQ_ENTRIES || - e->rx_mini_pending < MIN_RSPQ_ENTRIES || - e->rx_pending < MIN_FL_ENTRIES || - e->rx_jumbo_pending < MIN_FL_ENTRIES || - e->tx_pending < adapter->params.nports * MIN_TXQ_ENTRIES) - return -EINVAL; - - if (adapter->flags & FULL_INIT_DONE) - return -EBUSY; - - q = &adapter->params.sge.qset[pi->first_qset]; - for (i = 0; i < pi->nqsets; ++i, ++q) { - q->rspq_size = e->rx_mini_pending; - q->fl_size = e->rx_pending; - q->jumbo_size = e->rx_jumbo_pending; - q->txq_size[0] = e->tx_pending; - q->txq_size[1] = e->tx_pending; - q->txq_size[2] = e->tx_pending; - } - return 0; -} - -static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - struct qset_params *qsp; - struct sge_qset *qs; - int i; - - if (c->rx_coalesce_usecs * 10 > M_NEWTIMER) - return -EINVAL; - - for (i = 0; i < pi->nqsets; i++) { - qsp = &adapter->params.sge.qset[i]; - qs = &adapter->sge.qs[i]; - qsp->coalesce_usecs = c->rx_coalesce_usecs; - t3_update_qset_coalesce(qs, qsp); - } - - return 0; -} - -static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - struct qset_params *q = adapter->params.sge.qset; - - c->rx_coalesce_usecs = q->coalesce_usecs; - return 0; -} - -static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e, - u8 * data) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - int i, err = 0; - - u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - e->magic = EEPROM_MAGIC; - for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4) - err = t3_seeprom_read(adapter, i, (__le32 *) & buf[i]); - - if (!err) - memcpy(data, buf + e->offset, e->len); - kfree(buf); - return err; -} - -static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, - u8 * data) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - u32 aligned_offset, aligned_len; - __le32 *p; - u8 *buf; - int err; - - if (eeprom->magic != EEPROM_MAGIC) - return -EINVAL; - - aligned_offset = eeprom->offset & ~3; - aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3; - - if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) { - buf = kmalloc(aligned_len, GFP_KERNEL); - if (!buf) - return -ENOMEM; - err = t3_seeprom_read(adapter, aligned_offset, (__le32 *) buf); - if (!err && aligned_len > 4) - err = t3_seeprom_read(adapter, - aligned_offset + aligned_len - 4, - (__le32 *) & buf[aligned_len - 4]); - if (err) - goto out; - memcpy(buf + (eeprom->offset & 3), data, eeprom->len); - } else - buf = data; - - err = t3_seeprom_wp(adapter, 0); - if (err) - goto out; - - for (p = (__le32 *) 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) - kfree(buf); - return err; -} - -static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) -{ - wol->supported = 0; - wol->wolopts = 0; - memset(&wol->sopass, 0, sizeof(wol->sopass)); -} - -static const struct ethtool_ops cxgb_ethtool_ops = { - .get_settings = get_settings, - .set_settings = set_settings, - .get_drvinfo = get_drvinfo, - .get_msglevel = get_msglevel, - .set_msglevel = set_msglevel, - .get_ringparam = get_sge_param, - .set_ringparam = set_sge_param, - .get_coalesce = get_coalesce, - .set_coalesce = set_coalesce, - .get_eeprom_len = get_eeprom_len, - .get_eeprom = get_eeprom, - .set_eeprom = set_eeprom, - .get_pauseparam = get_pauseparam, - .set_pauseparam = set_pauseparam, - .get_link = ethtool_op_get_link, - .get_strings = get_strings, - .set_phys_id = set_phys_id, - .nway_reset = restart_autoneg, - .get_sset_count = get_sset_count, - .get_ethtool_stats = get_stats, - .get_regs_len = get_regs_len, - .get_regs = get_regs, - .get_wol = get_wol, -}; - -static int in_range(int val, int lo, int hi) -{ - return val < 0 || (val <= hi && val >= lo); -} - -static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - u32 cmd; - int ret; - - if (copy_from_user(&cmd, useraddr, sizeof(cmd))) - return -EFAULT; - - switch (cmd) { - case CHELSIO_SET_QSET_PARAMS:{ - int i; - struct qset_params *q; - struct ch_qset_params t; - int q1 = pi->first_qset; - int nqsets = pi->nqsets; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (copy_from_user(&t, useraddr, sizeof(t))) - return -EFAULT; - if (t.qset_idx >= SGE_QSETS) - 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, - MAX_TXQ_ENTRIES) || - !in_range(t.txq_size[1], MIN_TXQ_ENTRIES, - MAX_TXQ_ENTRIES) || - !in_range(t.txq_size[2], MIN_CTRL_TXQ_ENTRIES, - MAX_CTRL_TXQ_ENTRIES) || - !in_range(t.fl_size[0], MIN_FL_ENTRIES, - MAX_RX_BUFFERS) || - !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; - - if ((adapter->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; - - /* Allow setting of any available qset when offload enabled */ - if (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) { - q1 = 0; - for_each_port(adapter, i) { - pi = adap2pinfo(adapter, i); - nqsets += pi->first_qset + pi->nqsets; - } - } - - if (t.qset_idx < q1) - return -EINVAL; - if (t.qset_idx > q1 + nqsets - 1) - return -EINVAL; - - q = &adapter->params.sge.qset[t.qset_idx]; - - if (t.rspq_size >= 0) - q->rspq_size = t.rspq_size; - if (t.fl_size[0] >= 0) - q->fl_size = t.fl_size[0]; - if (t.fl_size[1] >= 0) - q->jumbo_size = t.fl_size[1]; - if (t.txq_size[0] >= 0) - q->txq_size[0] = t.txq_size[0]; - if (t.txq_size[1] >= 0) - q->txq_size[1] = t.txq_size[1]; - if (t.txq_size[2] >= 0) - q->txq_size[2] = t.txq_size[2]; - if (t.cong_thres >= 0) - q->cong_thres = t.cong_thres; - if (t.intr_lat >= 0) { - struct sge_qset *qs = - &adapter->sge.qs[t.qset_idx]; - - q->coalesce_usecs = t.intr_lat; - t3_update_qset_coalesce(qs, q); - } - if (t.polling >= 0) { - if (adapter->flags & USING_MSIX) - q->polling = t.polling; - else { - /* No polling with INTx for T3A */ - if (adapter->params.rev == 0 && - !(adapter->flags & USING_MSI)) - t.polling = 0; - - for (i = 0; i < SGE_QSETS; i++) { - q = &adapter->params.sge. - qset[i]; - q->polling = t.polling; - } - } - } - - if (t.lro >= 0) { - if (t.lro) - dev->wanted_features |= NETIF_F_GRO; - else - dev->wanted_features &= ~NETIF_F_GRO; - netdev_update_features(dev); - } - - break; - } - case CHELSIO_GET_QSET_PARAMS:{ - struct qset_params *q; - struct ch_qset_params t; - int q1 = pi->first_qset; - int nqsets = pi->nqsets; - int i; - - if (copy_from_user(&t, useraddr, sizeof(t))) - return -EFAULT; - - /* Display qsets for all ports when offload enabled */ - if (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) { - q1 = 0; - for_each_port(adapter, i) { - pi = adap2pinfo(adapter, i); - nqsets = pi->first_qset + pi->nqsets; - } - } - - if (t.qset_idx >= nqsets) - return -EINVAL; - - q = &adapter->params.sge.qset[q1 + t.qset_idx]; - t.rspq_size = q->rspq_size; - t.txq_size[0] = q->txq_size[0]; - t.txq_size[1] = q->txq_size[1]; - t.txq_size[2] = q->txq_size[2]; - t.fl_size[0] = q->fl_size; - t.fl_size[1] = q->jumbo_size; - t.polling = q->polling; - t.lro = !!(dev->features & NETIF_F_GRO); - t.intr_lat = q->coalesce_usecs; - t.cong_thres = q->cong_thres; - t.qnum = q1; - - if (adapter->flags & USING_MSIX) - t.vector = adapter->msix_info[q1 + t.qset_idx + 1].vec; - else - t.vector = adapter->pdev->irq; - - if (copy_to_user(useraddr, &t, sizeof(t))) - return -EFAULT; - break; - } - case CHELSIO_SET_QSET_NUM:{ - struct ch_reg edata; - unsigned int i, first_qset = 0, other_qsets = 0; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (adapter->flags & FULL_INIT_DONE) - return -EBUSY; - if (copy_from_user(&edata, useraddr, sizeof(edata))) - return -EFAULT; - if (edata.val < 1 || - (edata.val > 1 && !(adapter->flags & USING_MSIX))) - return -EINVAL; - - for_each_port(adapter, i) - if (adapter->port[i] && adapter->port[i] != dev) - other_qsets += adap2pinfo(adapter, i)->nqsets; - - if (edata.val + other_qsets > SGE_QSETS) - return -EINVAL; - - pi->nqsets = edata.val; - - for_each_port(adapter, i) - if (adapter->port[i]) { - pi = adap2pinfo(adapter, i); - pi->first_qset = first_qset; - first_qset += pi->nqsets; - } - break; - } - case CHELSIO_GET_QSET_NUM:{ - struct ch_reg edata; - - memset(&edata, 0, sizeof(struct ch_reg)); - - edata.cmd = CHELSIO_GET_QSET_NUM; - edata.val = pi->nqsets; - if (copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; - break; - } - case CHELSIO_LOAD_FW:{ - u8 *fw_data; - struct ch_mem_range t; - - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - if (copy_from_user(&t, useraddr, sizeof(t))) - return -EFAULT; - /* Check t.len sanity ? */ - fw_data = memdup_user(useraddr + sizeof(t), t.len); - if (IS_ERR(fw_data)) - return PTR_ERR(fw_data); - - ret = t3_load_fw(adapter, fw_data, t.len); - kfree(fw_data); - if (ret) - return ret; - break; - } - case CHELSIO_SETMTUTAB:{ - struct ch_mtus m; - int i; - - if (!is_offload(adapter)) - return -EOPNOTSUPP; - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (offload_running(adapter)) - return -EBUSY; - if (copy_from_user(&m, useraddr, sizeof(m))) - return -EFAULT; - if (m.nmtus != NMTUS) - return -EINVAL; - if (m.mtus[0] < 81) /* accommodate SACK */ - return -EINVAL; - - /* MTUs must be in ascending order */ - for (i = 1; i < NMTUS; ++i) - if (m.mtus[i] < m.mtus[i - 1]) - return -EINVAL; - - memcpy(adapter->params.mtus, m.mtus, - sizeof(adapter->params.mtus)); - break; - } - case CHELSIO_GET_PM:{ - struct tp_params *p = &adapter->params.tp; - struct ch_pm m = {.cmd = CHELSIO_GET_PM }; - - if (!is_offload(adapter)) - return -EOPNOTSUPP; - m.tx_pg_sz = p->tx_pg_size; - m.tx_num_pg = p->tx_num_pgs; - m.rx_pg_sz = p->rx_pg_size; - m.rx_num_pg = p->rx_num_pgs; - m.pm_total = p->pmtx_size + p->chan_rx_size * p->nchan; - if (copy_to_user(useraddr, &m, sizeof(m))) - return -EFAULT; - break; - } - case CHELSIO_SET_PM:{ - struct ch_pm m; - struct tp_params *p = &adapter->params.tp; - - if (!is_offload(adapter)) - return -EOPNOTSUPP; - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (adapter->flags & FULL_INIT_DONE) - return -EBUSY; - if (copy_from_user(&m, useraddr, sizeof(m))) - return -EFAULT; - if (!is_power_of_2(m.rx_pg_sz) || - !is_power_of_2(m.tx_pg_sz)) - return -EINVAL; /* not power of 2 */ - if (!(m.rx_pg_sz & 0x14000)) - return -EINVAL; /* not 16KB or 64KB */ - if (!(m.tx_pg_sz & 0x1554000)) - return -EINVAL; - if (m.tx_num_pg == -1) - m.tx_num_pg = p->tx_num_pgs; - if (m.rx_num_pg == -1) - m.rx_num_pg = p->rx_num_pgs; - if (m.tx_num_pg % 24 || m.rx_num_pg % 24) - return -EINVAL; - if (m.rx_num_pg * m.rx_pg_sz > p->chan_rx_size || - m.tx_num_pg * m.tx_pg_sz > p->chan_tx_size) - return -EINVAL; - p->rx_pg_size = m.rx_pg_sz; - p->tx_pg_size = m.tx_pg_sz; - p->rx_num_pgs = m.rx_num_pg; - p->tx_num_pgs = m.tx_num_pg; - break; - } - case CHELSIO_GET_MEM:{ - struct ch_mem_range t; - struct mc7 *mem; - u64 buf[32]; - - if (!is_offload(adapter)) - return -EOPNOTSUPP; - if (!(adapter->flags & FULL_INIT_DONE)) - return -EIO; /* need the memory controllers */ - if (copy_from_user(&t, useraddr, sizeof(t))) - return -EFAULT; - if ((t.addr & 7) || (t.len & 7)) - return -EINVAL; - if (t.mem_id == MEM_CM) - mem = &adapter->cm; - else if (t.mem_id == MEM_PMRX) - mem = &adapter->pmrx; - else if (t.mem_id == MEM_PMTX) - mem = &adapter->pmtx; - else - return -EINVAL; - - /* - * Version scheme: - * bits 0..9: chip version - * bits 10..15: chip revision - */ - t.version = 3 | (adapter->params.rev << 10); - if (copy_to_user(useraddr, &t, sizeof(t))) - return -EFAULT; - - /* - * Read 256 bytes at a time as len can be large and we don't - * want to use huge intermediate buffers. - */ - useraddr += sizeof(t); /* advance to start of buffer */ - while (t.len) { - unsigned int chunk = - min_t(unsigned int, t.len, sizeof(buf)); - - ret = - t3_mc7_bd_read(mem, t.addr / 8, chunk / 8, - buf); - if (ret) - return ret; - if (copy_to_user(useraddr, buf, chunk)) - return -EFAULT; - useraddr += chunk; - t.addr += chunk; - t.len -= chunk; - } - break; - } - case CHELSIO_SET_TRACE_FILTER:{ - struct ch_trace t; - const struct trace_params *tp; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (!offload_running(adapter)) - return -EAGAIN; - if (copy_from_user(&t, useraddr, sizeof(t))) - return -EFAULT; - - tp = (const struct trace_params *)&t.sip; - if (t.config_tx) - t3_config_trace_filter(adapter, tp, 0, - t.invert_match, - t.trace_tx); - if (t.config_rx) - t3_config_trace_filter(adapter, tp, 1, - t.invert_match, - t.trace_rx); - break; - } - default: - return -EOPNOTSUPP; - } - return 0; -} - -static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd) -{ - struct mii_ioctl_data *data = if_mii(req); - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - - switch (cmd) { - case SIOCGMIIREG: - case SIOCSMIIREG: - /* Convert phy_id from older PRTAD/DEVAD format */ - if (is_10G(adapter) && - !mdio_phy_id_is_c45(data->phy_id) && - (data->phy_id & 0x1f00) && - !(data->phy_id & 0xe0e0)) - data->phy_id = mdio_phy_id_c45(data->phy_id >> 8, - data->phy_id & 0x1f); - /* FALLTHRU */ - case SIOCGMIIPHY: - return mdio_mii_ioctl(&pi->phy.mdio, data, cmd); - case SIOCCHIOCTL: - return cxgb_extension_ioctl(dev, req->ifr_data); - default: - return -EOPNOTSUPP; - } -} - -static int cxgb_change_mtu(struct net_device *dev, int new_mtu) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - int ret; - - if (new_mtu < 81) /* accommodate SACK */ - return -EINVAL; - if ((ret = t3_mac_set_mtu(&pi->mac, new_mtu))) - return ret; - dev->mtu = new_mtu; - init_port_mtus(adapter); - if (adapter->params.rev == 0 && offload_running(adapter)) - t3_load_mtus(adapter, adapter->params.mtus, - adapter->params.a_wnd, adapter->params.b_wnd, - adapter->port[0]->mtu); - return 0; -} - -static int cxgb_set_mac_addr(struct net_device *dev, void *p) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - struct sockaddr *addr = p; - - if (!is_valid_ether_addr(addr->sa_data)) - return -EINVAL; - - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - t3_mac_set_address(&pi->mac, LAN_MAC_IDX, dev->dev_addr); - if (offload_running(adapter)) - write_smt_entry(adapter, pi->port_id); - return 0; -} - -/** - * t3_synchronize_rx - wait for current Rx processing on a port to complete - * @adap: the adapter - * @p: the port - * - * Ensures that current Rx processing on any of the queues associated with - * the given port completes before returning. We do this by acquiring and - * releasing the locks of the response queues associated with the port. - */ -static void t3_synchronize_rx(struct adapter *adap, const struct port_info *p) -{ - int i; - - for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) { - struct sge_rspq *q = &adap->sge.qs[i].rspq; - - spin_lock_irq(&q->lock); - spin_unlock_irq(&q->lock); - } -} - -static void cxgb_vlan_mode(struct net_device *dev, u32 features) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - - if (adapter->params.rev > 0) { - t3_set_vlan_accel(adapter, 1 << pi->port_id, - features & NETIF_F_HW_VLAN_RX); - } else { - /* single control for all ports */ - unsigned int i, have_vlans = features & NETIF_F_HW_VLAN_RX; - - for_each_port(adapter, i) - have_vlans |= - adapter->port[i]->features & NETIF_F_HW_VLAN_RX; - - t3_set_vlan_accel(adapter, 1, have_vlans); - } - t3_synchronize_rx(adapter, pi); -} - -static u32 cxgb_fix_features(struct net_device *dev, u32 features) -{ - /* - * Since there is no support for separate rx/tx vlan accel - * enable/disable make sure tx flag is always in same state as rx. - */ - if (features & NETIF_F_HW_VLAN_RX) - features |= NETIF_F_HW_VLAN_TX; - else - features &= ~NETIF_F_HW_VLAN_TX; - - return features; -} - -static int cxgb_set_features(struct net_device *dev, u32 features) -{ - u32 changed = dev->features ^ features; - - if (changed & NETIF_F_HW_VLAN_RX) - cxgb_vlan_mode(dev, features); - - return 0; -} - -#ifdef CONFIG_NET_POLL_CONTROLLER -static void cxgb_netpoll(struct net_device *dev) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - int qidx; - - for (qidx = pi->first_qset; qidx < pi->first_qset + pi->nqsets; qidx++) { - struct sge_qset *qs = &adapter->sge.qs[qidx]; - void *source; - - if (adapter->flags & USING_MSIX) - source = qs; - else - source = adapter; - - t3_intr_handler(adapter, qs->rspq.polling) (0, source); - } -} -#endif - -/* - * Periodic accumulation of MAC statistics. - */ -static void mac_stats_update(struct adapter *adapter) -{ - int i; - - for_each_port(adapter, i) { - struct net_device *dev = adapter->port[i]; - struct port_info *p = netdev_priv(dev); - - if (netif_running(dev)) { - spin_lock(&adapter->stats_lock); - t3_mac_update_stats(&p->mac); - spin_unlock(&adapter->stats_lock); - } - } -} - -static void check_link_status(struct adapter *adapter) -{ - int i; - - for_each_port(adapter, i) { - struct net_device *dev = adapter->port[i]; - struct port_info *p = netdev_priv(dev); - int link_fault; - - spin_lock_irq(&adapter->work_lock); - link_fault = p->link_fault; - spin_unlock_irq(&adapter->work_lock); - - if (link_fault) { - t3_link_fault(adapter, i); - continue; - } - - if (!(p->phy.caps & SUPPORTED_IRQ) && netif_running(dev)) { - t3_xgm_intr_disable(adapter, i); - t3_read_reg(adapter, A_XGM_INT_STATUS + p->mac.offset); - - t3_link_changed(adapter, i); - t3_xgm_intr_enable(adapter, i); - } - } -} - -static void check_t3b2_mac(struct adapter *adapter) -{ - int i; - - if (!rtnl_trylock()) /* synchronize with ifdown */ - return; - - for_each_port(adapter, i) { - struct net_device *dev = adapter->port[i]; - struct port_info *p = netdev_priv(dev); - int status; - - if (!netif_running(dev)) - continue; - - status = 0; - if (netif_running(dev) && netif_carrier_ok(dev)) - status = t3b2_mac_watchdog_task(&p->mac); - if (status == 1) - p->mac.stats.num_toggled++; - else if (status == 2) { - struct cmac *mac = &p->mac; - - t3_mac_set_mtu(mac, dev->mtu); - t3_mac_set_address(mac, LAN_MAC_IDX, dev->dev_addr); - cxgb_set_rxmode(dev); - 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_id); - p->mac.stats.num_resets++; - } - } - rtnl_unlock(); -} - - -static void t3_adap_check_task(struct work_struct *work) -{ - struct adapter *adapter = container_of(work, struct adapter, - adap_check_task.work); - const struct adapter_params *p = &adapter->params; - int port; - unsigned int v, status, reset; - - adapter->check_task_cnt++; - - check_link_status(adapter); - - /* Accumulate MAC stats if needed */ - if (!p->linkpoll_period || - (adapter->check_task_cnt * p->linkpoll_period) / 10 >= - p->stats_update_period) { - mac_stats_update(adapter); - adapter->check_task_cnt = 0; - } - - if (p->rev == T3_REV_B2) - check_t3b2_mac(adapter); - - /* - * Scan the XGMAC's to check for various conditions which we want to - * monitor in a periodic polling manner rather than via an interrupt - * condition. This is used for conditions which would otherwise flood - * the system with interrupts and we only really need to know that the - * conditions are "happening" ... For each condition we count the - * detection of the condition and reset it for the next polling loop. - */ - for_each_port(adapter, port) { - struct cmac *mac = &adap2pinfo(adapter, port)->mac; - u32 cause; - - cause = t3_read_reg(adapter, A_XGM_INT_CAUSE + mac->offset); - reset = 0; - if (cause & F_RXFIFO_OVERFLOW) { - mac->stats.rx_fifo_ovfl++; - reset |= F_RXFIFO_OVERFLOW; - } - - t3_write_reg(adapter, A_XGM_INT_CAUSE + mac->offset, reset); - } - - /* - * We do the same as above for FL_EMPTY interrupts. - */ - status = t3_read_reg(adapter, A_SG_INT_CAUSE); - reset = 0; - - if (status & F_FLEMPTY) { - struct sge_qset *qs = &adapter->sge.qs[0]; - int i = 0; - - reset |= F_FLEMPTY; - - v = (t3_read_reg(adapter, A_SG_RSPQ_FL_STATUS) >> S_FL0EMPTY) & - 0xffff; - - while (v) { - qs->fl[i].empty += (v & 1); - if (i) - qs++; - i ^= 1; - v >>= 1; - } - } - - t3_write_reg(adapter, A_SG_INT_CAUSE, reset); - - /* Schedule the next check update if any port is active. */ - spin_lock_irq(&adapter->work_lock); - if (adapter->open_device_map & PORT_MASK) - schedule_chk_task(adapter); - spin_unlock_irq(&adapter->work_lock); -} - -static void db_full_task(struct work_struct *work) -{ - struct adapter *adapter = container_of(work, struct adapter, - db_full_task); - - cxgb3_event_notify(&adapter->tdev, OFFLOAD_DB_FULL, 0); -} - -static void db_empty_task(struct work_struct *work) -{ - struct adapter *adapter = container_of(work, struct adapter, - db_empty_task); - - cxgb3_event_notify(&adapter->tdev, OFFLOAD_DB_EMPTY, 0); -} - -static void db_drop_task(struct work_struct *work) -{ - struct adapter *adapter = container_of(work, struct adapter, - db_drop_task); - unsigned long delay = 1000; - unsigned short r; - - cxgb3_event_notify(&adapter->tdev, OFFLOAD_DB_DROP, 0); - - /* - * Sleep a while before ringing the driver qset dbs. - * The delay is between 1000-2023 usecs. - */ - get_random_bytes(&r, 2); - delay += r & 1023; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(usecs_to_jiffies(delay)); - ring_dbs(adapter); -} - -/* - * Processes external (PHY) interrupts in process context. - */ -static void ext_intr_task(struct work_struct *work) -{ - struct adapter *adapter = container_of(work, struct adapter, - ext_intr_handler_task); - int i; - - /* Disable link fault interrupts */ - for_each_port(adapter, i) { - struct net_device *dev = adapter->port[i]; - struct port_info *p = netdev_priv(dev); - - t3_xgm_intr_disable(adapter, i); - t3_read_reg(adapter, A_XGM_INT_STATUS + p->mac.offset); - } - - /* Re-enable link fault interrupts */ - t3_phy_intr_handler(adapter); - - for_each_port(adapter, i) - t3_xgm_intr_enable(adapter, i); - - /* Now reenable external interrupts */ - spin_lock_irq(&adapter->work_lock); - if (adapter->slow_intr_mask) { - adapter->slow_intr_mask |= F_T3DBG; - t3_write_reg(adapter, A_PL_INT_CAUSE0, F_T3DBG); - t3_write_reg(adapter, A_PL_INT_ENABLE0, - adapter->slow_intr_mask); - } - spin_unlock_irq(&adapter->work_lock); -} - -/* - * Interrupt-context handler for external (PHY) interrupts. - */ -void t3_os_ext_intr_handler(struct adapter *adapter) -{ - /* - * Schedule a task to handle external interrupts as they may be slow - * and we use a mutex to protect MDIO registers. We disable PHY - * interrupts in the meantime and let the task reenable them when - * it's done. - */ - spin_lock(&adapter->work_lock); - if (adapter->slow_intr_mask) { - adapter->slow_intr_mask &= ~F_T3DBG; - t3_write_reg(adapter, A_PL_INT_ENABLE0, - adapter->slow_intr_mask); - queue_work(cxgb3_wq, &adapter->ext_intr_handler_task); - } - spin_unlock(&adapter->work_lock); -} - -void t3_os_link_fault_handler(struct adapter *adapter, int port_id) -{ - struct net_device *netdev = adapter->port[port_id]; - struct port_info *pi = netdev_priv(netdev); - - spin_lock(&adapter->work_lock); - pi->link_fault = 1; - spin_unlock(&adapter->work_lock); -} - -static int t3_adapter_error(struct adapter *adapter, int reset, int on_wq) -{ - int i, ret = 0; - - if (is_offload(adapter) && - test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) { - cxgb3_event_notify(&adapter->tdev, OFFLOAD_STATUS_DOWN, 0); - offload_close(&adapter->tdev); - } - - /* Stop all ports */ - for_each_port(adapter, i) { - struct net_device *netdev = adapter->port[i]; - - if (netif_running(netdev)) - __cxgb_close(netdev, on_wq); - } - - /* Stop SGE timers */ - t3_stop_sge_timers(adapter); - - adapter->flags &= ~FULL_INIT_DONE; - - if (reset) - ret = t3_reset_adapter(adapter); - - pci_disable_device(adapter->pdev); - - return ret; -} - -static int t3_reenable_adapter(struct adapter *adapter) -{ - if (pci_enable_device(adapter->pdev)) { - dev_err(&adapter->pdev->dev, - "Cannot re-enable PCI device after reset.\n"); - goto err; - } - pci_set_master(adapter->pdev); - pci_restore_state(adapter->pdev); - pci_save_state(adapter->pdev); - - /* Free sge resources */ - t3_free_sge_resources(adapter); - - if (t3_replay_prep_adapter(adapter)) - goto err; - - return 0; -err: - return -1; -} - -static void t3_resume_ports(struct adapter *adapter) -{ - int i; - - /* Restart the ports */ - for_each_port(adapter, i) { - struct net_device *netdev = adapter->port[i]; - - if (netif_running(netdev)) { - if (cxgb_open(netdev)) { - dev_err(&adapter->pdev->dev, - "can't bring device back up" - " after reset\n"); - continue; - } - } - } - - if (is_offload(adapter) && !ofld_disable) - cxgb3_event_notify(&adapter->tdev, OFFLOAD_STATUS_UP, 0); -} - -/* - * processes a fatal error. - * Bring the ports down, reset the chip, bring the ports back up. - */ -static void fatal_error_task(struct work_struct *work) -{ - struct adapter *adapter = container_of(work, struct adapter, - fatal_error_handler_task); - int err = 0; - - rtnl_lock(); - err = t3_adapter_error(adapter, 1, 1); - if (!err) - err = t3_reenable_adapter(adapter); - if (!err) - t3_resume_ports(adapter); - - CH_ALERT(adapter, "adapter reset %s\n", err ? "failed" : "succeeded"); - rtnl_unlock(); -} - -void t3_fatal_err(struct adapter *adapter) -{ - unsigned int fw_status[4]; - - if (adapter->flags & FULL_INIT_DONE) { - t3_sge_stop(adapter); - t3_write_reg(adapter, A_XGM_TX_CTRL, 0); - t3_write_reg(adapter, A_XGM_RX_CTRL, 0); - t3_write_reg(adapter, XGM_REG(A_XGM_TX_CTRL, 1), 0); - t3_write_reg(adapter, XGM_REG(A_XGM_RX_CTRL, 1), 0); - - spin_lock(&adapter->work_lock); - t3_intr_disable(adapter); - queue_work(cxgb3_wq, &adapter->fatal_error_handler_task); - spin_unlock(&adapter->work_lock); - } - CH_ALERT(adapter, "encountered fatal error, operation suspended\n"); - if (!t3_cim_ctl_blk_read(adapter, 0xa0, 4, fw_status)) - CH_ALERT(adapter, "FW status: 0x%x, 0x%x, 0x%x, 0x%x\n", - fw_status[0], fw_status[1], - fw_status[2], fw_status[3]); -} - -/** - * t3_io_error_detected - called when PCI error is detected - * @pdev: Pointer to PCI device - * @state: The current pci connection state - * - * This function is called after a PCI bus error affecting - * this device has been detected. - */ -static pci_ers_result_t t3_io_error_detected(struct pci_dev *pdev, - pci_channel_state_t state) -{ - struct adapter *adapter = pci_get_drvdata(pdev); - - if (state == pci_channel_io_perm_failure) - return PCI_ERS_RESULT_DISCONNECT; - - t3_adapter_error(adapter, 0, 0); - - /* Request a slot reset. */ - return PCI_ERS_RESULT_NEED_RESET; -} - -/** - * t3_io_slot_reset - called after the pci bus has been reset. - * @pdev: Pointer to PCI device - * - * Restart the card from scratch, as if from a cold-boot. - */ -static pci_ers_result_t t3_io_slot_reset(struct pci_dev *pdev) -{ - struct adapter *adapter = pci_get_drvdata(pdev); - - if (!t3_reenable_adapter(adapter)) - return PCI_ERS_RESULT_RECOVERED; - - return PCI_ERS_RESULT_DISCONNECT; -} - -/** - * t3_io_resume - called when traffic can start flowing again. - * @pdev: Pointer to PCI device - * - * This callback is called when the error recovery driver tells us that - * its OK to resume normal operation. - */ -static void t3_io_resume(struct pci_dev *pdev) -{ - struct adapter *adapter = pci_get_drvdata(pdev); - - CH_ALERT(adapter, "adapter recovering, PEX ERR 0x%x\n", - t3_read_reg(adapter, A_PCIE_PEX_ERR)); - - t3_resume_ports(adapter); -} - -static struct pci_error_handlers t3_err_handler = { - .error_detected = t3_io_error_detected, - .slot_reset = t3_io_slot_reset, - .resume = t3_io_resume, -}; - -/* - * Set the number of qsets based on the number of CPUs and the number of ports, - * not to exceed the number of available qsets, assuming there are enough qsets - * per port in HW. - */ -static void set_nqsets(struct adapter *adap) -{ - int i, j = 0; - int num_cpus = num_online_cpus(); - int hwports = adap->params.nports; - int nqsets = adap->msix_nvectors - 1; - - if (adap->params.rev > 0 && adap->flags & USING_MSIX) { - if (hwports == 2 && - (hwports * nqsets > SGE_QSETS || - num_cpus >= nqsets / hwports)) - nqsets /= hwports; - if (nqsets > num_cpus) - nqsets = num_cpus; - if (nqsets < 1 || hwports == 4) - nqsets = 1; - } else - nqsets = 1; - - for_each_port(adap, i) { - struct port_info *pi = adap2pinfo(adap, i); - - pi->first_qset = j; - pi->nqsets = nqsets; - j = pi->first_qset + nqsets; - - dev_info(&adap->pdev->dev, - "Port %d using %d queue sets.\n", i, nqsets); - } -} - -static int __devinit cxgb_enable_msix(struct adapter *adap) -{ - struct msix_entry entries[SGE_QSETS + 1]; - int vectors; - int i, err; - - vectors = ARRAY_SIZE(entries); - for (i = 0; i < vectors; ++i) - entries[i].entry = i; - - while ((err = pci_enable_msix(adap->pdev, entries, vectors)) > 0) - vectors = err; - - if (err < 0) - pci_disable_msix(adap->pdev); - - if (!err && vectors < (adap->params.nports + 1)) { - pci_disable_msix(adap->pdev); - err = -1; - } - - if (!err) { - for (i = 0; i < vectors; ++i) - adap->msix_info[i].vec = entries[i].vector; - adap->msix_nvectors = vectors; - } - - return err; -} - -static void __devinit print_port_info(struct adapter *adap, - const struct adapter_info *ai) -{ - static const char *pci_variant[] = { - "PCI", "PCI-X", "PCI-X ECC", "PCI-X 266", "PCI Express" - }; - - int i; - char buf[80]; - - if (is_pcie(adap)) - snprintf(buf, sizeof(buf), "%s x%d", - pci_variant[adap->params.pci.variant], - adap->params.pci.width); - else - snprintf(buf, sizeof(buf), "%s %dMHz/%d-bit", - pci_variant[adap->params.pci.variant], - adap->params.pci.speed, adap->params.pci.width); - - for_each_port(adap, i) { - struct net_device *dev = adap->port[i]; - const struct port_info *pi = netdev_priv(dev); - - if (!test_bit(i, &adap->registered_device_map)) - continue; - printk(KERN_INFO "%s: %s %s %sNIC (rev %d) %s%s\n", - dev->name, ai->desc, pi->phy.desc, - is_offload(adap) ? "R" : "", adap->params.rev, buf, - (adap->flags & USING_MSIX) ? " MSI-X" : - (adap->flags & USING_MSI) ? " MSI" : ""); - if (adap->name == dev->name && adap->params.vpd.mclk) - printk(KERN_INFO - "%s: %uMB CM, %uMB PMTX, %uMB PMRX, S/N: %s\n", - adap->name, t3_mc7_size(&adap->cm) >> 20, - t3_mc7_size(&adap->pmtx) >> 20, - t3_mc7_size(&adap->pmrx) >> 20, - adap->params.vpd.sn); - } -} - -static const struct net_device_ops cxgb_netdev_ops = { - .ndo_open = cxgb_open, - .ndo_stop = cxgb_close, - .ndo_start_xmit = t3_eth_xmit, - .ndo_get_stats = cxgb_get_stats, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_multicast_list = cxgb_set_rxmode, - .ndo_do_ioctl = cxgb_ioctl, - .ndo_change_mtu = cxgb_change_mtu, - .ndo_set_mac_address = cxgb_set_mac_addr, - .ndo_fix_features = cxgb_fix_features, - .ndo_set_features = cxgb_set_features, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = cxgb_netpoll, -#endif -}; - -static void __devinit cxgb3_init_iscsi_mac(struct net_device *dev) -{ - struct port_info *pi = netdev_priv(dev); - - memcpy(pi->iscsic.mac_addr, dev->dev_addr, ETH_ALEN); - pi->iscsic.mac_addr[3] |= 0x80; -} - -static int __devinit init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - static int version_printed; - - int i, err, pci_using_dac = 0; - resource_size_t mmio_start, mmio_len; - const struct adapter_info *ai; - struct adapter *adapter = NULL; - struct port_info *pi; - - if (!version_printed) { - printk(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION); - ++version_printed; - } - - if (!cxgb3_wq) { - cxgb3_wq = create_singlethread_workqueue(DRV_NAME); - if (!cxgb3_wq) { - printk(KERN_ERR DRV_NAME - ": cannot initialize work queue\n"); - return -ENOMEM; - } - } - - err = pci_enable_device(pdev); - if (err) { - dev_err(&pdev->dev, "cannot enable PCI device\n"); - goto out; - } - - err = pci_request_regions(pdev, DRV_NAME); - if (err) { - /* Just info, some other driver may have claimed the device. */ - dev_info(&pdev->dev, "cannot obtain PCI resources\n"); - goto out_disable_device; - } - - if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { - pci_using_dac = 1; - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); - if (err) { - dev_err(&pdev->dev, "unable to obtain 64-bit DMA for " - "coherent allocations\n"); - goto out_release_regions; - } - } else if ((err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) != 0) { - dev_err(&pdev->dev, "no usable DMA configuration\n"); - goto out_release_regions; - } - - pci_set_master(pdev); - pci_save_state(pdev); - - mmio_start = pci_resource_start(pdev, 0); - mmio_len = pci_resource_len(pdev, 0); - ai = t3_get_adapter_info(ent->driver_data); - - adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); - if (!adapter) { - err = -ENOMEM; - goto out_release_regions; - } - - adapter->nofail_skb = - alloc_skb(sizeof(struct cpl_set_tcb_field), GFP_KERNEL); - if (!adapter->nofail_skb) { - dev_err(&pdev->dev, "cannot allocate nofail buffer\n"); - err = -ENOMEM; - goto out_free_adapter; - } - - adapter->regs = ioremap_nocache(mmio_start, mmio_len); - if (!adapter->regs) { - dev_err(&pdev->dev, "cannot map device registers\n"); - err = -ENOMEM; - goto out_free_adapter; - } - - adapter->pdev = pdev; - adapter->name = pci_name(pdev); - adapter->msg_enable = dflt_msg_enable; - adapter->mmio_len = mmio_len; - - mutex_init(&adapter->mdio_lock); - spin_lock_init(&adapter->work_lock); - spin_lock_init(&adapter->stats_lock); - - INIT_LIST_HEAD(&adapter->adapter_list); - INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task); - INIT_WORK(&adapter->fatal_error_handler_task, fatal_error_task); - - INIT_WORK(&adapter->db_full_task, db_full_task); - INIT_WORK(&adapter->db_empty_task, db_empty_task); - INIT_WORK(&adapter->db_drop_task, db_drop_task); - - INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task); - - for (i = 0; i < ai->nports0 + ai->nports1; ++i) { - struct net_device *netdev; - - netdev = alloc_etherdev_mq(sizeof(struct port_info), SGE_QSETS); - if (!netdev) { - err = -ENOMEM; - goto out_free_dev; - } - - SET_NETDEV_DEV(netdev, &pdev->dev); - - adapter->port[i] = netdev; - pi = netdev_priv(netdev); - pi->adapter = adapter; - pi->port_id = i; - netif_carrier_off(netdev); - netdev->irq = pdev->irq; - netdev->mem_start = mmio_start; - netdev->mem_end = mmio_start + mmio_len - 1; - netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | - NETIF_F_TSO | NETIF_F_RXCSUM | NETIF_F_HW_VLAN_RX; - netdev->features |= netdev->hw_features | NETIF_F_HW_VLAN_TX; - if (pci_using_dac) - netdev->features |= NETIF_F_HIGHDMA; - - netdev->netdev_ops = &cxgb_netdev_ops; - SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops); - } - - pci_set_drvdata(pdev, adapter); - if (t3_prep_adapter(adapter, ai, 1) < 0) { - err = -ENODEV; - goto out_free_dev; - } - - /* - * The card is now ready to go. If any errors occur during device - * registration we do not fail the whole card but rather proceed only - * with the ports we manage to register successfully. However we must - * register at least one net device. - */ - for_each_port(adapter, i) { - err = register_netdev(adapter->port[i]); - if (err) - dev_warn(&pdev->dev, - "cannot register net device %s, skipping\n", - adapter->port[i]->name); - else { - /* - * Change the name we use for messages to the name of - * the first successfully registered interface. - */ - if (!adapter->registered_device_map) - adapter->name = adapter->port[i]->name; - - __set_bit(i, &adapter->registered_device_map); - } - } - if (!adapter->registered_device_map) { - dev_err(&pdev->dev, "could not register any net devices\n"); - goto out_free_dev; - } - - for_each_port(adapter, i) - cxgb3_init_iscsi_mac(adapter->port[i]); - - /* Driver's ready. Reflect it on LEDs */ - t3_led_ready(adapter); - - if (is_offload(adapter)) { - __set_bit(OFFLOAD_DEVMAP_BIT, &adapter->registered_device_map); - cxgb3_adapter_ofld(adapter); - } - - /* See what interrupts we'll be using */ - if (msi > 1 && cxgb_enable_msix(adapter) == 0) - adapter->flags |= USING_MSIX; - else if (msi > 0 && pci_enable_msi(pdev) == 0) - adapter->flags |= USING_MSI; - - set_nqsets(adapter); - - err = sysfs_create_group(&adapter->port[0]->dev.kobj, - &cxgb3_attr_group); - - for_each_port(adapter, i) - cxgb_vlan_mode(adapter->port[i], adapter->port[i]->features); - - print_port_info(adapter, ai); - return 0; - -out_free_dev: - iounmap(adapter->regs); - for (i = ai->nports0 + ai->nports1 - 1; i >= 0; --i) - if (adapter->port[i]) - free_netdev(adapter->port[i]); - -out_free_adapter: - kfree(adapter); - -out_release_regions: - pci_release_regions(pdev); -out_disable_device: - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); -out: - return err; -} - -static void __devexit remove_one(struct pci_dev *pdev) -{ - struct adapter *adapter = pci_get_drvdata(pdev); - - if (adapter) { - int i; - - t3_sge_stop(adapter); - sysfs_remove_group(&adapter->port[0]->dev.kobj, - &cxgb3_attr_group); - - if (is_offload(adapter)) { - cxgb3_adapter_unofld(adapter); - if (test_bit(OFFLOAD_DEVMAP_BIT, - &adapter->open_device_map)) - offload_close(&adapter->tdev); - } - - for_each_port(adapter, i) - if (test_bit(i, &adapter->registered_device_map)) - unregister_netdev(adapter->port[i]); - - t3_stop_sge_timers(adapter); - t3_free_sge_resources(adapter); - cxgb_disable_msi(adapter); - - for_each_port(adapter, i) - if (adapter->port[i]) - free_netdev(adapter->port[i]); - - iounmap(adapter->regs); - if (adapter->nofail_skb) - kfree_skb(adapter->nofail_skb); - kfree(adapter); - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - } -} - -static struct pci_driver driver = { - .name = DRV_NAME, - .id_table = cxgb3_pci_tbl, - .probe = init_one, - .remove = __devexit_p(remove_one), - .err_handler = &t3_err_handler, -}; - -static int __init cxgb3_init_module(void) -{ - int ret; - - cxgb3_offload_init(); - - ret = pci_register_driver(&driver); - return ret; -} - -static void __exit cxgb3_cleanup_module(void) -{ - pci_unregister_driver(&driver); - if (cxgb3_wq) - destroy_workqueue(cxgb3_wq); -} - -module_init(cxgb3_init_module); -module_exit(cxgb3_cleanup_module); diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c deleted file mode 100644 index 805076c54f1b..000000000000 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ /dev/null @@ -1,1418 +0,0 @@ -/* - * Copyright (c) 2006-2008 Chelsio, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "common.h" -#include "regs.h" -#include "cxgb3_ioctl.h" -#include "cxgb3_ctl_defs.h" -#include "cxgb3_defs.h" -#include "l2t.h" -#include "firmware_exports.h" -#include "cxgb3_offload.h" - -static LIST_HEAD(client_list); -static LIST_HEAD(ofld_dev_list); -static DEFINE_MUTEX(cxgb3_db_lock); - -static DEFINE_RWLOCK(adapter_list_lock); -static LIST_HEAD(adapter_list); - -static const unsigned int MAX_ATIDS = 64 * 1024; -static const unsigned int ATID_BASE = 0x10000; - -static void cxgb_neigh_update(struct neighbour *neigh); -static void cxgb_redirect(struct dst_entry *old, struct dst_entry *new); - -static inline int offload_activated(struct t3cdev *tdev) -{ - const struct adapter *adapter = tdev2adap(tdev); - - return test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map); -} - -/** - * cxgb3_register_client - register an offload client - * @client: the client - * - * Add the client to the client list, - * and call backs the client for each activated offload device - */ -void cxgb3_register_client(struct cxgb3_client *client) -{ - struct t3cdev *tdev; - - mutex_lock(&cxgb3_db_lock); - list_add_tail(&client->client_list, &client_list); - - if (client->add) { - list_for_each_entry(tdev, &ofld_dev_list, ofld_dev_list) { - if (offload_activated(tdev)) - client->add(tdev); - } - } - mutex_unlock(&cxgb3_db_lock); -} - -EXPORT_SYMBOL(cxgb3_register_client); - -/** - * cxgb3_unregister_client - unregister an offload client - * @client: the client - * - * Remove the client to the client list, - * and call backs the client for each activated offload device. - */ -void cxgb3_unregister_client(struct cxgb3_client *client) -{ - struct t3cdev *tdev; - - mutex_lock(&cxgb3_db_lock); - list_del(&client->client_list); - - if (client->remove) { - list_for_each_entry(tdev, &ofld_dev_list, ofld_dev_list) { - if (offload_activated(tdev)) - client->remove(tdev); - } - } - mutex_unlock(&cxgb3_db_lock); -} - -EXPORT_SYMBOL(cxgb3_unregister_client); - -/** - * cxgb3_add_clients - activate registered clients for an offload device - * @tdev: the offload device - * - * Call backs all registered clients once a offload device is activated - */ -void cxgb3_add_clients(struct t3cdev *tdev) -{ - struct cxgb3_client *client; - - mutex_lock(&cxgb3_db_lock); - list_for_each_entry(client, &client_list, client_list) { - if (client->add) - client->add(tdev); - } - mutex_unlock(&cxgb3_db_lock); -} - -/** - * cxgb3_remove_clients - deactivates registered clients - * for an offload device - * @tdev: the offload device - * - * Call backs all registered clients once a offload device is deactivated - */ -void cxgb3_remove_clients(struct t3cdev *tdev) -{ - struct cxgb3_client *client; - - mutex_lock(&cxgb3_db_lock); - list_for_each_entry(client, &client_list, client_list) { - if (client->remove) - client->remove(tdev); - } - mutex_unlock(&cxgb3_db_lock); -} - -void cxgb3_event_notify(struct t3cdev *tdev, u32 event, u32 port) -{ - struct cxgb3_client *client; - - mutex_lock(&cxgb3_db_lock); - list_for_each_entry(client, &client_list, client_list) { - if (client->event_handler) - client->event_handler(tdev, event, port); - } - mutex_unlock(&cxgb3_db_lock); -} - -static struct net_device *get_iff_from_mac(struct adapter *adapter, - const unsigned char *mac, - unsigned int vlan) -{ - int i; - - for_each_port(adapter, i) { - struct net_device *dev = adapter->port[i]; - - if (!memcmp(dev->dev_addr, mac, ETH_ALEN)) { - if (vlan && vlan != VLAN_VID_MASK) { - rcu_read_lock(); - dev = __vlan_find_dev_deep(dev, vlan); - rcu_read_unlock(); - } else if (netif_is_bond_slave(dev)) { - while (dev->master) - dev = dev->master; - } - return dev; - } - } - return NULL; -} - -static int cxgb_ulp_iscsi_ctl(struct adapter *adapter, unsigned int req, - void *data) -{ - int i; - int ret = 0; - unsigned int val = 0; - struct ulp_iscsi_info *uiip = data; - - switch (req) { - case ULP_ISCSI_GET_PARAMS: - uiip->pdev = adapter->pdev; - uiip->llimit = t3_read_reg(adapter, A_ULPRX_ISCSI_LLIMIT); - uiip->ulimit = t3_read_reg(adapter, A_ULPRX_ISCSI_ULIMIT); - uiip->tagmask = t3_read_reg(adapter, A_ULPRX_ISCSI_TAGMASK); - - val = t3_read_reg(adapter, A_ULPRX_ISCSI_PSZ); - for (i = 0; i < 4; i++, val >>= 8) - uiip->pgsz_factor[i] = val & 0xFF; - - val = t3_read_reg(adapter, A_TP_PARA_REG7); - uiip->max_txsz = - uiip->max_rxsz = min((val >> S_PMMAXXFERLEN0)&M_PMMAXXFERLEN0, - (val >> S_PMMAXXFERLEN1)&M_PMMAXXFERLEN1); - /* - * On tx, the iscsi pdu has to be <= tx page size and has to - * fit into the Tx PM FIFO. - */ - val = min(adapter->params.tp.tx_pg_size, - t3_read_reg(adapter, A_PM1_TX_CFG) >> 17); - uiip->max_txsz = min(val, uiip->max_txsz); - - /* set MaxRxData to 16224 */ - val = t3_read_reg(adapter, A_TP_PARA_REG2); - if ((val >> S_MAXRXDATA) != 0x3f60) { - val &= (M_RXCOALESCESIZE << S_RXCOALESCESIZE); - val |= V_MAXRXDATA(0x3f60); - printk(KERN_INFO - "%s, iscsi set MaxRxData to 16224 (0x%x).\n", - adapter->name, val); - t3_write_reg(adapter, A_TP_PARA_REG2, val); - } - - /* - * on rx, the iscsi pdu has to be < rx page size and the - * the max rx data length programmed in TP - */ - val = min(adapter->params.tp.rx_pg_size, - ((t3_read_reg(adapter, A_TP_PARA_REG2)) >> - S_MAXRXDATA) & M_MAXRXDATA); - uiip->max_rxsz = min(val, uiip->max_rxsz); - break; - case ULP_ISCSI_SET_PARAMS: - t3_write_reg(adapter, A_ULPRX_ISCSI_TAGMASK, uiip->tagmask); - /* program the ddp page sizes */ - for (i = 0; i < 4; i++) - val |= (uiip->pgsz_factor[i] & 0xF) << (8 * i); - if (val && (val != t3_read_reg(adapter, A_ULPRX_ISCSI_PSZ))) { - printk(KERN_INFO - "%s, setting iscsi pgsz 0x%x, %u,%u,%u,%u.\n", - adapter->name, val, uiip->pgsz_factor[0], - uiip->pgsz_factor[1], uiip->pgsz_factor[2], - uiip->pgsz_factor[3]); - t3_write_reg(adapter, A_ULPRX_ISCSI_PSZ, val); - } - break; - default: - ret = -EOPNOTSUPP; - } - return ret; -} - -/* Response queue used for RDMA events. */ -#define ASYNC_NOTIF_RSPQ 0 - -static int cxgb_rdma_ctl(struct adapter *adapter, unsigned int req, void *data) -{ - int ret = 0; - - switch (req) { - case RDMA_GET_PARAMS: { - struct rdma_info *rdma = data; - struct pci_dev *pdev = adapter->pdev; - - rdma->udbell_physbase = pci_resource_start(pdev, 2); - rdma->udbell_len = pci_resource_len(pdev, 2); - rdma->tpt_base = - t3_read_reg(adapter, A_ULPTX_TPT_LLIMIT); - rdma->tpt_top = t3_read_reg(adapter, A_ULPTX_TPT_ULIMIT); - rdma->pbl_base = - t3_read_reg(adapter, A_ULPTX_PBL_LLIMIT); - rdma->pbl_top = t3_read_reg(adapter, A_ULPTX_PBL_ULIMIT); - rdma->rqt_base = t3_read_reg(adapter, A_ULPRX_RQ_LLIMIT); - rdma->rqt_top = t3_read_reg(adapter, A_ULPRX_RQ_ULIMIT); - rdma->kdb_addr = adapter->regs + A_SG_KDOORBELL; - rdma->pdev = pdev; - break; - } - case RDMA_CQ_OP:{ - unsigned long flags; - struct rdma_cq_op *rdma = data; - - /* may be called in any context */ - spin_lock_irqsave(&adapter->sge.reg_lock, flags); - ret = t3_sge_cqcntxt_op(adapter, rdma->id, rdma->op, - rdma->credits); - spin_unlock_irqrestore(&adapter->sge.reg_lock, flags); - break; - } - case RDMA_GET_MEM:{ - struct ch_mem_range *t = data; - struct mc7 *mem; - - if ((t->addr & 7) || (t->len & 7)) - return -EINVAL; - if (t->mem_id == MEM_CM) - mem = &adapter->cm; - else if (t->mem_id == MEM_PMRX) - mem = &adapter->pmrx; - else if (t->mem_id == MEM_PMTX) - mem = &adapter->pmtx; - else - return -EINVAL; - - ret = - t3_mc7_bd_read(mem, t->addr / 8, t->len / 8, - (u64 *) t->buf); - if (ret) - return ret; - break; - } - case RDMA_CQ_SETUP:{ - struct rdma_cq_setup *rdma = data; - - spin_lock_irq(&adapter->sge.reg_lock); - ret = - t3_sge_init_cqcntxt(adapter, rdma->id, - rdma->base_addr, rdma->size, - ASYNC_NOTIF_RSPQ, - rdma->ovfl_mode, rdma->credits, - rdma->credit_thres); - spin_unlock_irq(&adapter->sge.reg_lock); - break; - } - case RDMA_CQ_DISABLE: - spin_lock_irq(&adapter->sge.reg_lock); - ret = t3_sge_disable_cqcntxt(adapter, *(unsigned int *)data); - spin_unlock_irq(&adapter->sge.reg_lock); - break; - case RDMA_CTRL_QP_SETUP:{ - struct rdma_ctrlqp_setup *rdma = data; - - spin_lock_irq(&adapter->sge.reg_lock); - ret = t3_sge_init_ecntxt(adapter, FW_RI_SGEEC_START, 0, - SGE_CNTXT_RDMA, - ASYNC_NOTIF_RSPQ, - rdma->base_addr, rdma->size, - FW_RI_TID_START, 1, 0); - spin_unlock_irq(&adapter->sge.reg_lock); - break; - } - case RDMA_GET_MIB: { - spin_lock(&adapter->stats_lock); - t3_tp_get_mib_stats(adapter, (struct tp_mib_stats *)data); - spin_unlock(&adapter->stats_lock); - break; - } - default: - ret = -EOPNOTSUPP; - } - return ret; -} - -static int cxgb_offload_ctl(struct t3cdev *tdev, unsigned int req, void *data) -{ - struct adapter *adapter = tdev2adap(tdev); - struct tid_range *tid; - struct mtutab *mtup; - struct iff_mac *iffmacp; - struct ddp_params *ddpp; - struct adap_ports *ports; - struct ofld_page_info *rx_page_info; - struct tp_params *tp = &adapter->params.tp; - int i; - - switch (req) { - case GET_MAX_OUTSTANDING_WR: - *(unsigned int *)data = FW_WR_NUM; - break; - case GET_WR_LEN: - *(unsigned int *)data = WR_FLITS; - break; - case GET_TX_MAX_CHUNK: - *(unsigned int *)data = 1 << 20; /* 1MB */ - break; - case GET_TID_RANGE: - tid = data; - tid->num = t3_mc5_size(&adapter->mc5) - - adapter->params.mc5.nroutes - - adapter->params.mc5.nfilters - adapter->params.mc5.nservers; - tid->base = 0; - break; - case GET_STID_RANGE: - tid = data; - tid->num = adapter->params.mc5.nservers; - tid->base = t3_mc5_size(&adapter->mc5) - tid->num - - adapter->params.mc5.nfilters - adapter->params.mc5.nroutes; - break; - case GET_L2T_CAPACITY: - *(unsigned int *)data = 2048; - break; - case GET_MTUS: - mtup = data; - mtup->size = NMTUS; - mtup->mtus = adapter->params.mtus; - break; - case GET_IFF_FROM_MAC: - iffmacp = data; - iffmacp->dev = get_iff_from_mac(adapter, iffmacp->mac_addr, - iffmacp->vlan_tag & - VLAN_VID_MASK); - break; - case GET_DDP_PARAMS: - ddpp = data; - ddpp->llimit = t3_read_reg(adapter, A_ULPRX_TDDP_LLIMIT); - ddpp->ulimit = t3_read_reg(adapter, A_ULPRX_TDDP_ULIMIT); - ddpp->tag_mask = t3_read_reg(adapter, A_ULPRX_TDDP_TAGMASK); - break; - case GET_PORTS: - ports = data; - ports->nports = adapter->params.nports; - for_each_port(adapter, i) - ports->lldevs[i] = adapter->port[i]; - break; - case ULP_ISCSI_GET_PARAMS: - case ULP_ISCSI_SET_PARAMS: - if (!offload_running(adapter)) - return -EAGAIN; - return cxgb_ulp_iscsi_ctl(adapter, req, data); - case RDMA_GET_PARAMS: - case RDMA_CQ_OP: - case RDMA_CQ_SETUP: - case RDMA_CQ_DISABLE: - case RDMA_CTRL_QP_SETUP: - case RDMA_GET_MEM: - case RDMA_GET_MIB: - if (!offload_running(adapter)) - return -EAGAIN; - return cxgb_rdma_ctl(adapter, req, data); - case GET_RX_PAGE_INFO: - rx_page_info = data; - rx_page_info->page_size = tp->rx_pg_size; - rx_page_info->num = tp->rx_num_pgs; - break; - case GET_ISCSI_IPV4ADDR: { - struct iscsi_ipv4addr *p = data; - struct port_info *pi = netdev_priv(p->dev); - p->ipv4addr = pi->iscsi_ipv4addr; - break; - } - case GET_EMBEDDED_INFO: { - struct ch_embedded_info *e = data; - - spin_lock(&adapter->stats_lock); - t3_get_fw_version(adapter, &e->fw_vers); - t3_get_tp_version(adapter, &e->tp_vers); - spin_unlock(&adapter->stats_lock); - break; - } - default: - return -EOPNOTSUPP; - } - return 0; -} - -/* - * Dummy handler for Rx offload packets in case we get an offload packet before - * proper processing is setup. This complains and drops the packet as it isn't - * normal to get offload packets at this stage. - */ -static int rx_offload_blackhole(struct t3cdev *dev, struct sk_buff **skbs, - int n) -{ - while (n--) - dev_kfree_skb_any(skbs[n]); - return 0; -} - -static void dummy_neigh_update(struct t3cdev *dev, struct neighbour *neigh) -{ -} - -void cxgb3_set_dummy_ops(struct t3cdev *dev) -{ - dev->recv = rx_offload_blackhole; - dev->neigh_update = dummy_neigh_update; -} - -/* - * Free an active-open TID. - */ -void *cxgb3_free_atid(struct t3cdev *tdev, int atid) -{ - struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; - union active_open_entry *p = atid2entry(t, atid); - void *ctx = p->t3c_tid.ctx; - - spin_lock_bh(&t->atid_lock); - p->next = t->afree; - t->afree = p; - t->atids_in_use--; - spin_unlock_bh(&t->atid_lock); - - return ctx; -} - -EXPORT_SYMBOL(cxgb3_free_atid); - -/* - * Free a server TID and return it to the free pool. - */ -void cxgb3_free_stid(struct t3cdev *tdev, int stid) -{ - struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; - union listen_entry *p = stid2entry(t, stid); - - spin_lock_bh(&t->stid_lock); - p->next = t->sfree; - t->sfree = p; - t->stids_in_use--; - spin_unlock_bh(&t->stid_lock); -} - -EXPORT_SYMBOL(cxgb3_free_stid); - -void cxgb3_insert_tid(struct t3cdev *tdev, struct cxgb3_client *client, - void *ctx, unsigned int tid) -{ - struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; - - t->tid_tab[tid].client = client; - t->tid_tab[tid].ctx = ctx; - atomic_inc(&t->tids_in_use); -} - -EXPORT_SYMBOL(cxgb3_insert_tid); - -/* - * Populate a TID_RELEASE WR. The skb must be already propely sized. - */ -static inline void mk_tid_release(struct sk_buff *skb, unsigned int tid) -{ - struct cpl_tid_release *req; - - skb->priority = CPL_PRIORITY_SETUP; - req = (struct cpl_tid_release *)__skb_put(skb, sizeof(*req)); - req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); - OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, tid)); -} - -static void t3_process_tid_release_list(struct work_struct *work) -{ - struct t3c_data *td = container_of(work, struct t3c_data, - tid_release_task); - struct sk_buff *skb; - struct t3cdev *tdev = td->dev; - - - spin_lock_bh(&td->tid_release_lock); - while (td->tid_release_list) { - struct t3c_tid_entry *p = td->tid_release_list; - - td->tid_release_list = p->ctx; - spin_unlock_bh(&td->tid_release_lock); - - skb = alloc_skb(sizeof(struct cpl_tid_release), - GFP_KERNEL); - if (!skb) - skb = td->nofail_skb; - if (!skb) { - spin_lock_bh(&td->tid_release_lock); - p->ctx = (void *)td->tid_release_list; - td->tid_release_list = (struct t3c_tid_entry *)p; - break; - } - mk_tid_release(skb, p - td->tid_maps.tid_tab); - cxgb3_ofld_send(tdev, skb); - p->ctx = NULL; - if (skb == td->nofail_skb) - td->nofail_skb = - alloc_skb(sizeof(struct cpl_tid_release), - GFP_KERNEL); - spin_lock_bh(&td->tid_release_lock); - } - td->release_list_incomplete = (td->tid_release_list == NULL) ? 0 : 1; - spin_unlock_bh(&td->tid_release_lock); - - if (!td->nofail_skb) - td->nofail_skb = - alloc_skb(sizeof(struct cpl_tid_release), - GFP_KERNEL); -} - -/* use ctx as a next pointer in the tid release list */ -void cxgb3_queue_tid_release(struct t3cdev *tdev, unsigned int tid) -{ - struct t3c_data *td = T3C_DATA(tdev); - struct t3c_tid_entry *p = &td->tid_maps.tid_tab[tid]; - - spin_lock_bh(&td->tid_release_lock); - p->ctx = (void *)td->tid_release_list; - p->client = NULL; - td->tid_release_list = p; - if (!p->ctx || td->release_list_incomplete) - schedule_work(&td->tid_release_task); - spin_unlock_bh(&td->tid_release_lock); -} - -EXPORT_SYMBOL(cxgb3_queue_tid_release); - -/* - * Remove a tid from the TID table. A client may defer processing its last - * CPL message if it is locked at the time it arrives, and while the message - * sits in the client's backlog the TID may be reused for another connection. - * To handle this we atomically switch the TID association if it still points - * to the original client context. - */ -void cxgb3_remove_tid(struct t3cdev *tdev, void *ctx, unsigned int tid) -{ - struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; - - BUG_ON(tid >= t->ntids); - if (tdev->type == T3A) - (void)cmpxchg(&t->tid_tab[tid].ctx, ctx, NULL); - else { - struct sk_buff *skb; - - skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_ATOMIC); - if (likely(skb)) { - mk_tid_release(skb, tid); - cxgb3_ofld_send(tdev, skb); - t->tid_tab[tid].ctx = NULL; - } else - cxgb3_queue_tid_release(tdev, tid); - } - atomic_dec(&t->tids_in_use); -} - -EXPORT_SYMBOL(cxgb3_remove_tid); - -int cxgb3_alloc_atid(struct t3cdev *tdev, struct cxgb3_client *client, - void *ctx) -{ - int atid = -1; - struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; - - spin_lock_bh(&t->atid_lock); - if (t->afree && - t->atids_in_use + atomic_read(&t->tids_in_use) + MC5_MIN_TIDS <= - t->ntids) { - union active_open_entry *p = t->afree; - - atid = (p - t->atid_tab) + t->atid_base; - t->afree = p->next; - p->t3c_tid.ctx = ctx; - p->t3c_tid.client = client; - t->atids_in_use++; - } - spin_unlock_bh(&t->atid_lock); - return atid; -} - -EXPORT_SYMBOL(cxgb3_alloc_atid); - -int cxgb3_alloc_stid(struct t3cdev *tdev, struct cxgb3_client *client, - void *ctx) -{ - int stid = -1; - struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; - - spin_lock_bh(&t->stid_lock); - if (t->sfree) { - union listen_entry *p = t->sfree; - - stid = (p - t->stid_tab) + t->stid_base; - t->sfree = p->next; - p->t3c_tid.ctx = ctx; - p->t3c_tid.client = client; - t->stids_in_use++; - } - spin_unlock_bh(&t->stid_lock); - return stid; -} - -EXPORT_SYMBOL(cxgb3_alloc_stid); - -/* Get the t3cdev associated with a net_device */ -struct t3cdev *dev2t3cdev(struct net_device *dev) -{ - const struct port_info *pi = netdev_priv(dev); - - return (struct t3cdev *)pi->adapter; -} - -EXPORT_SYMBOL(dev2t3cdev); - -static int do_smt_write_rpl(struct t3cdev *dev, struct sk_buff *skb) -{ - struct cpl_smt_write_rpl *rpl = cplhdr(skb); - - if (rpl->status != CPL_ERR_NONE) - printk(KERN_ERR - "Unexpected SMT_WRITE_RPL status %u for entry %u\n", - rpl->status, GET_TID(rpl)); - - return CPL_RET_BUF_DONE; -} - -static int do_l2t_write_rpl(struct t3cdev *dev, struct sk_buff *skb) -{ - struct cpl_l2t_write_rpl *rpl = cplhdr(skb); - - if (rpl->status != CPL_ERR_NONE) - printk(KERN_ERR - "Unexpected L2T_WRITE_RPL status %u for entry %u\n", - rpl->status, GET_TID(rpl)); - - return CPL_RET_BUF_DONE; -} - -static int do_rte_write_rpl(struct t3cdev *dev, struct sk_buff *skb) -{ - struct cpl_rte_write_rpl *rpl = cplhdr(skb); - - if (rpl->status != CPL_ERR_NONE) - printk(KERN_ERR - "Unexpected RTE_WRITE_RPL status %u for entry %u\n", - rpl->status, GET_TID(rpl)); - - return CPL_RET_BUF_DONE; -} - -static int do_act_open_rpl(struct t3cdev *dev, struct sk_buff *skb) -{ - struct cpl_act_open_rpl *rpl = cplhdr(skb); - unsigned int atid = G_TID(ntohl(rpl->atid)); - struct t3c_tid_entry *t3c_tid; - - t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid); - if (t3c_tid && t3c_tid->ctx && t3c_tid->client && - t3c_tid->client->handlers && - t3c_tid->client->handlers[CPL_ACT_OPEN_RPL]) { - return t3c_tid->client->handlers[CPL_ACT_OPEN_RPL] (dev, skb, - t3c_tid-> - ctx); - } else { - printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", - dev->name, CPL_ACT_OPEN_RPL); - return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; - } -} - -static int do_stid_rpl(struct t3cdev *dev, struct sk_buff *skb) -{ - union opcode_tid *p = cplhdr(skb); - unsigned int stid = G_TID(ntohl(p->opcode_tid)); - struct t3c_tid_entry *t3c_tid; - - t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid); - if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && - t3c_tid->client->handlers[p->opcode]) { - return t3c_tid->client->handlers[p->opcode] (dev, skb, - t3c_tid->ctx); - } else { - printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", - dev->name, p->opcode); - return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; - } -} - -static int do_hwtid_rpl(struct t3cdev *dev, struct sk_buff *skb) -{ - union opcode_tid *p = cplhdr(skb); - unsigned int hwtid = G_TID(ntohl(p->opcode_tid)); - struct t3c_tid_entry *t3c_tid; - - t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid); - if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && - t3c_tid->client->handlers[p->opcode]) { - return t3c_tid->client->handlers[p->opcode] - (dev, skb, t3c_tid->ctx); - } else { - printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", - dev->name, p->opcode); - return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; - } -} - -static int do_cr(struct t3cdev *dev, struct sk_buff *skb) -{ - struct cpl_pass_accept_req *req = cplhdr(skb); - unsigned int stid = G_PASS_OPEN_TID(ntohl(req->tos_tid)); - struct tid_info *t = &(T3C_DATA(dev))->tid_maps; - struct t3c_tid_entry *t3c_tid; - unsigned int tid = GET_TID(req); - - if (unlikely(tid >= t->ntids)) { - printk("%s: passive open TID %u too large\n", - dev->name, tid); - t3_fatal_err(tdev2adap(dev)); - return CPL_RET_BUF_DONE; - } - - t3c_tid = lookup_stid(t, stid); - if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && - t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]) { - return t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ] - (dev, skb, t3c_tid->ctx); - } else { - printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", - dev->name, CPL_PASS_ACCEPT_REQ); - return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; - } -} - -/* - * Returns an sk_buff for a reply CPL message of size len. If the input - * sk_buff has no other users it is trimmed and reused, otherwise a new buffer - * is allocated. The input skb must be of size at least len. Note that this - * operation does not destroy the original skb data even if it decides to reuse - * the buffer. - */ -static struct sk_buff *cxgb3_get_cpl_reply_skb(struct sk_buff *skb, size_t len, - gfp_t gfp) -{ - if (likely(!skb_cloned(skb))) { - BUG_ON(skb->len < len); - __skb_trim(skb, len); - skb_get(skb); - } else { - skb = alloc_skb(len, gfp); - if (skb) - __skb_put(skb, len); - } - return skb; -} - -static int do_abort_req_rss(struct t3cdev *dev, struct sk_buff *skb) -{ - union opcode_tid *p = cplhdr(skb); - unsigned int hwtid = G_TID(ntohl(p->opcode_tid)); - struct t3c_tid_entry *t3c_tid; - - t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid); - if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && - t3c_tid->client->handlers[p->opcode]) { - return t3c_tid->client->handlers[p->opcode] - (dev, skb, t3c_tid->ctx); - } else { - struct cpl_abort_req_rss *req = cplhdr(skb); - struct cpl_abort_rpl *rpl; - struct sk_buff *reply_skb; - unsigned int tid = GET_TID(req); - u8 cmd = req->status; - - if (req->status == CPL_ERR_RTX_NEG_ADVICE || - req->status == CPL_ERR_PERSIST_NEG_ADVICE) - goto out; - - reply_skb = cxgb3_get_cpl_reply_skb(skb, - sizeof(struct - cpl_abort_rpl), - GFP_ATOMIC); - - if (!reply_skb) { - printk("do_abort_req_rss: couldn't get skb!\n"); - goto out; - } - reply_skb->priority = CPL_PRIORITY_DATA; - __skb_put(reply_skb, sizeof(struct cpl_abort_rpl)); - rpl = cplhdr(reply_skb); - rpl->wr.wr_hi = - htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL)); - rpl->wr.wr_lo = htonl(V_WR_TID(tid)); - OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, tid)); - rpl->cmd = cmd; - cxgb3_ofld_send(dev, reply_skb); -out: - return CPL_RET_BUF_DONE; - } -} - -static int do_act_establish(struct t3cdev *dev, struct sk_buff *skb) -{ - struct cpl_act_establish *req = cplhdr(skb); - unsigned int atid = G_PASS_OPEN_TID(ntohl(req->tos_tid)); - struct tid_info *t = &(T3C_DATA(dev))->tid_maps; - struct t3c_tid_entry *t3c_tid; - unsigned int tid = GET_TID(req); - - if (unlikely(tid >= t->ntids)) { - printk("%s: active establish TID %u too large\n", - dev->name, tid); - t3_fatal_err(tdev2adap(dev)); - return CPL_RET_BUF_DONE; - } - - t3c_tid = lookup_atid(t, atid); - if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && - t3c_tid->client->handlers[CPL_ACT_ESTABLISH]) { - return t3c_tid->client->handlers[CPL_ACT_ESTABLISH] - (dev, skb, t3c_tid->ctx); - } else { - printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", - dev->name, CPL_ACT_ESTABLISH); - return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; - } -} - -static int do_trace(struct t3cdev *dev, struct sk_buff *skb) -{ - struct cpl_trace_pkt *p = cplhdr(skb); - - skb->protocol = htons(0xffff); - skb->dev = dev->lldev; - skb_pull(skb, sizeof(*p)); - skb_reset_mac_header(skb); - netif_receive_skb(skb); - return 0; -} - -/* - * That skb would better have come from process_responses() where we abuse - * ->priority and ->csum to carry our data. NB: if we get to per-arch - * ->csum, the things might get really interesting here. - */ - -static inline u32 get_hwtid(struct sk_buff *skb) -{ - return ntohl((__force __be32)skb->priority) >> 8 & 0xfffff; -} - -static inline u32 get_opcode(struct sk_buff *skb) -{ - return G_OPCODE(ntohl((__force __be32)skb->csum)); -} - -static int do_term(struct t3cdev *dev, struct sk_buff *skb) -{ - unsigned int hwtid = get_hwtid(skb); - unsigned int opcode = get_opcode(skb); - struct t3c_tid_entry *t3c_tid; - - t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid); - if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && - t3c_tid->client->handlers[opcode]) { - return t3c_tid->client->handlers[opcode] (dev, skb, - t3c_tid->ctx); - } else { - printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", - dev->name, opcode); - return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; - } -} - -static int nb_callback(struct notifier_block *self, unsigned long event, - void *ctx) -{ - switch (event) { - case (NETEVENT_NEIGH_UPDATE):{ - cxgb_neigh_update((struct neighbour *)ctx); - break; - } - case (NETEVENT_REDIRECT):{ - struct netevent_redirect *nr = ctx; - cxgb_redirect(nr->old, nr->new); - cxgb_neigh_update(dst_get_neighbour(nr->new)); - break; - } - default: - break; - } - return 0; -} - -static struct notifier_block nb = { - .notifier_call = nb_callback -}; - -/* - * Process a received packet with an unknown/unexpected CPL opcode. - */ -static int do_bad_cpl(struct t3cdev *dev, struct sk_buff *skb) -{ - printk(KERN_ERR "%s: received bad CPL command 0x%x\n", dev->name, - *skb->data); - return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; -} - -/* - * Handlers for each CPL opcode - */ -static cpl_handler_func cpl_handlers[NUM_CPL_CMDS]; - -/* - * Add a new handler to the CPL dispatch table. A NULL handler may be supplied - * to unregister an existing handler. - */ -void t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h) -{ - if (opcode < NUM_CPL_CMDS) - cpl_handlers[opcode] = h ? h : do_bad_cpl; - else - printk(KERN_ERR "T3C: handler registration for " - "opcode %x failed\n", opcode); -} - -EXPORT_SYMBOL(t3_register_cpl_handler); - -/* - * T3CDEV's receive method. - */ -static int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n) -{ - while (n--) { - struct sk_buff *skb = *skbs++; - unsigned int opcode = get_opcode(skb); - int ret = cpl_handlers[opcode] (dev, skb); - -#if VALIDATE_TID - if (ret & CPL_RET_UNKNOWN_TID) { - union opcode_tid *p = cplhdr(skb); - - printk(KERN_ERR "%s: CPL message (opcode %u) had " - "unknown TID %u\n", dev->name, opcode, - G_TID(ntohl(p->opcode_tid))); - } -#endif - if (ret & CPL_RET_BUF_DONE) - kfree_skb(skb); - } - return 0; -} - -/* - * Sends an sk_buff to a T3C driver after dealing with any active network taps. - */ -int cxgb3_ofld_send(struct t3cdev *dev, struct sk_buff *skb) -{ - int r; - - local_bh_disable(); - r = dev->send(dev, skb); - local_bh_enable(); - return r; -} - -EXPORT_SYMBOL(cxgb3_ofld_send); - -static int is_offloading(struct net_device *dev) -{ - struct adapter *adapter; - int i; - - read_lock_bh(&adapter_list_lock); - list_for_each_entry(adapter, &adapter_list, adapter_list) { - for_each_port(adapter, i) { - if (dev == adapter->port[i]) { - read_unlock_bh(&adapter_list_lock); - return 1; - } - } - } - read_unlock_bh(&adapter_list_lock); - return 0; -} - -static void cxgb_neigh_update(struct neighbour *neigh) -{ - struct net_device *dev = neigh->dev; - - if (dev && (is_offloading(dev))) { - struct t3cdev *tdev = dev2t3cdev(dev); - - BUG_ON(!tdev); - t3_l2t_update(tdev, neigh); - } -} - -static void set_l2t_ix(struct t3cdev *tdev, u32 tid, struct l2t_entry *e) -{ - struct sk_buff *skb; - struct cpl_set_tcb_field *req; - - skb = alloc_skb(sizeof(*req), GFP_ATOMIC); - if (!skb) { - printk(KERN_ERR "%s: cannot allocate skb!\n", __func__); - return; - } - skb->priority = CPL_PRIORITY_CONTROL; - req = (struct cpl_set_tcb_field *)skb_put(skb, sizeof(*req)); - req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); - OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid)); - req->reply = 0; - req->cpu_idx = 0; - req->word = htons(W_TCB_L2T_IX); - req->mask = cpu_to_be64(V_TCB_L2T_IX(M_TCB_L2T_IX)); - req->val = cpu_to_be64(V_TCB_L2T_IX(e->idx)); - tdev->send(tdev, skb); -} - -static void cxgb_redirect(struct dst_entry *old, struct dst_entry *new) -{ - struct net_device *olddev, *newdev; - struct tid_info *ti; - struct t3cdev *tdev; - u32 tid; - int update_tcb; - struct l2t_entry *e; - struct t3c_tid_entry *te; - - olddev = dst_get_neighbour(old)->dev; - newdev = dst_get_neighbour(new)->dev; - if (!is_offloading(olddev)) - return; - if (!is_offloading(newdev)) { - printk(KERN_WARNING "%s: Redirect to non-offload " - "device ignored.\n", __func__); - return; - } - tdev = dev2t3cdev(olddev); - BUG_ON(!tdev); - if (tdev != dev2t3cdev(newdev)) { - printk(KERN_WARNING "%s: Redirect to different " - "offload device ignored.\n", __func__); - return; - } - - /* Add new L2T entry */ - e = t3_l2t_get(tdev, dst_get_neighbour(new), newdev); - if (!e) { - printk(KERN_ERR "%s: couldn't allocate new l2t entry!\n", - __func__); - return; - } - - /* Walk tid table and notify clients of dst change. */ - ti = &(T3C_DATA(tdev))->tid_maps; - for (tid = 0; tid < ti->ntids; tid++) { - te = lookup_tid(ti, tid); - BUG_ON(!te); - if (te && te->ctx && te->client && te->client->redirect) { - update_tcb = te->client->redirect(te->ctx, old, new, e); - if (update_tcb) { - l2t_hold(L2DATA(tdev), e); - set_l2t_ix(tdev, tid, e); - } - } - } - l2t_release(L2DATA(tdev), e); -} - -/* - * Allocate a chunk of memory using kmalloc or, if that fails, vmalloc. - * The allocated memory is cleared. - */ -void *cxgb_alloc_mem(unsigned long size) -{ - void *p = kzalloc(size, GFP_KERNEL); - - if (!p) - p = vzalloc(size); - return p; -} - -/* - * Free memory allocated through t3_alloc_mem(). - */ -void cxgb_free_mem(void *addr) -{ - if (is_vmalloc_addr(addr)) - vfree(addr); - else - kfree(addr); -} - -/* - * Allocate and initialize the TID tables. Returns 0 on success. - */ -static int init_tid_tabs(struct tid_info *t, unsigned int ntids, - unsigned int natids, unsigned int nstids, - unsigned int atid_base, unsigned int stid_base) -{ - unsigned long size = ntids * sizeof(*t->tid_tab) + - natids * sizeof(*t->atid_tab) + nstids * sizeof(*t->stid_tab); - - t->tid_tab = cxgb_alloc_mem(size); - if (!t->tid_tab) - return -ENOMEM; - - t->stid_tab = (union listen_entry *)&t->tid_tab[ntids]; - t->atid_tab = (union active_open_entry *)&t->stid_tab[nstids]; - t->ntids = ntids; - t->nstids = nstids; - t->stid_base = stid_base; - t->sfree = NULL; - t->natids = natids; - t->atid_base = atid_base; - t->afree = NULL; - t->stids_in_use = t->atids_in_use = 0; - atomic_set(&t->tids_in_use, 0); - spin_lock_init(&t->stid_lock); - spin_lock_init(&t->atid_lock); - - /* - * Setup the free lists for stid_tab and atid_tab. - */ - if (nstids) { - while (--nstids) - t->stid_tab[nstids - 1].next = &t->stid_tab[nstids]; - t->sfree = t->stid_tab; - } - if (natids) { - while (--natids) - t->atid_tab[natids - 1].next = &t->atid_tab[natids]; - t->afree = t->atid_tab; - } - return 0; -} - -static void free_tid_maps(struct tid_info *t) -{ - cxgb_free_mem(t->tid_tab); -} - -static inline void add_adapter(struct adapter *adap) -{ - write_lock_bh(&adapter_list_lock); - list_add_tail(&adap->adapter_list, &adapter_list); - write_unlock_bh(&adapter_list_lock); -} - -static inline void remove_adapter(struct adapter *adap) -{ - write_lock_bh(&adapter_list_lock); - list_del(&adap->adapter_list); - write_unlock_bh(&adapter_list_lock); -} - -int cxgb3_offload_activate(struct adapter *adapter) -{ - struct t3cdev *dev = &adapter->tdev; - int natids, err; - struct t3c_data *t; - struct tid_range stid_range, tid_range; - struct mtutab mtutab; - unsigned int l2t_capacity; - - t = kzalloc(sizeof(*t), GFP_KERNEL); - if (!t) - return -ENOMEM; - - err = -EOPNOTSUPP; - if (dev->ctl(dev, GET_TX_MAX_CHUNK, &t->tx_max_chunk) < 0 || - dev->ctl(dev, GET_MAX_OUTSTANDING_WR, &t->max_wrs) < 0 || - dev->ctl(dev, GET_L2T_CAPACITY, &l2t_capacity) < 0 || - dev->ctl(dev, GET_MTUS, &mtutab) < 0 || - dev->ctl(dev, GET_TID_RANGE, &tid_range) < 0 || - dev->ctl(dev, GET_STID_RANGE, &stid_range) < 0) - goto out_free; - - err = -ENOMEM; - L2DATA(dev) = t3_init_l2t(l2t_capacity); - if (!L2DATA(dev)) - goto out_free; - - natids = min(tid_range.num / 2, MAX_ATIDS); - err = init_tid_tabs(&t->tid_maps, tid_range.num, natids, - stid_range.num, ATID_BASE, stid_range.base); - if (err) - goto out_free_l2t; - - t->mtus = mtutab.mtus; - t->nmtus = mtutab.size; - - INIT_WORK(&t->tid_release_task, t3_process_tid_release_list); - spin_lock_init(&t->tid_release_lock); - INIT_LIST_HEAD(&t->list_node); - t->dev = dev; - - T3C_DATA(dev) = t; - dev->recv = process_rx; - dev->neigh_update = t3_l2t_update; - - /* Register netevent handler once */ - if (list_empty(&adapter_list)) - register_netevent_notifier(&nb); - - t->nofail_skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_KERNEL); - t->release_list_incomplete = 0; - - add_adapter(adapter); - return 0; - -out_free_l2t: - t3_free_l2t(L2DATA(dev)); - L2DATA(dev) = NULL; -out_free: - kfree(t); - return err; -} - -void cxgb3_offload_deactivate(struct adapter *adapter) -{ - struct t3cdev *tdev = &adapter->tdev; - struct t3c_data *t = T3C_DATA(tdev); - - remove_adapter(adapter); - if (list_empty(&adapter_list)) - unregister_netevent_notifier(&nb); - - free_tid_maps(&t->tid_maps); - T3C_DATA(tdev) = NULL; - t3_free_l2t(L2DATA(tdev)); - L2DATA(tdev) = NULL; - if (t->nofail_skb) - kfree_skb(t->nofail_skb); - kfree(t); -} - -static inline void register_tdev(struct t3cdev *tdev) -{ - static int unit; - - mutex_lock(&cxgb3_db_lock); - snprintf(tdev->name, sizeof(tdev->name), "ofld_dev%d", unit++); - list_add_tail(&tdev->ofld_dev_list, &ofld_dev_list); - mutex_unlock(&cxgb3_db_lock); -} - -static inline void unregister_tdev(struct t3cdev *tdev) -{ - mutex_lock(&cxgb3_db_lock); - list_del(&tdev->ofld_dev_list); - mutex_unlock(&cxgb3_db_lock); -} - -static inline int adap2type(struct adapter *adapter) -{ - int type = 0; - - switch (adapter->params.rev) { - case T3_REV_A: - type = T3A; - break; - case T3_REV_B: - case T3_REV_B2: - type = T3B; - break; - case T3_REV_C: - type = T3C; - break; - } - return type; -} - -void __devinit cxgb3_adapter_ofld(struct adapter *adapter) -{ - struct t3cdev *tdev = &adapter->tdev; - - INIT_LIST_HEAD(&tdev->ofld_dev_list); - - cxgb3_set_dummy_ops(tdev); - tdev->send = t3_offload_tx; - tdev->ctl = cxgb_offload_ctl; - tdev->type = adap2type(adapter); - - register_tdev(tdev); -} - -void __devexit cxgb3_adapter_unofld(struct adapter *adapter) -{ - struct t3cdev *tdev = &adapter->tdev; - - tdev->recv = NULL; - tdev->neigh_update = NULL; - - unregister_tdev(tdev); -} - -void __init cxgb3_offload_init(void) -{ - int i; - - for (i = 0; i < NUM_CPL_CMDS; ++i) - cpl_handlers[i] = do_bad_cpl; - - t3_register_cpl_handler(CPL_SMT_WRITE_RPL, do_smt_write_rpl); - t3_register_cpl_handler(CPL_L2T_WRITE_RPL, do_l2t_write_rpl); - t3_register_cpl_handler(CPL_RTE_WRITE_RPL, do_rte_write_rpl); - t3_register_cpl_handler(CPL_PASS_OPEN_RPL, do_stid_rpl); - t3_register_cpl_handler(CPL_CLOSE_LISTSRV_RPL, do_stid_rpl); - t3_register_cpl_handler(CPL_PASS_ACCEPT_REQ, do_cr); - t3_register_cpl_handler(CPL_PASS_ESTABLISH, do_hwtid_rpl); - t3_register_cpl_handler(CPL_ABORT_RPL_RSS, do_hwtid_rpl); - t3_register_cpl_handler(CPL_ABORT_RPL, do_hwtid_rpl); - t3_register_cpl_handler(CPL_RX_URG_NOTIFY, do_hwtid_rpl); - t3_register_cpl_handler(CPL_RX_DATA, do_hwtid_rpl); - t3_register_cpl_handler(CPL_TX_DATA_ACK, do_hwtid_rpl); - t3_register_cpl_handler(CPL_TX_DMA_ACK, do_hwtid_rpl); - t3_register_cpl_handler(CPL_ACT_OPEN_RPL, do_act_open_rpl); - t3_register_cpl_handler(CPL_PEER_CLOSE, do_hwtid_rpl); - t3_register_cpl_handler(CPL_CLOSE_CON_RPL, do_hwtid_rpl); - t3_register_cpl_handler(CPL_ABORT_REQ_RSS, do_abort_req_rss); - t3_register_cpl_handler(CPL_ACT_ESTABLISH, do_act_establish); - t3_register_cpl_handler(CPL_SET_TCB_RPL, do_hwtid_rpl); - t3_register_cpl_handler(CPL_GET_TCB_RPL, do_hwtid_rpl); - t3_register_cpl_handler(CPL_RDMA_TERMINATE, do_term); - t3_register_cpl_handler(CPL_RDMA_EC_STATUS, do_hwtid_rpl); - t3_register_cpl_handler(CPL_TRACE_PKT, do_trace); - t3_register_cpl_handler(CPL_RX_DATA_DDP, do_hwtid_rpl); - t3_register_cpl_handler(CPL_RX_DDP_COMPLETE, do_hwtid_rpl); - t3_register_cpl_handler(CPL_ISCSI_HDR, do_hwtid_rpl); -} diff --git a/drivers/net/cxgb3/cxgb3_offload.h b/drivers/net/cxgb3/cxgb3_offload.h deleted file mode 100644 index 929c298115ca..000000000000 --- a/drivers/net/cxgb3/cxgb3_offload.h +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright (c) 2006-2008 Chelsio, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _CXGB3_OFFLOAD_H -#define _CXGB3_OFFLOAD_H - -#include -#include - -#include "l2t.h" - -#include "t3cdev.h" -#include "t3_cpl.h" - -struct adapter; - -void cxgb3_offload_init(void); - -void cxgb3_adapter_ofld(struct adapter *adapter); -void cxgb3_adapter_unofld(struct adapter *adapter); -int cxgb3_offload_activate(struct adapter *adapter); -void cxgb3_offload_deactivate(struct adapter *adapter); - -void cxgb3_set_dummy_ops(struct t3cdev *dev); - -struct t3cdev *dev2t3cdev(struct net_device *dev); - -/* - * Client registration. Users of T3 driver must register themselves. - * The T3 driver will call the add function of every client for each T3 - * adapter activated, passing up the t3cdev ptr. Each client fills out an - * array of callback functions to process CPL messages. - */ - -void cxgb3_register_client(struct cxgb3_client *client); -void cxgb3_unregister_client(struct cxgb3_client *client); -void cxgb3_add_clients(struct t3cdev *tdev); -void cxgb3_remove_clients(struct t3cdev *tdev); -void cxgb3_event_notify(struct t3cdev *tdev, u32 event, u32 port); - -typedef int (*cxgb3_cpl_handler_func)(struct t3cdev *dev, - struct sk_buff *skb, void *ctx); - -enum { - OFFLOAD_STATUS_UP, - OFFLOAD_STATUS_DOWN, - OFFLOAD_PORT_DOWN, - OFFLOAD_PORT_UP, - OFFLOAD_DB_FULL, - OFFLOAD_DB_EMPTY, - OFFLOAD_DB_DROP -}; - -struct cxgb3_client { - char *name; - void (*add) (struct t3cdev *); - void (*remove) (struct t3cdev *); - cxgb3_cpl_handler_func *handlers; - int (*redirect)(void *ctx, struct dst_entry *old, - struct dst_entry *new, struct l2t_entry *l2t); - struct list_head client_list; - void (*event_handler)(struct t3cdev *tdev, u32 event, u32 port); -}; - -/* - * TID allocation services. - */ -int cxgb3_alloc_atid(struct t3cdev *dev, struct cxgb3_client *client, - void *ctx); -int cxgb3_alloc_stid(struct t3cdev *dev, struct cxgb3_client *client, - void *ctx); -void *cxgb3_free_atid(struct t3cdev *dev, int atid); -void cxgb3_free_stid(struct t3cdev *dev, int stid); -void cxgb3_insert_tid(struct t3cdev *dev, struct cxgb3_client *client, - void *ctx, unsigned int tid); -void cxgb3_queue_tid_release(struct t3cdev *dev, unsigned int tid); -void cxgb3_remove_tid(struct t3cdev *dev, void *ctx, unsigned int tid); - -struct t3c_tid_entry { - struct cxgb3_client *client; - void *ctx; -}; - -/* CPL message priority levels */ -enum { - CPL_PRIORITY_DATA = 0, /* data messages */ - CPL_PRIORITY_SETUP = 1, /* connection setup messages */ - CPL_PRIORITY_TEARDOWN = 0, /* connection teardown messages */ - CPL_PRIORITY_LISTEN = 1, /* listen start/stop messages */ - CPL_PRIORITY_ACK = 1, /* RX ACK messages */ - CPL_PRIORITY_CONTROL = 1 /* offload control messages */ -}; - -/* Flags for return value of CPL message handlers */ -enum { - CPL_RET_BUF_DONE = 1, /* buffer processing done, buffer may be freed */ - CPL_RET_BAD_MSG = 2, /* bad CPL message (e.g., unknown opcode) */ - CPL_RET_UNKNOWN_TID = 4 /* unexpected unknown TID */ -}; - -typedef int (*cpl_handler_func)(struct t3cdev *dev, struct sk_buff *skb); - -/* - * Returns a pointer to the first byte of the CPL header in an sk_buff that - * contains a CPL message. - */ -static inline void *cplhdr(struct sk_buff *skb) -{ - return skb->data; -} - -void t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h); - -union listen_entry { - struct t3c_tid_entry t3c_tid; - union listen_entry *next; -}; - -union active_open_entry { - struct t3c_tid_entry t3c_tid; - union active_open_entry *next; -}; - -/* - * Holds the size, base address, free list start, etc of the TID, server TID, - * and active-open TID tables for a offload device. - * The tables themselves are allocated dynamically. - */ -struct tid_info { - struct t3c_tid_entry *tid_tab; - unsigned int ntids; - atomic_t tids_in_use; - - union listen_entry *stid_tab; - unsigned int nstids; - unsigned int stid_base; - - union active_open_entry *atid_tab; - unsigned int natids; - unsigned int atid_base; - - /* - * The following members are accessed R/W so we put them in their own - * cache lines. - * - * XXX We could combine the atid fields above with the lock here since - * atids are use once (unlike other tids). OTOH the above fields are - * usually in cache due to tid_tab. - */ - spinlock_t atid_lock ____cacheline_aligned_in_smp; - union active_open_entry *afree; - unsigned int atids_in_use; - - spinlock_t stid_lock ____cacheline_aligned; - union listen_entry *sfree; - unsigned int stids_in_use; -}; - -struct t3c_data { - struct list_head list_node; - struct t3cdev *dev; - unsigned int tx_max_chunk; /* max payload for TX_DATA */ - unsigned int max_wrs; /* max in-flight WRs per connection */ - unsigned int nmtus; - const unsigned short *mtus; - struct tid_info tid_maps; - - struct t3c_tid_entry *tid_release_list; - spinlock_t tid_release_lock; - struct work_struct tid_release_task; - - struct sk_buff *nofail_skb; - unsigned int release_list_incomplete; -}; - -/* - * t3cdev -> t3c_data accessor - */ -#define T3C_DATA(dev) (*(struct t3c_data **)&(dev)->l4opt) - -#endif diff --git a/drivers/net/cxgb3/firmware_exports.h b/drivers/net/cxgb3/firmware_exports.h deleted file mode 100644 index 0d9b0e6dccff..000000000000 --- a/drivers/net/cxgb3/firmware_exports.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2004-2008 Chelsio, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _FIRMWARE_EXPORTS_H_ -#define _FIRMWARE_EXPORTS_H_ - -/* WR OPCODES supported by the firmware. - */ -#define FW_WROPCODE_FORWARD 0x01 -#define FW_WROPCODE_BYPASS 0x05 - -#define FW_WROPCODE_TUNNEL_TX_PKT 0x03 - -#define FW_WROPOCDE_ULPTX_DATA_SGL 0x00 -#define FW_WROPCODE_ULPTX_MEM_READ 0x02 -#define FW_WROPCODE_ULPTX_PKT 0x04 -#define FW_WROPCODE_ULPTX_INVALIDATE 0x06 - -#define FW_WROPCODE_TUNNEL_RX_PKT 0x07 - -#define FW_WROPCODE_OFLD_GETTCB_RPL 0x08 -#define FW_WROPCODE_OFLD_CLOSE_CON 0x09 -#define FW_WROPCODE_OFLD_TP_ABORT_CON_REQ 0x0A -#define FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL 0x0F -#define FW_WROPCODE_OFLD_HOST_ABORT_CON_REQ 0x0B -#define FW_WROPCODE_OFLD_TP_ABORT_CON_RPL 0x0C -#define FW_WROPCODE_OFLD_TX_DATA 0x0D -#define FW_WROPCODE_OFLD_TX_DATA_ACK 0x0E - -#define FW_WROPCODE_RI_RDMA_INIT 0x10 -#define FW_WROPCODE_RI_RDMA_WRITE 0x11 -#define FW_WROPCODE_RI_RDMA_READ_REQ 0x12 -#define FW_WROPCODE_RI_RDMA_READ_RESP 0x13 -#define FW_WROPCODE_RI_SEND 0x14 -#define FW_WROPCODE_RI_TERMINATE 0x15 -#define FW_WROPCODE_RI_RDMA_READ 0x16 -#define FW_WROPCODE_RI_RECEIVE 0x17 -#define FW_WROPCODE_RI_BIND_MW 0x18 -#define FW_WROPCODE_RI_FASTREGISTER_MR 0x19 -#define FW_WROPCODE_RI_LOCAL_INV 0x1A -#define FW_WROPCODE_RI_MODIFY_QP 0x1B -#define FW_WROPCODE_RI_BYPASS 0x1C - -#define FW_WROPOCDE_RSVD 0x1E - -#define FW_WROPCODE_SGE_EGRESSCONTEXT_RR 0x1F - -#define FW_WROPCODE_MNGT 0x1D -#define FW_MNGTOPCODE_PKTSCHED_SET 0x00 - -/* Maximum size of a WR sent from the host, limited by the SGE. - * - * Note: WR coming from ULP or TP are only limited by CIM. - */ -#define FW_WR_SIZE 128 - -/* Maximum number of outstanding WRs sent from the host. Value must be - * programmed in the CTRL/TUNNEL/QP SGE Egress Context and used by - * offload modules to limit the number of WRs per connection. - */ -#define FW_T3_WR_NUM 16 -#define FW_N3_WR_NUM 7 - -#ifndef N3 -# define FW_WR_NUM FW_T3_WR_NUM -#else -# define FW_WR_NUM FW_N3_WR_NUM -#endif - -/* FW_TUNNEL_NUM corresponds to the number of supported TUNNEL Queues. These - * queues must start at SGE Egress Context FW_TUNNEL_SGEEC_START and must - * start at 'TID' (or 'uP Token') FW_TUNNEL_TID_START. - * - * Ingress Traffic (e.g. DMA completion credit) for TUNNEL Queue[i] is sent - * to RESP Queue[i]. - */ -#define FW_TUNNEL_NUM 8 -#define FW_TUNNEL_SGEEC_START 8 -#define FW_TUNNEL_TID_START 65544 - -/* FW_CTRL_NUM corresponds to the number of supported CTRL Queues. These queues - * must start at SGE Egress Context FW_CTRL_SGEEC_START and must start at 'TID' - * (or 'uP Token') FW_CTRL_TID_START. - * - * Ingress Traffic for CTRL Queue[i] is sent to RESP Queue[i]. - */ -#define FW_CTRL_NUM 8 -#define FW_CTRL_SGEEC_START 65528 -#define FW_CTRL_TID_START 65536 - -/* FW_OFLD_NUM corresponds to the number of supported OFFLOAD Queues. These - * queues must start at SGE Egress Context FW_OFLD_SGEEC_START. - * - * Note: the 'uP Token' in the SGE Egress Context fields is irrelevant for - * OFFLOAD Queues, as the host is responsible for providing the correct TID in - * every WR. - * - * Ingress Trafffic for OFFLOAD Queue[i] is sent to RESP Queue[i]. - */ -#define FW_OFLD_NUM 8 -#define FW_OFLD_SGEEC_START 0 - -/* - * - */ -#define FW_RI_NUM 1 -#define FW_RI_SGEEC_START 65527 -#define FW_RI_TID_START 65552 - -/* - * The RX_PKT_TID - */ -#define FW_RX_PKT_NUM 1 -#define FW_RX_PKT_TID_START 65553 - -/* FW_WRC_NUM corresponds to the number of Work Request Context that supported - * by the firmware. - */ -#define FW_WRC_NUM \ - (65536 + FW_TUNNEL_NUM + FW_CTRL_NUM + FW_RI_NUM + FW_RX_PKT_NUM) - -/* - * FW type and version. - */ -#define S_FW_VERSION_TYPE 28 -#define M_FW_VERSION_TYPE 0xF -#define V_FW_VERSION_TYPE(x) ((x) << S_FW_VERSION_TYPE) -#define G_FW_VERSION_TYPE(x) \ - (((x) >> S_FW_VERSION_TYPE) & M_FW_VERSION_TYPE) - -#define S_FW_VERSION_MAJOR 16 -#define M_FW_VERSION_MAJOR 0xFFF -#define V_FW_VERSION_MAJOR(x) ((x) << S_FW_VERSION_MAJOR) -#define G_FW_VERSION_MAJOR(x) \ - (((x) >> S_FW_VERSION_MAJOR) & M_FW_VERSION_MAJOR) - -#define S_FW_VERSION_MINOR 8 -#define M_FW_VERSION_MINOR 0xFF -#define V_FW_VERSION_MINOR(x) ((x) << S_FW_VERSION_MINOR) -#define G_FW_VERSION_MINOR(x) \ - (((x) >> S_FW_VERSION_MINOR) & M_FW_VERSION_MINOR) - -#define S_FW_VERSION_MICRO 0 -#define M_FW_VERSION_MICRO 0xFF -#define V_FW_VERSION_MICRO(x) ((x) << S_FW_VERSION_MICRO) -#define G_FW_VERSION_MICRO(x) \ - (((x) >> S_FW_VERSION_MICRO) & M_FW_VERSION_MICRO) - -#endif /* _FIRMWARE_EXPORTS_H_ */ diff --git a/drivers/net/cxgb3/l2t.c b/drivers/net/cxgb3/l2t.c deleted file mode 100644 index f452c4003253..000000000000 --- a/drivers/net/cxgb3/l2t.c +++ /dev/null @@ -1,445 +0,0 @@ -/* - * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#include -#include -#include -#include -#include -#include -#include -#include "common.h" -#include "t3cdev.h" -#include "cxgb3_defs.h" -#include "l2t.h" -#include "t3_cpl.h" -#include "firmware_exports.h" - -#define VLAN_NONE 0xfff - -/* - * Module locking notes: There is a RW lock protecting the L2 table as a - * whole plus a spinlock per L2T entry. Entry lookups and allocations happen - * under the protection of the table lock, individual entry changes happen - * while holding that entry's spinlock. The table lock nests outside the - * entry locks. Allocations of new entries take the table lock as writers so - * no other lookups can happen while allocating new entries. Entry updates - * take the table lock as readers so multiple entries can be updated in - * parallel. An L2T entry can be dropped by decrementing its reference count - * and therefore can happen in parallel with entry allocation but no entry - * can change state or increment its ref count during allocation as both of - * these perform lookups. - */ - -static inline unsigned int vlan_prio(const struct l2t_entry *e) -{ - return e->vlan >> 13; -} - -static inline unsigned int arp_hash(u32 key, int ifindex, - const struct l2t_data *d) -{ - return jhash_2words(key, ifindex, 0) & (d->nentries - 1); -} - -static inline void neigh_replace(struct l2t_entry *e, struct neighbour *n) -{ - neigh_hold(n); - if (e->neigh) - neigh_release(e->neigh); - e->neigh = n; -} - -/* - * Set up an L2T entry and send any packets waiting in the arp queue. The - * supplied skb is used for the CPL_L2T_WRITE_REQ. Must be called with the - * entry locked. - */ -static int setup_l2e_send_pending(struct t3cdev *dev, struct sk_buff *skb, - struct l2t_entry *e) -{ - struct cpl_l2t_write_req *req; - struct sk_buff *tmp; - - if (!skb) { - skb = alloc_skb(sizeof(*req), GFP_ATOMIC); - if (!skb) - return -ENOMEM; - } - - req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req)); - req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); - OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, e->idx)); - req->params = htonl(V_L2T_W_IDX(e->idx) | V_L2T_W_IFF(e->smt_idx) | - V_L2T_W_VLAN(e->vlan & VLAN_VID_MASK) | - V_L2T_W_PRIO(vlan_prio(e))); - memcpy(e->dmac, e->neigh->ha, sizeof(e->dmac)); - memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac)); - skb->priority = CPL_PRIORITY_CONTROL; - cxgb3_ofld_send(dev, skb); - - skb_queue_walk_safe(&e->arpq, skb, tmp) { - __skb_unlink(skb, &e->arpq); - cxgb3_ofld_send(dev, skb); - } - e->state = L2T_STATE_VALID; - - return 0; -} - -/* - * Add a packet to the an L2T entry's queue of packets awaiting resolution. - * Must be called with the entry's lock held. - */ -static inline void arpq_enqueue(struct l2t_entry *e, struct sk_buff *skb) -{ - __skb_queue_tail(&e->arpq, skb); -} - -int t3_l2t_send_slow(struct t3cdev *dev, struct sk_buff *skb, - struct l2t_entry *e) -{ -again: - switch (e->state) { - case L2T_STATE_STALE: /* entry is stale, kick off revalidation */ - neigh_event_send(e->neigh, NULL); - spin_lock_bh(&e->lock); - if (e->state == L2T_STATE_STALE) - e->state = L2T_STATE_VALID; - spin_unlock_bh(&e->lock); - case L2T_STATE_VALID: /* fast-path, send the packet on */ - return cxgb3_ofld_send(dev, skb); - case L2T_STATE_RESOLVING: - spin_lock_bh(&e->lock); - if (e->state != L2T_STATE_RESOLVING) { - /* ARP already completed */ - spin_unlock_bh(&e->lock); - goto again; - } - arpq_enqueue(e, skb); - spin_unlock_bh(&e->lock); - - /* - * Only the first packet added to the arpq should kick off - * resolution. However, because the alloc_skb below can fail, - * we allow each packet added to the arpq to retry resolution - * as a way of recovering from transient memory exhaustion. - * A better way would be to use a work request to retry L2T - * entries when there's no memory. - */ - if (!neigh_event_send(e->neigh, NULL)) { - skb = alloc_skb(sizeof(struct cpl_l2t_write_req), - GFP_ATOMIC); - if (!skb) - break; - - spin_lock_bh(&e->lock); - if (!skb_queue_empty(&e->arpq)) - setup_l2e_send_pending(dev, skb, e); - else /* we lost the race */ - __kfree_skb(skb); - spin_unlock_bh(&e->lock); - } - } - return 0; -} - -EXPORT_SYMBOL(t3_l2t_send_slow); - -void t3_l2t_send_event(struct t3cdev *dev, struct l2t_entry *e) -{ -again: - switch (e->state) { - case L2T_STATE_STALE: /* entry is stale, kick off revalidation */ - neigh_event_send(e->neigh, NULL); - spin_lock_bh(&e->lock); - if (e->state == L2T_STATE_STALE) { - e->state = L2T_STATE_VALID; - } - spin_unlock_bh(&e->lock); - return; - case L2T_STATE_VALID: /* fast-path, send the packet on */ - return; - case L2T_STATE_RESOLVING: - spin_lock_bh(&e->lock); - if (e->state != L2T_STATE_RESOLVING) { - /* ARP already completed */ - spin_unlock_bh(&e->lock); - goto again; - } - spin_unlock_bh(&e->lock); - - /* - * Only the first packet added to the arpq should kick off - * resolution. However, because the alloc_skb below can fail, - * we allow each packet added to the arpq to retry resolution - * as a way of recovering from transient memory exhaustion. - * A better way would be to use a work request to retry L2T - * entries when there's no memory. - */ - neigh_event_send(e->neigh, NULL); - } -} - -EXPORT_SYMBOL(t3_l2t_send_event); - -/* - * Allocate a free L2T entry. Must be called with l2t_data.lock held. - */ -static struct l2t_entry *alloc_l2e(struct l2t_data *d) -{ - struct l2t_entry *end, *e, **p; - - if (!atomic_read(&d->nfree)) - return NULL; - - /* there's definitely a free entry */ - for (e = d->rover, end = &d->l2tab[d->nentries]; e != end; ++e) - if (atomic_read(&e->refcnt) == 0) - goto found; - - for (e = &d->l2tab[1]; atomic_read(&e->refcnt); ++e) ; -found: - d->rover = e + 1; - atomic_dec(&d->nfree); - - /* - * The entry we found may be an inactive entry that is - * presently in the hash table. We need to remove it. - */ - if (e->state != L2T_STATE_UNUSED) { - int hash = arp_hash(e->addr, e->ifindex, d); - - for (p = &d->l2tab[hash].first; *p; p = &(*p)->next) - if (*p == e) { - *p = e->next; - break; - } - e->state = L2T_STATE_UNUSED; - } - return e; -} - -/* - * Called when an L2T entry has no more users. The entry is left in the hash - * table since it is likely to be reused but we also bump nfree to indicate - * that the entry can be reallocated for a different neighbor. We also drop - * the existing neighbor reference in case the neighbor is going away and is - * waiting on our reference. - * - * Because entries can be reallocated to other neighbors once their ref count - * drops to 0 we need to take the entry's lock to avoid races with a new - * incarnation. - */ -void t3_l2e_free(struct l2t_data *d, struct l2t_entry *e) -{ - spin_lock_bh(&e->lock); - if (atomic_read(&e->refcnt) == 0) { /* hasn't been recycled */ - if (e->neigh) { - neigh_release(e->neigh); - e->neigh = NULL; - } - } - spin_unlock_bh(&e->lock); - atomic_inc(&d->nfree); -} - -EXPORT_SYMBOL(t3_l2e_free); - -/* - * Update an L2T entry that was previously used for the same next hop as neigh. - * Must be called with softirqs disabled. - */ -static inline void reuse_entry(struct l2t_entry *e, struct neighbour *neigh) -{ - unsigned int nud_state; - - spin_lock(&e->lock); /* avoid race with t3_l2t_free */ - - if (neigh != e->neigh) - neigh_replace(e, neigh); - nud_state = neigh->nud_state; - if (memcmp(e->dmac, neigh->ha, sizeof(e->dmac)) || - !(nud_state & NUD_VALID)) - e->state = L2T_STATE_RESOLVING; - else if (nud_state & NUD_CONNECTED) - e->state = L2T_STATE_VALID; - else - e->state = L2T_STATE_STALE; - spin_unlock(&e->lock); -} - -struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh, - struct net_device *dev) -{ - struct l2t_entry *e; - struct l2t_data *d = L2DATA(cdev); - u32 addr = *(u32 *) neigh->primary_key; - int ifidx = neigh->dev->ifindex; - int hash = arp_hash(addr, ifidx, d); - struct port_info *p = netdev_priv(dev); - int smt_idx = p->port_id; - - write_lock_bh(&d->lock); - for (e = d->l2tab[hash].first; e; e = e->next) - if (e->addr == addr && e->ifindex == ifidx && - e->smt_idx == smt_idx) { - l2t_hold(d, e); - if (atomic_read(&e->refcnt) == 1) - reuse_entry(e, neigh); - goto done; - } - - /* Need to allocate a new entry */ - e = alloc_l2e(d); - if (e) { - spin_lock(&e->lock); /* avoid race with t3_l2t_free */ - e->next = d->l2tab[hash].first; - d->l2tab[hash].first = e; - e->state = L2T_STATE_RESOLVING; - e->addr = addr; - e->ifindex = ifidx; - e->smt_idx = smt_idx; - atomic_set(&e->refcnt, 1); - neigh_replace(e, neigh); - if (neigh->dev->priv_flags & IFF_802_1Q_VLAN) - e->vlan = vlan_dev_vlan_id(neigh->dev); - else - e->vlan = VLAN_NONE; - spin_unlock(&e->lock); - } -done: - write_unlock_bh(&d->lock); - return e; -} - -EXPORT_SYMBOL(t3_l2t_get); - -/* - * Called when address resolution fails for an L2T entry to handle packets - * on the arpq head. If a packet specifies a failure handler it is invoked, - * otherwise the packets is sent to the offload device. - * - * XXX: maybe we should abandon the latter behavior and just require a failure - * handler. - */ -static void handle_failed_resolution(struct t3cdev *dev, struct sk_buff_head *arpq) -{ - struct sk_buff *skb, *tmp; - - skb_queue_walk_safe(arpq, skb, tmp) { - struct l2t_skb_cb *cb = L2T_SKB_CB(skb); - - __skb_unlink(skb, arpq); - if (cb->arp_failure_handler) - cb->arp_failure_handler(dev, skb); - else - cxgb3_ofld_send(dev, skb); - } -} - -/* - * Called when the host's ARP layer makes a change to some entry that is - * loaded into the HW L2 table. - */ -void t3_l2t_update(struct t3cdev *dev, struct neighbour *neigh) -{ - struct sk_buff_head arpq; - struct l2t_entry *e; - struct l2t_data *d = L2DATA(dev); - u32 addr = *(u32 *) neigh->primary_key; - int ifidx = neigh->dev->ifindex; - int hash = arp_hash(addr, ifidx, d); - - read_lock_bh(&d->lock); - for (e = d->l2tab[hash].first; e; e = e->next) - if (e->addr == addr && e->ifindex == ifidx) { - spin_lock(&e->lock); - goto found; - } - read_unlock_bh(&d->lock); - return; - -found: - __skb_queue_head_init(&arpq); - - read_unlock(&d->lock); - if (atomic_read(&e->refcnt)) { - if (neigh != e->neigh) - neigh_replace(e, neigh); - - if (e->state == L2T_STATE_RESOLVING) { - if (neigh->nud_state & NUD_FAILED) { - skb_queue_splice_init(&e->arpq, &arpq); - } else if (neigh->nud_state & (NUD_CONNECTED|NUD_STALE)) - setup_l2e_send_pending(dev, NULL, e); - } else { - e->state = neigh->nud_state & NUD_CONNECTED ? - L2T_STATE_VALID : L2T_STATE_STALE; - if (memcmp(e->dmac, neigh->ha, 6)) - setup_l2e_send_pending(dev, NULL, e); - } - } - spin_unlock_bh(&e->lock); - - if (!skb_queue_empty(&arpq)) - handle_failed_resolution(dev, &arpq); -} - -struct l2t_data *t3_init_l2t(unsigned int l2t_capacity) -{ - struct l2t_data *d; - int i, size = sizeof(*d) + l2t_capacity * sizeof(struct l2t_entry); - - d = cxgb_alloc_mem(size); - if (!d) - return NULL; - - d->nentries = l2t_capacity; - d->rover = &d->l2tab[1]; /* entry 0 is not used */ - atomic_set(&d->nfree, l2t_capacity - 1); - rwlock_init(&d->lock); - - for (i = 0; i < l2t_capacity; ++i) { - d->l2tab[i].idx = i; - d->l2tab[i].state = L2T_STATE_UNUSED; - __skb_queue_head_init(&d->l2tab[i].arpq); - spin_lock_init(&d->l2tab[i].lock); - atomic_set(&d->l2tab[i].refcnt, 0); - } - return d; -} - -void t3_free_l2t(struct l2t_data *d) -{ - cxgb_free_mem(d); -} - diff --git a/drivers/net/cxgb3/l2t.h b/drivers/net/cxgb3/l2t.h deleted file mode 100644 index 7a12d52ed4fc..000000000000 --- a/drivers/net/cxgb3/l2t.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _CHELSIO_L2T_H -#define _CHELSIO_L2T_H - -#include -#include "t3cdev.h" -#include - -enum { - L2T_STATE_VALID, /* entry is up to date */ - L2T_STATE_STALE, /* entry may be used but needs revalidation */ - L2T_STATE_RESOLVING, /* entry needs address resolution */ - L2T_STATE_UNUSED /* entry not in use */ -}; - -struct neighbour; -struct sk_buff; - -/* - * Each L2T entry plays multiple roles. First of all, it keeps state for the - * corresponding entry of the HW L2 table and maintains a queue of offload - * packets awaiting address resolution. Second, it is a node of a hash table - * chain, where the nodes of the chain are linked together through their next - * pointer. Finally, each node is a bucket of a hash table, pointing to the - * first element in its chain through its first pointer. - */ -struct l2t_entry { - u16 state; /* entry state */ - u16 idx; /* entry index */ - u32 addr; /* dest IP address */ - int ifindex; /* neighbor's net_device's ifindex */ - u16 smt_idx; /* SMT index */ - u16 vlan; /* VLAN TCI (id: bits 0-11, prio: 13-15 */ - struct neighbour *neigh; /* associated neighbour */ - struct l2t_entry *first; /* start of hash chain */ - struct l2t_entry *next; /* next l2t_entry on chain */ - struct sk_buff_head arpq; /* queue of packets awaiting resolution */ - spinlock_t lock; - atomic_t refcnt; /* entry reference count */ - u8 dmac[6]; /* neighbour's MAC address */ -}; - -struct l2t_data { - unsigned int nentries; /* number of entries */ - struct l2t_entry *rover; /* starting point for next allocation */ - atomic_t nfree; /* number of free entries */ - rwlock_t lock; - struct l2t_entry l2tab[0]; -}; - -typedef void (*arp_failure_handler_func)(struct t3cdev * dev, - struct sk_buff * skb); - -/* - * Callback stored in an skb to handle address resolution failure. - */ -struct l2t_skb_cb { - arp_failure_handler_func arp_failure_handler; -}; - -#define L2T_SKB_CB(skb) ((struct l2t_skb_cb *)(skb)->cb) - -static inline void set_arp_failure_handler(struct sk_buff *skb, - arp_failure_handler_func hnd) -{ - L2T_SKB_CB(skb)->arp_failure_handler = hnd; -} - -/* - * Getting to the L2 data from an offload device. - */ -#define L2DATA(dev) ((dev)->l2opt) - -#define W_TCB_L2T_IX 0 -#define S_TCB_L2T_IX 7 -#define M_TCB_L2T_IX 0x7ffULL -#define V_TCB_L2T_IX(x) ((x) << S_TCB_L2T_IX) - -void t3_l2e_free(struct l2t_data *d, struct l2t_entry *e); -void t3_l2t_update(struct t3cdev *dev, struct neighbour *neigh); -struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh, - struct net_device *dev); -int t3_l2t_send_slow(struct t3cdev *dev, struct sk_buff *skb, - struct l2t_entry *e); -void t3_l2t_send_event(struct t3cdev *dev, struct l2t_entry *e); -struct l2t_data *t3_init_l2t(unsigned int l2t_capacity); -void t3_free_l2t(struct l2t_data *d); - -int cxgb3_ofld_send(struct t3cdev *dev, struct sk_buff *skb); - -static inline int l2t_send(struct t3cdev *dev, struct sk_buff *skb, - struct l2t_entry *e) -{ - if (likely(e->state == L2T_STATE_VALID)) - return cxgb3_ofld_send(dev, skb); - return t3_l2t_send_slow(dev, skb, e); -} - -static inline void l2t_release(struct l2t_data *d, struct l2t_entry *e) -{ - if (atomic_dec_and_test(&e->refcnt)) - t3_l2e_free(d, e); -} - -static inline void l2t_hold(struct l2t_data *d, struct l2t_entry *e) -{ - if (atomic_add_return(1, &e->refcnt) == 1) /* 0 -> 1 transition */ - atomic_dec(&d->nfree); -} - -#endif diff --git a/drivers/net/cxgb3/mc5.c b/drivers/net/cxgb3/mc5.c deleted file mode 100644 index e13b7fe9d082..000000000000 --- a/drivers/net/cxgb3/mc5.c +++ /dev/null @@ -1,438 +0,0 @@ -/* - * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#include "common.h" -#include "regs.h" - -enum { - IDT75P52100 = 4, - IDT75N43102 = 5 -}; - -/* DBGI command mode */ -enum { - DBGI_MODE_MBUS = 0, - DBGI_MODE_IDT52100 = 5 -}; - -/* IDT 75P52100 commands */ -#define IDT_CMD_READ 0 -#define IDT_CMD_WRITE 1 -#define IDT_CMD_SEARCH 2 -#define IDT_CMD_LEARN 3 - -/* IDT LAR register address and value for 144-bit mode (low 32 bits) */ -#define IDT_LAR_ADR0 0x180006 -#define IDT_LAR_MODE144 0xffff0000 - -/* IDT SCR and SSR addresses (low 32 bits) */ -#define IDT_SCR_ADR0 0x180000 -#define IDT_SSR0_ADR0 0x180002 -#define IDT_SSR1_ADR0 0x180004 - -/* IDT GMR base address (low 32 bits) */ -#define IDT_GMR_BASE_ADR0 0x180020 - -/* IDT data and mask array base addresses (low 32 bits) */ -#define IDT_DATARY_BASE_ADR0 0 -#define IDT_MSKARY_BASE_ADR0 0x80000 - -/* IDT 75N43102 commands */ -#define IDT4_CMD_SEARCH144 3 -#define IDT4_CMD_WRITE 4 -#define IDT4_CMD_READ 5 - -/* IDT 75N43102 SCR address (low 32 bits) */ -#define IDT4_SCR_ADR0 0x3 - -/* IDT 75N43102 GMR base addresses (low 32 bits) */ -#define IDT4_GMR_BASE0 0x10 -#define IDT4_GMR_BASE1 0x20 -#define IDT4_GMR_BASE2 0x30 - -/* IDT 75N43102 data and mask array base addresses (low 32 bits) */ -#define IDT4_DATARY_BASE_ADR0 0x1000000 -#define IDT4_MSKARY_BASE_ADR0 0x2000000 - -#define MAX_WRITE_ATTEMPTS 5 - -#define MAX_ROUTES 2048 - -/* - * Issue a command to the TCAM and wait for its completion. The address and - * any data required by the command must have been setup by the caller. - */ -static int mc5_cmd_write(struct adapter *adapter, u32 cmd) -{ - t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_CMD, cmd); - return t3_wait_op_done(adapter, A_MC5_DB_DBGI_RSP_STATUS, - F_DBGIRSPVALID, 1, MAX_WRITE_ATTEMPTS, 1); -} - -static inline void dbgi_wr_addr3(struct adapter *adapter, u32 v1, u32 v2, - u32 v3) -{ - t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR0, v1); - t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR1, v2); - t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR2, v3); -} - -static inline void dbgi_wr_data3(struct adapter *adapter, u32 v1, u32 v2, - u32 v3) -{ - t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA0, v1); - t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA1, v2); - t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA2, v3); -} - -static inline void dbgi_rd_rsp3(struct adapter *adapter, u32 *v1, u32 *v2, - u32 *v3) -{ - *v1 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA0); - *v2 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA1); - *v3 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA2); -} - -/* - * Write data to the TCAM register at address (0, 0, addr_lo) using the TCAM - * command cmd. The data to be written must have been set up by the caller. - * Returns -1 on failure, 0 on success. - */ -static int mc5_write(struct adapter *adapter, u32 addr_lo, u32 cmd) -{ - t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR0, addr_lo); - if (mc5_cmd_write(adapter, cmd) == 0) - return 0; - CH_ERR(adapter, "MC5 timeout writing to TCAM address 0x%x\n", - addr_lo); - return -1; -} - -static int init_mask_data_array(struct mc5 *mc5, u32 mask_array_base, - u32 data_array_base, u32 write_cmd, - int addr_shift) -{ - unsigned int i; - struct adapter *adap = mc5->adapter; - - /* - * We need the size of the TCAM data and mask arrays in terms of - * 72-bit entries. - */ - unsigned int size72 = mc5->tcam_size; - unsigned int server_base = t3_read_reg(adap, A_MC5_DB_SERVER_INDEX); - - if (mc5->mode == MC5_MODE_144_BIT) { - size72 *= 2; /* 1 144-bit entry is 2 72-bit entries */ - server_base *= 2; - } - - /* Clear the data array */ - dbgi_wr_data3(adap, 0, 0, 0); - for (i = 0; i < size72; i++) - if (mc5_write(adap, data_array_base + (i << addr_shift), - write_cmd)) - 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); - if (mc5_write(adap, mask_array_base + (i << addr_shift), - write_cmd)) - return -1; - } - return 0; -} - -static int init_idt52100(struct mc5 *mc5) -{ - int i; - struct adapter *adap = mc5->adapter; - - t3_write_reg(adap, A_MC5_DB_RSP_LATENCY, - V_RDLAT(0x15) | V_LRNLAT(0x15) | V_SRCHLAT(0x15)); - t3_write_reg(adap, A_MC5_DB_PART_ID_INDEX, 2); - - /* - * Use GMRs 14-15 for ELOOKUP, GMRs 12-13 for SYN lookups, and - * GMRs 8-9 for ACK- and AOPEN searches. - */ - t3_write_reg(adap, A_MC5_DB_POPEN_DATA_WR_CMD, IDT_CMD_WRITE); - t3_write_reg(adap, A_MC5_DB_POPEN_MASK_WR_CMD, IDT_CMD_WRITE); - t3_write_reg(adap, A_MC5_DB_AOPEN_SRCH_CMD, IDT_CMD_SEARCH); - t3_write_reg(adap, A_MC5_DB_AOPEN_LRN_CMD, IDT_CMD_LEARN); - t3_write_reg(adap, A_MC5_DB_SYN_SRCH_CMD, IDT_CMD_SEARCH | 0x6000); - t3_write_reg(adap, A_MC5_DB_SYN_LRN_CMD, IDT_CMD_LEARN); - t3_write_reg(adap, A_MC5_DB_ACK_SRCH_CMD, IDT_CMD_SEARCH); - t3_write_reg(adap, A_MC5_DB_ACK_LRN_CMD, IDT_CMD_LEARN); - t3_write_reg(adap, A_MC5_DB_ILOOKUP_CMD, IDT_CMD_SEARCH); - t3_write_reg(adap, A_MC5_DB_ELOOKUP_CMD, IDT_CMD_SEARCH | 0x7000); - t3_write_reg(adap, A_MC5_DB_DATA_WRITE_CMD, IDT_CMD_WRITE); - t3_write_reg(adap, A_MC5_DB_DATA_READ_CMD, IDT_CMD_READ); - - /* Set DBGI command mode for IDT TCAM. */ - t3_write_reg(adap, A_MC5_DB_DBGI_CONFIG, DBGI_MODE_IDT52100); - - /* Set up LAR */ - dbgi_wr_data3(adap, IDT_LAR_MODE144, 0, 0); - if (mc5_write(adap, IDT_LAR_ADR0, IDT_CMD_WRITE)) - goto err; - - /* Set up SSRs */ - dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0); - if (mc5_write(adap, IDT_SSR0_ADR0, IDT_CMD_WRITE) || - mc5_write(adap, IDT_SSR1_ADR0, IDT_CMD_WRITE)) - goto err; - - /* Set up GMRs */ - for (i = 0; i < 32; ++i) { - if (i >= 12 && i < 15) - dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff); - else if (i == 15) - dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff); - else - dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff); - - if (mc5_write(adap, IDT_GMR_BASE_ADR0 + i, IDT_CMD_WRITE)) - goto err; - } - - /* Set up SCR */ - dbgi_wr_data3(adap, 1, 0, 0); - if (mc5_write(adap, IDT_SCR_ADR0, IDT_CMD_WRITE)) - goto err; - - return init_mask_data_array(mc5, IDT_MSKARY_BASE_ADR0, - IDT_DATARY_BASE_ADR0, IDT_CMD_WRITE, 0); -err: - return -EIO; -} - -static int init_idt43102(struct mc5 *mc5) -{ - int i; - struct adapter *adap = mc5->adapter; - - t3_write_reg(adap, A_MC5_DB_RSP_LATENCY, - adap->params.rev == 0 ? V_RDLAT(0xd) | V_SRCHLAT(0x11) : - V_RDLAT(0xd) | V_SRCHLAT(0x12)); - - /* - * Use GMRs 24-25 for ELOOKUP, GMRs 20-21 for SYN lookups, and no mask - * for ACK- and AOPEN searches. - */ - t3_write_reg(adap, A_MC5_DB_POPEN_DATA_WR_CMD, IDT4_CMD_WRITE); - t3_write_reg(adap, A_MC5_DB_POPEN_MASK_WR_CMD, IDT4_CMD_WRITE); - t3_write_reg(adap, A_MC5_DB_AOPEN_SRCH_CMD, - IDT4_CMD_SEARCH144 | 0x3800); - t3_write_reg(adap, A_MC5_DB_SYN_SRCH_CMD, IDT4_CMD_SEARCH144); - t3_write_reg(adap, A_MC5_DB_ACK_SRCH_CMD, IDT4_CMD_SEARCH144 | 0x3800); - t3_write_reg(adap, A_MC5_DB_ILOOKUP_CMD, IDT4_CMD_SEARCH144 | 0x3800); - t3_write_reg(adap, A_MC5_DB_ELOOKUP_CMD, IDT4_CMD_SEARCH144 | 0x800); - t3_write_reg(adap, A_MC5_DB_DATA_WRITE_CMD, IDT4_CMD_WRITE); - t3_write_reg(adap, A_MC5_DB_DATA_READ_CMD, IDT4_CMD_READ); - - t3_write_reg(adap, A_MC5_DB_PART_ID_INDEX, 3); - - /* Set DBGI command mode for IDT TCAM. */ - t3_write_reg(adap, A_MC5_DB_DBGI_CONFIG, DBGI_MODE_IDT52100); - - /* Set up GMRs */ - dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff); - for (i = 0; i < 7; ++i) - if (mc5_write(adap, IDT4_GMR_BASE0 + i, IDT4_CMD_WRITE)) - goto err; - - for (i = 0; i < 4; ++i) - if (mc5_write(adap, IDT4_GMR_BASE2 + i, IDT4_CMD_WRITE)) - goto err; - - dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff); - if (mc5_write(adap, IDT4_GMR_BASE1, IDT4_CMD_WRITE) || - mc5_write(adap, IDT4_GMR_BASE1 + 1, IDT4_CMD_WRITE) || - mc5_write(adap, IDT4_GMR_BASE1 + 4, IDT4_CMD_WRITE)) - goto err; - - dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff); - if (mc5_write(adap, IDT4_GMR_BASE1 + 5, IDT4_CMD_WRITE)) - goto err; - - /* Set up SCR */ - dbgi_wr_data3(adap, 0xf0000000, 0, 0); - if (mc5_write(adap, IDT4_SCR_ADR0, IDT4_CMD_WRITE)) - goto err; - - return init_mask_data_array(mc5, IDT4_MSKARY_BASE_ADR0, - IDT4_DATARY_BASE_ADR0, IDT4_CMD_WRITE, 1); -err: - return -EIO; -} - -/* 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); -} - -/* 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); -} - -/* - * Initialization that requires the OS and protocol layers to already - * be initialized goes here. - */ -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; - struct adapter *adap = mc5->adapter; - - if (!tcam_size) - return 0; - - if (nroutes > MAX_ROUTES || nroutes + nservers + nfilters > tcam_size) - return -EINVAL; - - /* 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); - 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; - } - - t3_write_reg(adap, A_MC5_DB_ROUTING_TABLE_INDEX, tcam_size - nroutes); - t3_write_reg(adap, A_MC5_DB_FILTER_TABLE, - tcam_size - nroutes - 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); - - mc5_dbgi_mode_enable(mc5); - - switch (mc5->part_type) { - case IDT75P52100: - err = init_idt52100(mc5); - break; - case IDT75N43102: - err = init_idt43102(mc5); - break; - default: - CH_ERR(adap, "Unsupported TCAM type %d\n", mc5->part_type); - err = -EINVAL; - break; - } - - mc5_dbgi_mode_disable(mc5); - return err; -} - - -#define MC5_INT_FATAL (F_PARITYERR | F_REQQPARERR | F_DISPQPARERR) - -/* - * MC5 interrupt handler - */ -void t3_mc5_intr_handler(struct mc5 *mc5) -{ - struct adapter *adap = mc5->adapter; - u32 cause = t3_read_reg(adap, A_MC5_DB_INT_CAUSE); - - if ((cause & F_PARITYERR) && mc5->parity_enabled) { - CH_ALERT(adap, "MC5 parity error\n"); - mc5->stats.parity_err++; - } - - if (cause & F_REQQPARERR) { - CH_ALERT(adap, "MC5 request queue parity error\n"); - mc5->stats.reqq_parity_err++; - } - - if (cause & F_DISPQPARERR) { - CH_ALERT(adap, "MC5 dispatch queue parity error\n"); - mc5->stats.dispq_parity_err++; - } - - if (cause & F_ACTRGNFULL) - mc5->stats.active_rgn_full++; - if (cause & F_NFASRCHFAIL) - mc5->stats.nfa_srch_err++; - if (cause & F_UNKNOWNCMD) - mc5->stats.unknown_cmd++; - if (cause & F_DELACTEMPTY) - mc5->stats.del_act_empty++; - if (cause & MC5_INT_FATAL) - t3_fatal_err(adap); - - t3_write_reg(adap, A_MC5_DB_INT_CAUSE, cause); -} - -void t3_mc5_prep(struct adapter *adapter, struct mc5 *mc5, int mode) -{ -#define K * 1024 - - static unsigned int tcam_part_size[] = { /* in K 72-bit entries */ - 64 K, 128 K, 256 K, 32 K - }; - -#undef K - - u32 cfg = t3_read_reg(adapter, A_MC5_DB_CONFIG); - - mc5->adapter = adapter; - mc5->mode = (unsigned char)mode; - mc5->part_type = (unsigned char)G_TMTYPE(cfg); - if (cfg & F_TMTYPEHI) - mc5->part_type |= 4; - - mc5->tcam_size = tcam_part_size[G_TMPARTSIZE(cfg)]; - if (mode == MC5_MODE_144_BIT) - mc5->tcam_size /= 2; -} diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h deleted file mode 100644 index 6990f6c65221..000000000000 --- a/drivers/net/cxgb3/regs.h +++ /dev/null @@ -1,2598 +0,0 @@ -#define A_SG_CONTROL 0x0 - -#define S_CONGMODE 29 -#define V_CONGMODE(x) ((x) << S_CONGMODE) -#define F_CONGMODE V_CONGMODE(1U) - -#define S_TNLFLMODE 28 -#define V_TNLFLMODE(x) ((x) << S_TNLFLMODE) -#define F_TNLFLMODE V_TNLFLMODE(1U) - -#define S_FATLPERREN 27 -#define V_FATLPERREN(x) ((x) << S_FATLPERREN) -#define F_FATLPERREN V_FATLPERREN(1U) - -#define S_DROPPKT 20 -#define V_DROPPKT(x) ((x) << S_DROPPKT) -#define F_DROPPKT V_DROPPKT(1U) - -#define S_EGRGENCTRL 19 -#define V_EGRGENCTRL(x) ((x) << S_EGRGENCTRL) -#define F_EGRGENCTRL V_EGRGENCTRL(1U) - -#define S_USERSPACESIZE 14 -#define M_USERSPACESIZE 0x1f -#define V_USERSPACESIZE(x) ((x) << S_USERSPACESIZE) - -#define S_HOSTPAGESIZE 11 -#define M_HOSTPAGESIZE 0x7 -#define V_HOSTPAGESIZE(x) ((x) << S_HOSTPAGESIZE) - -#define S_FLMODE 9 -#define V_FLMODE(x) ((x) << S_FLMODE) -#define F_FLMODE V_FLMODE(1U) - -#define S_PKTSHIFT 6 -#define M_PKTSHIFT 0x7 -#define V_PKTSHIFT(x) ((x) << S_PKTSHIFT) - -#define S_ONEINTMULTQ 5 -#define V_ONEINTMULTQ(x) ((x) << S_ONEINTMULTQ) -#define F_ONEINTMULTQ V_ONEINTMULTQ(1U) - -#define S_BIGENDIANINGRESS 2 -#define V_BIGENDIANINGRESS(x) ((x) << S_BIGENDIANINGRESS) -#define F_BIGENDIANINGRESS V_BIGENDIANINGRESS(1U) - -#define S_ISCSICOALESCING 1 -#define V_ISCSICOALESCING(x) ((x) << S_ISCSICOALESCING) -#define F_ISCSICOALESCING V_ISCSICOALESCING(1U) - -#define S_GLOBALENABLE 0 -#define V_GLOBALENABLE(x) ((x) << S_GLOBALENABLE) -#define F_GLOBALENABLE V_GLOBALENABLE(1U) - -#define S_AVOIDCQOVFL 24 -#define V_AVOIDCQOVFL(x) ((x) << S_AVOIDCQOVFL) -#define F_AVOIDCQOVFL V_AVOIDCQOVFL(1U) - -#define S_OPTONEINTMULTQ 23 -#define V_OPTONEINTMULTQ(x) ((x) << S_OPTONEINTMULTQ) -#define F_OPTONEINTMULTQ V_OPTONEINTMULTQ(1U) - -#define S_CQCRDTCTRL 22 -#define V_CQCRDTCTRL(x) ((x) << S_CQCRDTCTRL) -#define F_CQCRDTCTRL V_CQCRDTCTRL(1U) - -#define A_SG_KDOORBELL 0x4 - -#define S_SELEGRCNTX 31 -#define V_SELEGRCNTX(x) ((x) << S_SELEGRCNTX) -#define F_SELEGRCNTX V_SELEGRCNTX(1U) - -#define S_EGRCNTX 0 -#define M_EGRCNTX 0xffff -#define V_EGRCNTX(x) ((x) << S_EGRCNTX) - -#define A_SG_GTS 0x8 - -#define S_RSPQ 29 -#define M_RSPQ 0x7 -#define V_RSPQ(x) ((x) << S_RSPQ) -#define G_RSPQ(x) (((x) >> S_RSPQ) & M_RSPQ) - -#define S_NEWTIMER 16 -#define M_NEWTIMER 0x1fff -#define V_NEWTIMER(x) ((x) << S_NEWTIMER) - -#define S_NEWINDEX 0 -#define M_NEWINDEX 0xffff -#define V_NEWINDEX(x) ((x) << S_NEWINDEX) - -#define A_SG_CONTEXT_CMD 0xc - -#define S_CONTEXT_CMD_OPCODE 28 -#define M_CONTEXT_CMD_OPCODE 0xf -#define V_CONTEXT_CMD_OPCODE(x) ((x) << S_CONTEXT_CMD_OPCODE) - -#define S_CONTEXT_CMD_BUSY 27 -#define V_CONTEXT_CMD_BUSY(x) ((x) << S_CONTEXT_CMD_BUSY) -#define F_CONTEXT_CMD_BUSY V_CONTEXT_CMD_BUSY(1U) - -#define S_CQ_CREDIT 20 - -#define M_CQ_CREDIT 0x7f - -#define V_CQ_CREDIT(x) ((x) << S_CQ_CREDIT) - -#define G_CQ_CREDIT(x) (((x) >> S_CQ_CREDIT) & M_CQ_CREDIT) - -#define S_CQ 19 - -#define V_CQ(x) ((x) << S_CQ) -#define F_CQ V_CQ(1U) - -#define S_RESPONSEQ 18 -#define V_RESPONSEQ(x) ((x) << S_RESPONSEQ) -#define F_RESPONSEQ V_RESPONSEQ(1U) - -#define S_EGRESS 17 -#define V_EGRESS(x) ((x) << S_EGRESS) -#define F_EGRESS V_EGRESS(1U) - -#define S_FREELIST 16 -#define V_FREELIST(x) ((x) << S_FREELIST) -#define F_FREELIST V_FREELIST(1U) - -#define S_CONTEXT 0 -#define M_CONTEXT 0xffff -#define V_CONTEXT(x) ((x) << S_CONTEXT) - -#define G_CONTEXT(x) (((x) >> S_CONTEXT) & M_CONTEXT) - -#define A_SG_CONTEXT_DATA0 0x10 - -#define A_SG_CONTEXT_DATA1 0x14 - -#define A_SG_CONTEXT_DATA2 0x18 - -#define A_SG_CONTEXT_DATA3 0x1c - -#define A_SG_CONTEXT_MASK0 0x20 - -#define A_SG_CONTEXT_MASK1 0x24 - -#define A_SG_CONTEXT_MASK2 0x28 - -#define A_SG_CONTEXT_MASK3 0x2c - -#define A_SG_RSPQ_CREDIT_RETURN 0x30 - -#define S_CREDITS 0 -#define M_CREDITS 0xffff -#define V_CREDITS(x) ((x) << S_CREDITS) - -#define A_SG_DATA_INTR 0x34 - -#define S_ERRINTR 31 -#define V_ERRINTR(x) ((x) << S_ERRINTR) -#define F_ERRINTR V_ERRINTR(1U) - -#define A_SG_HI_DRB_HI_THRSH 0x38 - -#define A_SG_HI_DRB_LO_THRSH 0x3c - -#define A_SG_LO_DRB_HI_THRSH 0x40 - -#define A_SG_LO_DRB_LO_THRSH 0x44 - -#define A_SG_RSPQ_FL_STATUS 0x4c - -#define S_RSPQ0DISABLED 8 - -#define S_FL0EMPTY 16 -#define V_FL0EMPTY(x) ((x) << S_FL0EMPTY) -#define F_FL0EMPTY V_FL0EMPTY(1U) - -#define A_SG_EGR_RCQ_DRB_THRSH 0x54 - -#define S_HIRCQDRBTHRSH 16 -#define M_HIRCQDRBTHRSH 0x7ff -#define V_HIRCQDRBTHRSH(x) ((x) << S_HIRCQDRBTHRSH) - -#define S_LORCQDRBTHRSH 0 -#define M_LORCQDRBTHRSH 0x7ff -#define V_LORCQDRBTHRSH(x) ((x) << S_LORCQDRBTHRSH) - -#define A_SG_EGR_CNTX_BADDR 0x58 - -#define A_SG_INT_CAUSE 0x5c - -#define S_HIRCQPARITYERROR 31 -#define V_HIRCQPARITYERROR(x) ((x) << S_HIRCQPARITYERROR) -#define F_HIRCQPARITYERROR V_HIRCQPARITYERROR(1U) - -#define S_LORCQPARITYERROR 30 -#define V_LORCQPARITYERROR(x) ((x) << S_LORCQPARITYERROR) -#define F_LORCQPARITYERROR V_LORCQPARITYERROR(1U) - -#define S_HIDRBPARITYERROR 29 -#define V_HIDRBPARITYERROR(x) ((x) << S_HIDRBPARITYERROR) -#define F_HIDRBPARITYERROR V_HIDRBPARITYERROR(1U) - -#define S_LODRBPARITYERROR 28 -#define V_LODRBPARITYERROR(x) ((x) << S_LODRBPARITYERROR) -#define F_LODRBPARITYERROR V_LODRBPARITYERROR(1U) - -#define S_FLPARITYERROR 22 -#define M_FLPARITYERROR 0x3f -#define V_FLPARITYERROR(x) ((x) << S_FLPARITYERROR) -#define G_FLPARITYERROR(x) (((x) >> S_FLPARITYERROR) & M_FLPARITYERROR) - -#define S_ITPARITYERROR 20 -#define M_ITPARITYERROR 0x3 -#define V_ITPARITYERROR(x) ((x) << S_ITPARITYERROR) -#define G_ITPARITYERROR(x) (((x) >> S_ITPARITYERROR) & M_ITPARITYERROR) - -#define S_IRPARITYERROR 19 -#define V_IRPARITYERROR(x) ((x) << S_IRPARITYERROR) -#define F_IRPARITYERROR V_IRPARITYERROR(1U) - -#define S_RCPARITYERROR 18 -#define V_RCPARITYERROR(x) ((x) << S_RCPARITYERROR) -#define F_RCPARITYERROR V_RCPARITYERROR(1U) - -#define S_OCPARITYERROR 17 -#define V_OCPARITYERROR(x) ((x) << S_OCPARITYERROR) -#define F_OCPARITYERROR V_OCPARITYERROR(1U) - -#define S_CPPARITYERROR 16 -#define V_CPPARITYERROR(x) ((x) << S_CPPARITYERROR) -#define F_CPPARITYERROR V_CPPARITYERROR(1U) - -#define S_R_REQ_FRAMINGERROR 15 -#define V_R_REQ_FRAMINGERROR(x) ((x) << S_R_REQ_FRAMINGERROR) -#define F_R_REQ_FRAMINGERROR V_R_REQ_FRAMINGERROR(1U) - -#define S_UC_REQ_FRAMINGERROR 14 -#define V_UC_REQ_FRAMINGERROR(x) ((x) << S_UC_REQ_FRAMINGERROR) -#define F_UC_REQ_FRAMINGERROR V_UC_REQ_FRAMINGERROR(1U) - -#define S_HICTLDRBDROPERR 13 -#define V_HICTLDRBDROPERR(x) ((x) << S_HICTLDRBDROPERR) -#define F_HICTLDRBDROPERR V_HICTLDRBDROPERR(1U) - -#define S_LOCTLDRBDROPERR 12 -#define V_LOCTLDRBDROPERR(x) ((x) << S_LOCTLDRBDROPERR) -#define F_LOCTLDRBDROPERR V_LOCTLDRBDROPERR(1U) - -#define S_HIPIODRBDROPERR 11 -#define V_HIPIODRBDROPERR(x) ((x) << S_HIPIODRBDROPERR) -#define F_HIPIODRBDROPERR V_HIPIODRBDROPERR(1U) - -#define S_LOPIODRBDROPERR 10 -#define V_LOPIODRBDROPERR(x) ((x) << S_LOPIODRBDROPERR) -#define F_LOPIODRBDROPERR V_LOPIODRBDROPERR(1U) - -#define S_HIPRIORITYDBFULL 7 -#define V_HIPRIORITYDBFULL(x) ((x) << S_HIPRIORITYDBFULL) -#define F_HIPRIORITYDBFULL V_HIPRIORITYDBFULL(1U) - -#define S_HIPRIORITYDBEMPTY 6 -#define V_HIPRIORITYDBEMPTY(x) ((x) << S_HIPRIORITYDBEMPTY) -#define F_HIPRIORITYDBEMPTY V_HIPRIORITYDBEMPTY(1U) - -#define S_LOPRIORITYDBFULL 5 -#define V_LOPRIORITYDBFULL(x) ((x) << S_LOPRIORITYDBFULL) -#define F_LOPRIORITYDBFULL V_LOPRIORITYDBFULL(1U) - -#define S_LOPRIORITYDBEMPTY 4 -#define V_LOPRIORITYDBEMPTY(x) ((x) << S_LOPRIORITYDBEMPTY) -#define F_LOPRIORITYDBEMPTY V_LOPRIORITYDBEMPTY(1U) - -#define S_RSPQDISABLED 3 -#define V_RSPQDISABLED(x) ((x) << S_RSPQDISABLED) -#define F_RSPQDISABLED V_RSPQDISABLED(1U) - -#define S_RSPQCREDITOVERFOW 2 -#define V_RSPQCREDITOVERFOW(x) ((x) << S_RSPQCREDITOVERFOW) -#define F_RSPQCREDITOVERFOW V_RSPQCREDITOVERFOW(1U) - -#define S_FLEMPTY 1 -#define V_FLEMPTY(x) ((x) << S_FLEMPTY) -#define F_FLEMPTY V_FLEMPTY(1U) - -#define A_SG_INT_ENABLE 0x60 - -#define A_SG_CMDQ_CREDIT_TH 0x64 - -#define S_TIMEOUT 8 -#define M_TIMEOUT 0xffffff -#define V_TIMEOUT(x) ((x) << S_TIMEOUT) - -#define S_THRESHOLD 0 -#define M_THRESHOLD 0xff -#define V_THRESHOLD(x) ((x) << S_THRESHOLD) - -#define A_SG_TIMER_TICK 0x68 - -#define A_SG_CQ_CONTEXT_BADDR 0x6c - -#define A_SG_OCO_BASE 0x70 - -#define S_BASE1 16 -#define M_BASE1 0xffff -#define V_BASE1(x) ((x) << S_BASE1) - -#define A_SG_DRB_PRI_THRESH 0x74 - -#define A_PCIX_INT_ENABLE 0x80 - -#define S_MSIXPARERR 22 -#define M_MSIXPARERR 0x7 - -#define V_MSIXPARERR(x) ((x) << S_MSIXPARERR) - -#define S_CFPARERR 18 -#define M_CFPARERR 0xf - -#define V_CFPARERR(x) ((x) << S_CFPARERR) - -#define S_RFPARERR 14 -#define M_RFPARERR 0xf - -#define V_RFPARERR(x) ((x) << S_RFPARERR) - -#define S_WFPARERR 12 -#define M_WFPARERR 0x3 - -#define V_WFPARERR(x) ((x) << S_WFPARERR) - -#define S_PIOPARERR 11 -#define V_PIOPARERR(x) ((x) << S_PIOPARERR) -#define F_PIOPARERR V_PIOPARERR(1U) - -#define S_DETUNCECCERR 10 -#define V_DETUNCECCERR(x) ((x) << S_DETUNCECCERR) -#define F_DETUNCECCERR V_DETUNCECCERR(1U) - -#define S_DETCORECCERR 9 -#define V_DETCORECCERR(x) ((x) << S_DETCORECCERR) -#define F_DETCORECCERR V_DETCORECCERR(1U) - -#define S_RCVSPLCMPERR 8 -#define V_RCVSPLCMPERR(x) ((x) << S_RCVSPLCMPERR) -#define F_RCVSPLCMPERR V_RCVSPLCMPERR(1U) - -#define S_UNXSPLCMP 7 -#define V_UNXSPLCMP(x) ((x) << S_UNXSPLCMP) -#define F_UNXSPLCMP V_UNXSPLCMP(1U) - -#define S_SPLCMPDIS 6 -#define V_SPLCMPDIS(x) ((x) << S_SPLCMPDIS) -#define F_SPLCMPDIS V_SPLCMPDIS(1U) - -#define S_DETPARERR 5 -#define V_DETPARERR(x) ((x) << S_DETPARERR) -#define F_DETPARERR V_DETPARERR(1U) - -#define S_SIGSYSERR 4 -#define V_SIGSYSERR(x) ((x) << S_SIGSYSERR) -#define F_SIGSYSERR V_SIGSYSERR(1U) - -#define S_RCVMSTABT 3 -#define V_RCVMSTABT(x) ((x) << S_RCVMSTABT) -#define F_RCVMSTABT V_RCVMSTABT(1U) - -#define S_RCVTARABT 2 -#define V_RCVTARABT(x) ((x) << S_RCVTARABT) -#define F_RCVTARABT V_RCVTARABT(1U) - -#define S_SIGTARABT 1 -#define V_SIGTARABT(x) ((x) << S_SIGTARABT) -#define F_SIGTARABT V_SIGTARABT(1U) - -#define S_MSTDETPARERR 0 -#define V_MSTDETPARERR(x) ((x) << S_MSTDETPARERR) -#define F_MSTDETPARERR V_MSTDETPARERR(1U) - -#define A_PCIX_INT_CAUSE 0x84 - -#define A_PCIX_CFG 0x88 - -#define S_DMASTOPEN 19 -#define V_DMASTOPEN(x) ((x) << S_DMASTOPEN) -#define F_DMASTOPEN V_DMASTOPEN(1U) - -#define S_CLIDECEN 18 -#define V_CLIDECEN(x) ((x) << S_CLIDECEN) -#define F_CLIDECEN V_CLIDECEN(1U) - -#define A_PCIX_MODE 0x8c - -#define S_PCLKRANGE 6 -#define M_PCLKRANGE 0x3 -#define V_PCLKRANGE(x) ((x) << S_PCLKRANGE) -#define G_PCLKRANGE(x) (((x) >> S_PCLKRANGE) & M_PCLKRANGE) - -#define S_PCIXINITPAT 2 -#define M_PCIXINITPAT 0xf -#define V_PCIXINITPAT(x) ((x) << S_PCIXINITPAT) -#define G_PCIXINITPAT(x) (((x) >> S_PCIXINITPAT) & M_PCIXINITPAT) - -#define S_64BIT 0 -#define V_64BIT(x) ((x) << S_64BIT) -#define F_64BIT V_64BIT(1U) - -#define A_PCIE_INT_ENABLE 0x80 - -#define S_BISTERR 15 -#define M_BISTERR 0xff - -#define V_BISTERR(x) ((x) << S_BISTERR) - -#define S_TXPARERR 18 -#define V_TXPARERR(x) ((x) << S_TXPARERR) -#define F_TXPARERR V_TXPARERR(1U) - -#define S_RXPARERR 17 -#define V_RXPARERR(x) ((x) << S_RXPARERR) -#define F_RXPARERR V_RXPARERR(1U) - -#define S_RETRYLUTPARERR 16 -#define V_RETRYLUTPARERR(x) ((x) << S_RETRYLUTPARERR) -#define F_RETRYLUTPARERR V_RETRYLUTPARERR(1U) - -#define S_RETRYBUFPARERR 15 -#define V_RETRYBUFPARERR(x) ((x) << S_RETRYBUFPARERR) -#define F_RETRYBUFPARERR V_RETRYBUFPARERR(1U) - -#define S_PCIE_MSIXPARERR 12 -#define M_PCIE_MSIXPARERR 0x7 - -#define V_PCIE_MSIXPARERR(x) ((x) << S_PCIE_MSIXPARERR) - -#define S_PCIE_CFPARERR 11 -#define V_PCIE_CFPARERR(x) ((x) << S_PCIE_CFPARERR) -#define F_PCIE_CFPARERR V_PCIE_CFPARERR(1U) - -#define S_PCIE_RFPARERR 10 -#define V_PCIE_RFPARERR(x) ((x) << S_PCIE_RFPARERR) -#define F_PCIE_RFPARERR V_PCIE_RFPARERR(1U) - -#define S_PCIE_WFPARERR 9 -#define V_PCIE_WFPARERR(x) ((x) << S_PCIE_WFPARERR) -#define F_PCIE_WFPARERR V_PCIE_WFPARERR(1U) - -#define S_PCIE_PIOPARERR 8 -#define V_PCIE_PIOPARERR(x) ((x) << S_PCIE_PIOPARERR) -#define F_PCIE_PIOPARERR V_PCIE_PIOPARERR(1U) - -#define S_UNXSPLCPLERRC 7 -#define V_UNXSPLCPLERRC(x) ((x) << S_UNXSPLCPLERRC) -#define F_UNXSPLCPLERRC V_UNXSPLCPLERRC(1U) - -#define S_UNXSPLCPLERRR 6 -#define V_UNXSPLCPLERRR(x) ((x) << S_UNXSPLCPLERRR) -#define F_UNXSPLCPLERRR V_UNXSPLCPLERRR(1U) - -#define S_PEXERR 0 -#define V_PEXERR(x) ((x) << S_PEXERR) -#define F_PEXERR V_PEXERR(1U) - -#define A_PCIE_INT_CAUSE 0x84 - -#define S_PCIE_DMASTOPEN 24 -#define V_PCIE_DMASTOPEN(x) ((x) << S_PCIE_DMASTOPEN) -#define F_PCIE_DMASTOPEN V_PCIE_DMASTOPEN(1U) - -#define A_PCIE_CFG 0x88 - -#define S_ENABLELINKDWNDRST 21 -#define V_ENABLELINKDWNDRST(x) ((x) << S_ENABLELINKDWNDRST) -#define F_ENABLELINKDWNDRST V_ENABLELINKDWNDRST(1U) - -#define S_ENABLELINKDOWNRST 20 -#define V_ENABLELINKDOWNRST(x) ((x) << S_ENABLELINKDOWNRST) -#define F_ENABLELINKDOWNRST V_ENABLELINKDOWNRST(1U) - -#define S_PCIE_CLIDECEN 16 -#define V_PCIE_CLIDECEN(x) ((x) << S_PCIE_CLIDECEN) -#define F_PCIE_CLIDECEN V_PCIE_CLIDECEN(1U) - -#define S_CRSTWRMMODE 0 -#define V_CRSTWRMMODE(x) ((x) << S_CRSTWRMMODE) -#define F_CRSTWRMMODE V_CRSTWRMMODE(1U) - -#define A_PCIE_MODE 0x8c - -#define S_NUMFSTTRNSEQRX 10 -#define M_NUMFSTTRNSEQRX 0xff -#define V_NUMFSTTRNSEQRX(x) ((x) << S_NUMFSTTRNSEQRX) -#define G_NUMFSTTRNSEQRX(x) (((x) >> S_NUMFSTTRNSEQRX) & M_NUMFSTTRNSEQRX) - -#define A_PCIE_PEX_CTRL0 0x98 - -#define S_NUMFSTTRNSEQ 22 -#define M_NUMFSTTRNSEQ 0xff -#define V_NUMFSTTRNSEQ(x) ((x) << S_NUMFSTTRNSEQ) -#define G_NUMFSTTRNSEQ(x) (((x) >> S_NUMFSTTRNSEQ) & M_NUMFSTTRNSEQ) - -#define S_REPLAYLMT 2 -#define M_REPLAYLMT 0xfffff - -#define V_REPLAYLMT(x) ((x) << S_REPLAYLMT) - -#define A_PCIE_PEX_CTRL1 0x9c - -#define S_T3A_ACKLAT 0 -#define M_T3A_ACKLAT 0x7ff - -#define V_T3A_ACKLAT(x) ((x) << S_T3A_ACKLAT) - -#define S_ACKLAT 0 -#define M_ACKLAT 0x1fff - -#define V_ACKLAT(x) ((x) << S_ACKLAT) - -#define A_PCIE_PEX_ERR 0xa4 - -#define A_T3DBG_GPIO_EN 0xd0 - -#define S_GPIO11_OEN 27 -#define V_GPIO11_OEN(x) ((x) << S_GPIO11_OEN) -#define F_GPIO11_OEN V_GPIO11_OEN(1U) - -#define S_GPIO10_OEN 26 -#define V_GPIO10_OEN(x) ((x) << S_GPIO10_OEN) -#define F_GPIO10_OEN V_GPIO10_OEN(1U) - -#define S_GPIO7_OEN 23 -#define V_GPIO7_OEN(x) ((x) << S_GPIO7_OEN) -#define F_GPIO7_OEN V_GPIO7_OEN(1U) - -#define S_GPIO6_OEN 22 -#define V_GPIO6_OEN(x) ((x) << S_GPIO6_OEN) -#define F_GPIO6_OEN V_GPIO6_OEN(1U) - -#define S_GPIO5_OEN 21 -#define V_GPIO5_OEN(x) ((x) << S_GPIO5_OEN) -#define F_GPIO5_OEN V_GPIO5_OEN(1U) - -#define S_GPIO4_OEN 20 -#define V_GPIO4_OEN(x) ((x) << S_GPIO4_OEN) -#define F_GPIO4_OEN V_GPIO4_OEN(1U) - -#define S_GPIO2_OEN 18 -#define V_GPIO2_OEN(x) ((x) << S_GPIO2_OEN) -#define F_GPIO2_OEN V_GPIO2_OEN(1U) - -#define S_GPIO1_OEN 17 -#define V_GPIO1_OEN(x) ((x) << S_GPIO1_OEN) -#define F_GPIO1_OEN V_GPIO1_OEN(1U) - -#define S_GPIO0_OEN 16 -#define V_GPIO0_OEN(x) ((x) << S_GPIO0_OEN) -#define F_GPIO0_OEN V_GPIO0_OEN(1U) - -#define S_GPIO10_OUT_VAL 10 -#define V_GPIO10_OUT_VAL(x) ((x) << S_GPIO10_OUT_VAL) -#define F_GPIO10_OUT_VAL V_GPIO10_OUT_VAL(1U) - -#define S_GPIO7_OUT_VAL 7 -#define V_GPIO7_OUT_VAL(x) ((x) << S_GPIO7_OUT_VAL) -#define F_GPIO7_OUT_VAL V_GPIO7_OUT_VAL(1U) - -#define S_GPIO6_OUT_VAL 6 -#define V_GPIO6_OUT_VAL(x) ((x) << S_GPIO6_OUT_VAL) -#define F_GPIO6_OUT_VAL V_GPIO6_OUT_VAL(1U) - -#define S_GPIO5_OUT_VAL 5 -#define V_GPIO5_OUT_VAL(x) ((x) << S_GPIO5_OUT_VAL) -#define F_GPIO5_OUT_VAL V_GPIO5_OUT_VAL(1U) - -#define S_GPIO4_OUT_VAL 4 -#define V_GPIO4_OUT_VAL(x) ((x) << S_GPIO4_OUT_VAL) -#define F_GPIO4_OUT_VAL V_GPIO4_OUT_VAL(1U) - -#define S_GPIO2_OUT_VAL 2 -#define V_GPIO2_OUT_VAL(x) ((x) << S_GPIO2_OUT_VAL) -#define F_GPIO2_OUT_VAL V_GPIO2_OUT_VAL(1U) - -#define S_GPIO1_OUT_VAL 1 -#define V_GPIO1_OUT_VAL(x) ((x) << S_GPIO1_OUT_VAL) -#define F_GPIO1_OUT_VAL V_GPIO1_OUT_VAL(1U) - -#define S_GPIO0_OUT_VAL 0 -#define V_GPIO0_OUT_VAL(x) ((x) << S_GPIO0_OUT_VAL) -#define F_GPIO0_OUT_VAL V_GPIO0_OUT_VAL(1U) - -#define A_T3DBG_INT_ENABLE 0xd8 - -#define S_GPIO11 11 -#define V_GPIO11(x) ((x) << S_GPIO11) -#define F_GPIO11 V_GPIO11(1U) - -#define S_GPIO10 10 -#define V_GPIO10(x) ((x) << S_GPIO10) -#define F_GPIO10 V_GPIO10(1U) - -#define S_GPIO9 9 -#define V_GPIO9(x) ((x) << S_GPIO9) -#define F_GPIO9 V_GPIO9(1U) - -#define S_GPIO7 7 -#define V_GPIO7(x) ((x) << S_GPIO7) -#define F_GPIO7 V_GPIO7(1U) - -#define S_GPIO6 6 -#define V_GPIO6(x) ((x) << S_GPIO6) -#define F_GPIO6 V_GPIO6(1U) - -#define S_GPIO5 5 -#define V_GPIO5(x) ((x) << S_GPIO5) -#define F_GPIO5 V_GPIO5(1U) - -#define S_GPIO4 4 -#define V_GPIO4(x) ((x) << S_GPIO4) -#define F_GPIO4 V_GPIO4(1U) - -#define S_GPIO3 3 -#define V_GPIO3(x) ((x) << S_GPIO3) -#define F_GPIO3 V_GPIO3(1U) - -#define S_GPIO2 2 -#define V_GPIO2(x) ((x) << S_GPIO2) -#define F_GPIO2 V_GPIO2(1U) - -#define S_GPIO1 1 -#define V_GPIO1(x) ((x) << S_GPIO1) -#define F_GPIO1 V_GPIO1(1U) - -#define S_GPIO0 0 -#define V_GPIO0(x) ((x) << S_GPIO0) -#define F_GPIO0 V_GPIO0(1U) - -#define A_T3DBG_INT_CAUSE 0xdc - -#define A_T3DBG_GPIO_ACT_LOW 0xf0 - -#define MC7_PMRX_BASE_ADDR 0x100 - -#define A_MC7_CFG 0x100 - -#define S_IFEN 13 -#define V_IFEN(x) ((x) << S_IFEN) -#define F_IFEN V_IFEN(1U) - -#define S_TERM150 11 -#define V_TERM150(x) ((x) << S_TERM150) -#define F_TERM150 V_TERM150(1U) - -#define S_SLOW 10 -#define V_SLOW(x) ((x) << S_SLOW) -#define F_SLOW V_SLOW(1U) - -#define S_WIDTH 8 -#define M_WIDTH 0x3 -#define V_WIDTH(x) ((x) << S_WIDTH) -#define G_WIDTH(x) (((x) >> S_WIDTH) & M_WIDTH) - -#define S_BKS 6 -#define V_BKS(x) ((x) << S_BKS) -#define F_BKS V_BKS(1U) - -#define S_ORG 5 -#define V_ORG(x) ((x) << S_ORG) -#define F_ORG V_ORG(1U) - -#define S_DEN 2 -#define M_DEN 0x7 -#define V_DEN(x) ((x) << S_DEN) -#define G_DEN(x) (((x) >> S_DEN) & M_DEN) - -#define S_RDY 1 -#define V_RDY(x) ((x) << S_RDY) -#define F_RDY V_RDY(1U) - -#define S_CLKEN 0 -#define V_CLKEN(x) ((x) << S_CLKEN) -#define F_CLKEN V_CLKEN(1U) - -#define A_MC7_MODE 0x104 - -#define S_BUSY 31 -#define V_BUSY(x) ((x) << S_BUSY) -#define F_BUSY V_BUSY(1U) - -#define S_BUSY 31 -#define V_BUSY(x) ((x) << S_BUSY) -#define F_BUSY V_BUSY(1U) - -#define A_MC7_EXT_MODE1 0x108 - -#define A_MC7_EXT_MODE2 0x10c - -#define A_MC7_EXT_MODE3 0x110 - -#define A_MC7_PRE 0x114 - -#define A_MC7_REF 0x118 - -#define S_PREREFDIV 1 -#define M_PREREFDIV 0x3fff -#define V_PREREFDIV(x) ((x) << S_PREREFDIV) - -#define S_PERREFEN 0 -#define V_PERREFEN(x) ((x) << S_PERREFEN) -#define F_PERREFEN V_PERREFEN(1U) - -#define A_MC7_DLL 0x11c - -#define S_DLLENB 1 -#define V_DLLENB(x) ((x) << S_DLLENB) -#define F_DLLENB V_DLLENB(1U) - -#define S_DLLRST 0 -#define V_DLLRST(x) ((x) << S_DLLRST) -#define F_DLLRST V_DLLRST(1U) - -#define A_MC7_PARM 0x120 - -#define S_ACTTOPREDLY 26 -#define M_ACTTOPREDLY 0xf -#define V_ACTTOPREDLY(x) ((x) << S_ACTTOPREDLY) - -#define S_ACTTORDWRDLY 23 -#define M_ACTTORDWRDLY 0x7 -#define V_ACTTORDWRDLY(x) ((x) << S_ACTTORDWRDLY) - -#define S_PRECYC 20 -#define M_PRECYC 0x7 -#define V_PRECYC(x) ((x) << S_PRECYC) - -#define S_REFCYC 13 -#define M_REFCYC 0x7f -#define V_REFCYC(x) ((x) << S_REFCYC) - -#define S_BKCYC 8 -#define M_BKCYC 0x1f -#define V_BKCYC(x) ((x) << S_BKCYC) - -#define S_WRTORDDLY 4 -#define M_WRTORDDLY 0xf -#define V_WRTORDDLY(x) ((x) << S_WRTORDDLY) - -#define S_RDTOWRDLY 0 -#define M_RDTOWRDLY 0xf -#define V_RDTOWRDLY(x) ((x) << S_RDTOWRDLY) - -#define A_MC7_CAL 0x128 - -#define S_BUSY 31 -#define V_BUSY(x) ((x) << S_BUSY) -#define F_BUSY V_BUSY(1U) - -#define S_BUSY 31 -#define V_BUSY(x) ((x) << S_BUSY) -#define F_BUSY V_BUSY(1U) - -#define S_CAL_FAULT 30 -#define V_CAL_FAULT(x) ((x) << S_CAL_FAULT) -#define F_CAL_FAULT V_CAL_FAULT(1U) - -#define S_SGL_CAL_EN 20 -#define V_SGL_CAL_EN(x) ((x) << S_SGL_CAL_EN) -#define F_SGL_CAL_EN V_SGL_CAL_EN(1U) - -#define A_MC7_ERR_ADDR 0x12c - -#define A_MC7_ECC 0x130 - -#define S_ECCCHKEN 1 -#define V_ECCCHKEN(x) ((x) << S_ECCCHKEN) -#define F_ECCCHKEN V_ECCCHKEN(1U) - -#define S_ECCGENEN 0 -#define V_ECCGENEN(x) ((x) << S_ECCGENEN) -#define F_ECCGENEN V_ECCGENEN(1U) - -#define A_MC7_CE_ADDR 0x134 - -#define A_MC7_CE_DATA0 0x138 - -#define A_MC7_CE_DATA1 0x13c - -#define A_MC7_CE_DATA2 0x140 - -#define S_DATA 0 -#define M_DATA 0xff - -#define G_DATA(x) (((x) >> S_DATA) & M_DATA) - -#define A_MC7_UE_ADDR 0x144 - -#define A_MC7_UE_DATA0 0x148 - -#define A_MC7_UE_DATA1 0x14c - -#define A_MC7_UE_DATA2 0x150 - -#define A_MC7_BD_ADDR 0x154 - -#define S_ADDR 3 - -#define M_ADDR 0x1fffffff - -#define A_MC7_BD_DATA0 0x158 - -#define A_MC7_BD_DATA1 0x15c - -#define A_MC7_BD_OP 0x164 - -#define S_OP 0 - -#define V_OP(x) ((x) << S_OP) -#define F_OP V_OP(1U) - -#define F_OP V_OP(1U) -#define A_SF_OP 0x6dc - -#define A_MC7_BIST_ADDR_BEG 0x168 - -#define A_MC7_BIST_ADDR_END 0x16c - -#define A_MC7_BIST_DATA 0x170 - -#define A_MC7_BIST_OP 0x174 - -#define S_CONT 3 -#define V_CONT(x) ((x) << S_CONT) -#define F_CONT V_CONT(1U) - -#define F_CONT V_CONT(1U) - -#define A_MC7_INT_ENABLE 0x178 - -#define S_AE 17 -#define V_AE(x) ((x) << S_AE) -#define F_AE V_AE(1U) - -#define S_PE 2 -#define M_PE 0x7fff - -#define V_PE(x) ((x) << S_PE) - -#define G_PE(x) (((x) >> S_PE) & M_PE) - -#define S_UE 1 -#define V_UE(x) ((x) << S_UE) -#define F_UE V_UE(1U) - -#define S_CE 0 -#define V_CE(x) ((x) << S_CE) -#define F_CE V_CE(1U) - -#define A_MC7_INT_CAUSE 0x17c - -#define MC7_PMTX_BASE_ADDR 0x180 - -#define MC7_CM_BASE_ADDR 0x200 - -#define A_CIM_BOOT_CFG 0x280 - -#define S_BOOTADDR 2 -#define M_BOOTADDR 0x3fffffff -#define V_BOOTADDR(x) ((x) << S_BOOTADDR) - -#define A_CIM_SDRAM_BASE_ADDR 0x28c - -#define A_CIM_SDRAM_ADDR_SIZE 0x290 - -#define A_CIM_HOST_INT_ENABLE 0x298 - -#define S_DTAGPARERR 28 -#define V_DTAGPARERR(x) ((x) << S_DTAGPARERR) -#define F_DTAGPARERR V_DTAGPARERR(1U) - -#define S_ITAGPARERR 27 -#define V_ITAGPARERR(x) ((x) << S_ITAGPARERR) -#define F_ITAGPARERR V_ITAGPARERR(1U) - -#define S_IBQTPPARERR 26 -#define V_IBQTPPARERR(x) ((x) << S_IBQTPPARERR) -#define F_IBQTPPARERR V_IBQTPPARERR(1U) - -#define S_IBQULPPARERR 25 -#define V_IBQULPPARERR(x) ((x) << S_IBQULPPARERR) -#define F_IBQULPPARERR V_IBQULPPARERR(1U) - -#define S_IBQSGEHIPARERR 24 -#define V_IBQSGEHIPARERR(x) ((x) << S_IBQSGEHIPARERR) -#define F_IBQSGEHIPARERR V_IBQSGEHIPARERR(1U) - -#define S_IBQSGELOPARERR 23 -#define V_IBQSGELOPARERR(x) ((x) << S_IBQSGELOPARERR) -#define F_IBQSGELOPARERR V_IBQSGELOPARERR(1U) - -#define S_OBQULPLOPARERR 22 -#define V_OBQULPLOPARERR(x) ((x) << S_OBQULPLOPARERR) -#define F_OBQULPLOPARERR V_OBQULPLOPARERR(1U) - -#define S_OBQULPHIPARERR 21 -#define V_OBQULPHIPARERR(x) ((x) << S_OBQULPHIPARERR) -#define F_OBQULPHIPARERR V_OBQULPHIPARERR(1U) - -#define S_OBQSGEPARERR 20 -#define V_OBQSGEPARERR(x) ((x) << S_OBQSGEPARERR) -#define F_OBQSGEPARERR V_OBQSGEPARERR(1U) - -#define S_DCACHEPARERR 19 -#define V_DCACHEPARERR(x) ((x) << S_DCACHEPARERR) -#define F_DCACHEPARERR V_DCACHEPARERR(1U) - -#define S_ICACHEPARERR 18 -#define V_ICACHEPARERR(x) ((x) << S_ICACHEPARERR) -#define F_ICACHEPARERR V_ICACHEPARERR(1U) - -#define S_DRAMPARERR 17 -#define V_DRAMPARERR(x) ((x) << S_DRAMPARERR) -#define F_DRAMPARERR V_DRAMPARERR(1U) - -#define A_CIM_HOST_INT_CAUSE 0x29c - -#define S_BLKWRPLINT 12 -#define V_BLKWRPLINT(x) ((x) << S_BLKWRPLINT) -#define F_BLKWRPLINT V_BLKWRPLINT(1U) - -#define S_BLKRDPLINT 11 -#define V_BLKRDPLINT(x) ((x) << S_BLKRDPLINT) -#define F_BLKRDPLINT V_BLKRDPLINT(1U) - -#define S_BLKWRCTLINT 10 -#define V_BLKWRCTLINT(x) ((x) << S_BLKWRCTLINT) -#define F_BLKWRCTLINT V_BLKWRCTLINT(1U) - -#define S_BLKRDCTLINT 9 -#define V_BLKRDCTLINT(x) ((x) << S_BLKRDCTLINT) -#define F_BLKRDCTLINT V_BLKRDCTLINT(1U) - -#define S_BLKWRFLASHINT 8 -#define V_BLKWRFLASHINT(x) ((x) << S_BLKWRFLASHINT) -#define F_BLKWRFLASHINT V_BLKWRFLASHINT(1U) - -#define S_BLKRDFLASHINT 7 -#define V_BLKRDFLASHINT(x) ((x) << S_BLKRDFLASHINT) -#define F_BLKRDFLASHINT V_BLKRDFLASHINT(1U) - -#define S_SGLWRFLASHINT 6 -#define V_SGLWRFLASHINT(x) ((x) << S_SGLWRFLASHINT) -#define F_SGLWRFLASHINT V_SGLWRFLASHINT(1U) - -#define S_WRBLKFLASHINT 5 -#define V_WRBLKFLASHINT(x) ((x) << S_WRBLKFLASHINT) -#define F_WRBLKFLASHINT V_WRBLKFLASHINT(1U) - -#define S_BLKWRBOOTINT 4 -#define V_BLKWRBOOTINT(x) ((x) << S_BLKWRBOOTINT) -#define F_BLKWRBOOTINT V_BLKWRBOOTINT(1U) - -#define S_FLASHRANGEINT 2 -#define V_FLASHRANGEINT(x) ((x) << S_FLASHRANGEINT) -#define F_FLASHRANGEINT V_FLASHRANGEINT(1U) - -#define S_SDRAMRANGEINT 1 -#define V_SDRAMRANGEINT(x) ((x) << S_SDRAMRANGEINT) -#define F_SDRAMRANGEINT V_SDRAMRANGEINT(1U) - -#define S_RSVDSPACEINT 0 -#define V_RSVDSPACEINT(x) ((x) << S_RSVDSPACEINT) -#define F_RSVDSPACEINT V_RSVDSPACEINT(1U) - -#define A_CIM_HOST_ACC_CTRL 0x2b0 - -#define S_HOSTBUSY 17 -#define V_HOSTBUSY(x) ((x) << S_HOSTBUSY) -#define F_HOSTBUSY V_HOSTBUSY(1U) - -#define A_CIM_HOST_ACC_DATA 0x2b4 - -#define A_CIM_IBQ_DBG_CFG 0x2c0 - -#define S_IBQDBGADDR 16 -#define M_IBQDBGADDR 0x1ff -#define V_IBQDBGADDR(x) ((x) << S_IBQDBGADDR) -#define G_IBQDBGADDR(x) (((x) >> S_IBQDBGADDR) & M_IBQDBGADDR) - -#define S_IBQDBGQID 3 -#define M_IBQDBGQID 0x3 -#define V_IBQDBGQID(x) ((x) << S_IBQDBGQID) -#define G_IBQDBGQID(x) (((x) >> S_IBQDBGQID) & M_IBQDBGQID) - -#define S_IBQDBGWR 2 -#define V_IBQDBGWR(x) ((x) << S_IBQDBGWR) -#define F_IBQDBGWR V_IBQDBGWR(1U) - -#define S_IBQDBGBUSY 1 -#define V_IBQDBGBUSY(x) ((x) << S_IBQDBGBUSY) -#define F_IBQDBGBUSY V_IBQDBGBUSY(1U) - -#define S_IBQDBGEN 0 -#define V_IBQDBGEN(x) ((x) << S_IBQDBGEN) -#define F_IBQDBGEN V_IBQDBGEN(1U) - -#define A_CIM_IBQ_DBG_DATA 0x2c8 - -#define A_TP_IN_CONFIG 0x300 - -#define S_RXFBARBPRIO 25 -#define V_RXFBARBPRIO(x) ((x) << S_RXFBARBPRIO) -#define F_RXFBARBPRIO V_RXFBARBPRIO(1U) - -#define S_TXFBARBPRIO 24 -#define V_TXFBARBPRIO(x) ((x) << S_TXFBARBPRIO) -#define F_TXFBARBPRIO V_TXFBARBPRIO(1U) - -#define S_NICMODE 14 -#define V_NICMODE(x) ((x) << S_NICMODE) -#define F_NICMODE V_NICMODE(1U) - -#define F_NICMODE V_NICMODE(1U) - -#define S_IPV6ENABLE 15 -#define V_IPV6ENABLE(x) ((x) << S_IPV6ENABLE) -#define F_IPV6ENABLE V_IPV6ENABLE(1U) - -#define A_TP_OUT_CONFIG 0x304 - -#define S_VLANEXTRACTIONENABLE 12 - -#define A_TP_GLOBAL_CONFIG 0x308 - -#define S_TXPACINGENABLE 24 -#define V_TXPACINGENABLE(x) ((x) << S_TXPACINGENABLE) -#define F_TXPACINGENABLE V_TXPACINGENABLE(1U) - -#define S_PATHMTU 15 -#define V_PATHMTU(x) ((x) << S_PATHMTU) -#define F_PATHMTU V_PATHMTU(1U) - -#define S_IPCHECKSUMOFFLOAD 13 -#define V_IPCHECKSUMOFFLOAD(x) ((x) << S_IPCHECKSUMOFFLOAD) -#define F_IPCHECKSUMOFFLOAD V_IPCHECKSUMOFFLOAD(1U) - -#define S_UDPCHECKSUMOFFLOAD 12 -#define V_UDPCHECKSUMOFFLOAD(x) ((x) << S_UDPCHECKSUMOFFLOAD) -#define F_UDPCHECKSUMOFFLOAD V_UDPCHECKSUMOFFLOAD(1U) - -#define S_TCPCHECKSUMOFFLOAD 11 -#define V_TCPCHECKSUMOFFLOAD(x) ((x) << S_TCPCHECKSUMOFFLOAD) -#define F_TCPCHECKSUMOFFLOAD V_TCPCHECKSUMOFFLOAD(1U) - -#define S_IPTTL 0 -#define M_IPTTL 0xff -#define V_IPTTL(x) ((x) << S_IPTTL) - -#define A_TP_CMM_MM_BASE 0x314 - -#define A_TP_CMM_TIMER_BASE 0x318 - -#define S_CMTIMERMAXNUM 28 -#define M_CMTIMERMAXNUM 0x3 -#define V_CMTIMERMAXNUM(x) ((x) << S_CMTIMERMAXNUM) - -#define A_TP_PMM_SIZE 0x31c - -#define A_TP_PMM_TX_BASE 0x320 - -#define A_TP_PMM_RX_BASE 0x328 - -#define A_TP_PMM_RX_PAGE_SIZE 0x32c - -#define A_TP_PMM_RX_MAX_PAGE 0x330 - -#define A_TP_PMM_TX_PAGE_SIZE 0x334 - -#define A_TP_PMM_TX_MAX_PAGE 0x338 - -#define A_TP_TCP_OPTIONS 0x340 - -#define S_MTUDEFAULT 16 -#define M_MTUDEFAULT 0xffff -#define V_MTUDEFAULT(x) ((x) << S_MTUDEFAULT) - -#define S_MTUENABLE 10 -#define V_MTUENABLE(x) ((x) << S_MTUENABLE) -#define F_MTUENABLE V_MTUENABLE(1U) - -#define S_SACKRX 8 -#define V_SACKRX(x) ((x) << S_SACKRX) -#define F_SACKRX V_SACKRX(1U) - -#define S_SACKMODE 4 - -#define M_SACKMODE 0x3 - -#define V_SACKMODE(x) ((x) << S_SACKMODE) - -#define S_WINDOWSCALEMODE 2 -#define M_WINDOWSCALEMODE 0x3 -#define V_WINDOWSCALEMODE(x) ((x) << S_WINDOWSCALEMODE) - -#define S_TIMESTAMPSMODE 0 - -#define M_TIMESTAMPSMODE 0x3 - -#define V_TIMESTAMPSMODE(x) ((x) << S_TIMESTAMPSMODE) - -#define A_TP_DACK_CONFIG 0x344 - -#define S_AUTOSTATE3 30 -#define M_AUTOSTATE3 0x3 -#define V_AUTOSTATE3(x) ((x) << S_AUTOSTATE3) - -#define S_AUTOSTATE2 28 -#define M_AUTOSTATE2 0x3 -#define V_AUTOSTATE2(x) ((x) << S_AUTOSTATE2) - -#define S_AUTOSTATE1 26 -#define M_AUTOSTATE1 0x3 -#define V_AUTOSTATE1(x) ((x) << S_AUTOSTATE1) - -#define S_BYTETHRESHOLD 5 -#define M_BYTETHRESHOLD 0xfffff -#define V_BYTETHRESHOLD(x) ((x) << S_BYTETHRESHOLD) - -#define S_MSSTHRESHOLD 3 -#define M_MSSTHRESHOLD 0x3 -#define V_MSSTHRESHOLD(x) ((x) << S_MSSTHRESHOLD) - -#define S_AUTOCAREFUL 2 -#define V_AUTOCAREFUL(x) ((x) << S_AUTOCAREFUL) -#define F_AUTOCAREFUL V_AUTOCAREFUL(1U) - -#define S_AUTOENABLE 1 -#define V_AUTOENABLE(x) ((x) << S_AUTOENABLE) -#define F_AUTOENABLE V_AUTOENABLE(1U) - -#define S_DACK_MODE 0 -#define V_DACK_MODE(x) ((x) << S_DACK_MODE) -#define F_DACK_MODE V_DACK_MODE(1U) - -#define A_TP_PC_CONFIG 0x348 - -#define S_TXTOSQUEUEMAPMODE 26 -#define V_TXTOSQUEUEMAPMODE(x) ((x) << S_TXTOSQUEUEMAPMODE) -#define F_TXTOSQUEUEMAPMODE V_TXTOSQUEUEMAPMODE(1U) - -#define S_ENABLEEPCMDAFULL 23 -#define V_ENABLEEPCMDAFULL(x) ((x) << S_ENABLEEPCMDAFULL) -#define F_ENABLEEPCMDAFULL V_ENABLEEPCMDAFULL(1U) - -#define S_MODULATEUNIONMODE 22 -#define V_MODULATEUNIONMODE(x) ((x) << S_MODULATEUNIONMODE) -#define F_MODULATEUNIONMODE V_MODULATEUNIONMODE(1U) - -#define S_TXDEFERENABLE 20 -#define V_TXDEFERENABLE(x) ((x) << S_TXDEFERENABLE) -#define F_TXDEFERENABLE V_TXDEFERENABLE(1U) - -#define S_RXCONGESTIONMODE 19 -#define V_RXCONGESTIONMODE(x) ((x) << S_RXCONGESTIONMODE) -#define F_RXCONGESTIONMODE V_RXCONGESTIONMODE(1U) - -#define S_HEARBEATDACK 16 -#define V_HEARBEATDACK(x) ((x) << S_HEARBEATDACK) -#define F_HEARBEATDACK V_HEARBEATDACK(1U) - -#define S_TXCONGESTIONMODE 15 -#define V_TXCONGESTIONMODE(x) ((x) << S_TXCONGESTIONMODE) -#define F_TXCONGESTIONMODE V_TXCONGESTIONMODE(1U) - -#define S_ENABLEOCSPIFULL 30 -#define V_ENABLEOCSPIFULL(x) ((x) << S_ENABLEOCSPIFULL) -#define F_ENABLEOCSPIFULL V_ENABLEOCSPIFULL(1U) - -#define S_LOCKTID 28 -#define V_LOCKTID(x) ((x) << S_LOCKTID) -#define F_LOCKTID V_LOCKTID(1U) - -#define S_TABLELATENCYDELTA 0 -#define M_TABLELATENCYDELTA 0xf -#define V_TABLELATENCYDELTA(x) ((x) << S_TABLELATENCYDELTA) -#define G_TABLELATENCYDELTA(x) \ - (((x) >> S_TABLELATENCYDELTA) & M_TABLELATENCYDELTA) - -#define A_TP_PC_CONFIG2 0x34c - -#define S_DISBLEDAPARBIT0 15 -#define V_DISBLEDAPARBIT0(x) ((x) << S_DISBLEDAPARBIT0) -#define F_DISBLEDAPARBIT0 V_DISBLEDAPARBIT0(1U) - -#define S_ENABLEARPMISS 13 -#define V_ENABLEARPMISS(x) ((x) << S_ENABLEARPMISS) -#define F_ENABLEARPMISS V_ENABLEARPMISS(1U) - -#define S_ENABLENONOFDTNLSYN 12 -#define V_ENABLENONOFDTNLSYN(x) ((x) << S_ENABLENONOFDTNLSYN) -#define F_ENABLENONOFDTNLSYN V_ENABLENONOFDTNLSYN(1U) - -#define S_ENABLEIPV6RSS 11 -#define V_ENABLEIPV6RSS(x) ((x) << S_ENABLEIPV6RSS) -#define F_ENABLEIPV6RSS V_ENABLEIPV6RSS(1U) - -#define S_CHDRAFULL 4 -#define V_CHDRAFULL(x) ((x) << S_CHDRAFULL) -#define F_CHDRAFULL V_CHDRAFULL(1U) - -#define A_TP_TCP_BACKOFF_REG0 0x350 - -#define A_TP_TCP_BACKOFF_REG1 0x354 - -#define A_TP_TCP_BACKOFF_REG2 0x358 - -#define A_TP_TCP_BACKOFF_REG3 0x35c - -#define A_TP_PARA_REG2 0x368 - -#define S_MAXRXDATA 16 -#define M_MAXRXDATA 0xffff -#define V_MAXRXDATA(x) ((x) << S_MAXRXDATA) - -#define S_RXCOALESCESIZE 0 -#define M_RXCOALESCESIZE 0xffff -#define V_RXCOALESCESIZE(x) ((x) << S_RXCOALESCESIZE) - -#define A_TP_PARA_REG3 0x36c - -#define S_TXDATAACKIDX 16 -#define M_TXDATAACKIDX 0xf - -#define V_TXDATAACKIDX(x) ((x) << S_TXDATAACKIDX) - -#define S_TXPACEAUTOSTRICT 10 -#define V_TXPACEAUTOSTRICT(x) ((x) << S_TXPACEAUTOSTRICT) -#define F_TXPACEAUTOSTRICT V_TXPACEAUTOSTRICT(1U) - -#define S_TXPACEFIXED 9 -#define V_TXPACEFIXED(x) ((x) << S_TXPACEFIXED) -#define F_TXPACEFIXED V_TXPACEFIXED(1U) - -#define S_TXPACEAUTO 8 -#define V_TXPACEAUTO(x) ((x) << S_TXPACEAUTO) -#define F_TXPACEAUTO V_TXPACEAUTO(1U) - -#define S_RXCOALESCEENABLE 1 -#define V_RXCOALESCEENABLE(x) ((x) << S_RXCOALESCEENABLE) -#define F_RXCOALESCEENABLE V_RXCOALESCEENABLE(1U) - -#define S_RXCOALESCEPSHEN 0 -#define V_RXCOALESCEPSHEN(x) ((x) << S_RXCOALESCEPSHEN) -#define F_RXCOALESCEPSHEN V_RXCOALESCEPSHEN(1U) - -#define A_TP_PARA_REG4 0x370 - -#define A_TP_PARA_REG5 0x374 - -#define S_RXDDPOFFINIT 3 -#define V_RXDDPOFFINIT(x) ((x) << S_RXDDPOFFINIT) -#define F_RXDDPOFFINIT V_RXDDPOFFINIT(1U) - -#define A_TP_PARA_REG6 0x378 - -#define S_T3A_ENABLEESND 13 -#define V_T3A_ENABLEESND(x) ((x) << S_T3A_ENABLEESND) -#define F_T3A_ENABLEESND V_T3A_ENABLEESND(1U) - -#define S_ENABLEESND 11 -#define V_ENABLEESND(x) ((x) << S_ENABLEESND) -#define F_ENABLEESND V_ENABLEESND(1U) - -#define A_TP_PARA_REG7 0x37c - -#define S_PMMAXXFERLEN1 16 -#define M_PMMAXXFERLEN1 0xffff -#define V_PMMAXXFERLEN1(x) ((x) << S_PMMAXXFERLEN1) - -#define S_PMMAXXFERLEN0 0 -#define M_PMMAXXFERLEN0 0xffff -#define V_PMMAXXFERLEN0(x) ((x) << S_PMMAXXFERLEN0) - -#define A_TP_TIMER_RESOLUTION 0x390 - -#define S_TIMERRESOLUTION 16 -#define M_TIMERRESOLUTION 0xff -#define V_TIMERRESOLUTION(x) ((x) << S_TIMERRESOLUTION) - -#define S_TIMESTAMPRESOLUTION 8 -#define M_TIMESTAMPRESOLUTION 0xff -#define V_TIMESTAMPRESOLUTION(x) ((x) << S_TIMESTAMPRESOLUTION) - -#define S_DELAYEDACKRESOLUTION 0 -#define M_DELAYEDACKRESOLUTION 0xff -#define V_DELAYEDACKRESOLUTION(x) ((x) << S_DELAYEDACKRESOLUTION) - -#define A_TP_MSL 0x394 - -#define A_TP_RXT_MIN 0x398 - -#define A_TP_RXT_MAX 0x39c - -#define A_TP_PERS_MIN 0x3a0 - -#define A_TP_PERS_MAX 0x3a4 - -#define A_TP_KEEP_IDLE 0x3a8 - -#define A_TP_KEEP_INTVL 0x3ac - -#define A_TP_INIT_SRTT 0x3b0 - -#define A_TP_DACK_TIMER 0x3b4 - -#define A_TP_FINWAIT2_TIMER 0x3b8 - -#define A_TP_SHIFT_CNT 0x3c0 - -#define S_SYNSHIFTMAX 24 - -#define M_SYNSHIFTMAX 0xff - -#define V_SYNSHIFTMAX(x) ((x) << S_SYNSHIFTMAX) - -#define S_RXTSHIFTMAXR1 20 - -#define M_RXTSHIFTMAXR1 0xf - -#define V_RXTSHIFTMAXR1(x) ((x) << S_RXTSHIFTMAXR1) - -#define S_RXTSHIFTMAXR2 16 - -#define M_RXTSHIFTMAXR2 0xf - -#define V_RXTSHIFTMAXR2(x) ((x) << S_RXTSHIFTMAXR2) - -#define S_PERSHIFTBACKOFFMAX 12 -#define M_PERSHIFTBACKOFFMAX 0xf -#define V_PERSHIFTBACKOFFMAX(x) ((x) << S_PERSHIFTBACKOFFMAX) - -#define S_PERSHIFTMAX 8 -#define M_PERSHIFTMAX 0xf -#define V_PERSHIFTMAX(x) ((x) << S_PERSHIFTMAX) - -#define S_KEEPALIVEMAX 0 - -#define M_KEEPALIVEMAX 0xff - -#define V_KEEPALIVEMAX(x) ((x) << S_KEEPALIVEMAX) - -#define A_TP_MTU_PORT_TABLE 0x3d0 - -#define A_TP_CCTRL_TABLE 0x3dc - -#define A_TP_MTU_TABLE 0x3e4 - -#define A_TP_RSS_MAP_TABLE 0x3e8 - -#define A_TP_RSS_LKP_TABLE 0x3ec - -#define A_TP_RSS_CONFIG 0x3f0 - -#define S_TNL4TUPEN 29 -#define V_TNL4TUPEN(x) ((x) << S_TNL4TUPEN) -#define F_TNL4TUPEN V_TNL4TUPEN(1U) - -#define S_TNL2TUPEN 28 -#define V_TNL2TUPEN(x) ((x) << S_TNL2TUPEN) -#define F_TNL2TUPEN V_TNL2TUPEN(1U) - -#define S_TNLPRTEN 26 -#define V_TNLPRTEN(x) ((x) << S_TNLPRTEN) -#define F_TNLPRTEN V_TNLPRTEN(1U) - -#define S_TNLMAPEN 25 -#define V_TNLMAPEN(x) ((x) << S_TNLMAPEN) -#define F_TNLMAPEN V_TNLMAPEN(1U) - -#define S_TNLLKPEN 24 -#define V_TNLLKPEN(x) ((x) << S_TNLLKPEN) -#define F_TNLLKPEN V_TNLLKPEN(1U) - -#define S_RRCPLMAPEN 7 -#define V_RRCPLMAPEN(x) ((x) << S_RRCPLMAPEN) -#define F_RRCPLMAPEN V_RRCPLMAPEN(1U) - -#define S_RRCPLCPUSIZE 4 -#define M_RRCPLCPUSIZE 0x7 -#define V_RRCPLCPUSIZE(x) ((x) << S_RRCPLCPUSIZE) - -#define S_RQFEEDBACKENABLE 3 -#define V_RQFEEDBACKENABLE(x) ((x) << S_RQFEEDBACKENABLE) -#define F_RQFEEDBACKENABLE V_RQFEEDBACKENABLE(1U) - -#define S_HASHTOEPLITZ 2 -#define V_HASHTOEPLITZ(x) ((x) << S_HASHTOEPLITZ) -#define F_HASHTOEPLITZ V_HASHTOEPLITZ(1U) - -#define S_DISABLE 0 - -#define A_TP_TM_PIO_ADDR 0x418 - -#define A_TP_TM_PIO_DATA 0x41c - -#define A_TP_TX_MOD_QUE_TABLE 0x420 - -#define A_TP_TX_RESOURCE_LIMIT 0x424 - -#define A_TP_TX_MOD_QUEUE_REQ_MAP 0x428 - -#define S_TX_MOD_QUEUE_REQ_MAP 0 -#define M_TX_MOD_QUEUE_REQ_MAP 0xff -#define V_TX_MOD_QUEUE_REQ_MAP(x) ((x) << S_TX_MOD_QUEUE_REQ_MAP) - -#define A_TP_TX_MOD_QUEUE_WEIGHT1 0x42c - -#define A_TP_TX_MOD_QUEUE_WEIGHT0 0x430 - -#define A_TP_MOD_CHANNEL_WEIGHT 0x434 - -#define A_TP_MOD_RATE_LIMIT 0x438 - -#define A_TP_PIO_ADDR 0x440 - -#define A_TP_PIO_DATA 0x444 - -#define A_TP_RESET 0x44c - -#define S_FLSTINITENABLE 1 -#define V_FLSTINITENABLE(x) ((x) << S_FLSTINITENABLE) -#define F_FLSTINITENABLE V_FLSTINITENABLE(1U) - -#define S_TPRESET 0 -#define V_TPRESET(x) ((x) << S_TPRESET) -#define F_TPRESET V_TPRESET(1U) - -#define A_TP_CMM_MM_RX_FLST_BASE 0x460 - -#define A_TP_CMM_MM_TX_FLST_BASE 0x464 - -#define A_TP_CMM_MM_PS_FLST_BASE 0x468 - -#define A_TP_MIB_INDEX 0x450 - -#define A_TP_MIB_RDATA 0x454 - -#define A_TP_CMM_MM_MAX_PSTRUCT 0x46c - -#define A_TP_INT_ENABLE 0x470 - -#define S_FLMTXFLSTEMPTY 30 -#define V_FLMTXFLSTEMPTY(x) ((x) << S_FLMTXFLSTEMPTY) -#define F_FLMTXFLSTEMPTY V_FLMTXFLSTEMPTY(1U) - -#define S_FLMRXFLSTEMPTY 29 -#define V_FLMRXFLSTEMPTY(x) ((x) << S_FLMRXFLSTEMPTY) -#define F_FLMRXFLSTEMPTY V_FLMRXFLSTEMPTY(1U) - -#define S_ARPLUTPERR 26 -#define V_ARPLUTPERR(x) ((x) << S_ARPLUTPERR) -#define F_ARPLUTPERR V_ARPLUTPERR(1U) - -#define S_CMCACHEPERR 24 -#define V_CMCACHEPERR(x) ((x) << S_CMCACHEPERR) -#define F_CMCACHEPERR V_CMCACHEPERR(1U) - -#define A_TP_INT_CAUSE 0x474 - -#define A_TP_TX_MOD_Q1_Q0_RATE_LIMIT 0x8 - -#define A_TP_TX_DROP_CFG_CH0 0x12b - -#define A_TP_TX_DROP_MODE 0x12f - -#define A_TP_EGRESS_CONFIG 0x145 - -#define S_REWRITEFORCETOSIZE 0 -#define V_REWRITEFORCETOSIZE(x) ((x) << S_REWRITEFORCETOSIZE) -#define F_REWRITEFORCETOSIZE V_REWRITEFORCETOSIZE(1U) - -#define A_TP_TX_TRC_KEY0 0x20 - -#define A_TP_RX_TRC_KEY0 0x120 - -#define A_TP_TX_DROP_CNT_CH0 0x12d - -#define S_TXDROPCNTCH0RCVD 0 -#define M_TXDROPCNTCH0RCVD 0xffff -#define V_TXDROPCNTCH0RCVD(x) ((x) << S_TXDROPCNTCH0RCVD) -#define G_TXDROPCNTCH0RCVD(x) (((x) >> S_TXDROPCNTCH0RCVD) & \ - M_TXDROPCNTCH0RCVD) - -#define A_TP_PROXY_FLOW_CNTL 0x4b0 - -#define A_TP_EMBED_OP_FIELD0 0x4e8 -#define A_TP_EMBED_OP_FIELD1 0x4ec -#define A_TP_EMBED_OP_FIELD2 0x4f0 -#define A_TP_EMBED_OP_FIELD3 0x4f4 -#define A_TP_EMBED_OP_FIELD4 0x4f8 -#define A_TP_EMBED_OP_FIELD5 0x4fc - -#define A_ULPRX_CTL 0x500 - -#define S_ROUND_ROBIN 4 -#define V_ROUND_ROBIN(x) ((x) << S_ROUND_ROBIN) -#define F_ROUND_ROBIN V_ROUND_ROBIN(1U) - -#define A_ULPRX_INT_ENABLE 0x504 - -#define S_DATASELFRAMEERR0 7 -#define V_DATASELFRAMEERR0(x) ((x) << S_DATASELFRAMEERR0) -#define F_DATASELFRAMEERR0 V_DATASELFRAMEERR0(1U) - -#define S_DATASELFRAMEERR1 6 -#define V_DATASELFRAMEERR1(x) ((x) << S_DATASELFRAMEERR1) -#define F_DATASELFRAMEERR1 V_DATASELFRAMEERR1(1U) - -#define S_PCMDMUXPERR 5 -#define V_PCMDMUXPERR(x) ((x) << S_PCMDMUXPERR) -#define F_PCMDMUXPERR V_PCMDMUXPERR(1U) - -#define S_ARBFPERR 4 -#define V_ARBFPERR(x) ((x) << S_ARBFPERR) -#define F_ARBFPERR V_ARBFPERR(1U) - -#define S_ARBPF0PERR 3 -#define V_ARBPF0PERR(x) ((x) << S_ARBPF0PERR) -#define F_ARBPF0PERR V_ARBPF0PERR(1U) - -#define S_ARBPF1PERR 2 -#define V_ARBPF1PERR(x) ((x) << S_ARBPF1PERR) -#define F_ARBPF1PERR V_ARBPF1PERR(1U) - -#define S_PARERRPCMD 1 -#define V_PARERRPCMD(x) ((x) << S_PARERRPCMD) -#define F_PARERRPCMD V_PARERRPCMD(1U) - -#define S_PARERRDATA 0 -#define V_PARERRDATA(x) ((x) << S_PARERRDATA) -#define F_PARERRDATA V_PARERRDATA(1U) - -#define A_ULPRX_INT_CAUSE 0x508 - -#define A_ULPRX_ISCSI_LLIMIT 0x50c - -#define A_ULPRX_ISCSI_ULIMIT 0x510 - -#define A_ULPRX_ISCSI_TAGMASK 0x514 - -#define A_ULPRX_ISCSI_PSZ 0x518 - -#define A_ULPRX_TDDP_LLIMIT 0x51c - -#define A_ULPRX_TDDP_ULIMIT 0x520 -#define A_ULPRX_TDDP_PSZ 0x528 - -#define S_HPZ0 0 -#define M_HPZ0 0xf -#define V_HPZ0(x) ((x) << S_HPZ0) -#define G_HPZ0(x) (((x) >> S_HPZ0) & M_HPZ0) - -#define A_ULPRX_STAG_LLIMIT 0x52c - -#define A_ULPRX_STAG_ULIMIT 0x530 - -#define A_ULPRX_RQ_LLIMIT 0x534 -#define A_ULPRX_RQ_LLIMIT 0x534 - -#define A_ULPRX_RQ_ULIMIT 0x538 -#define A_ULPRX_RQ_ULIMIT 0x538 - -#define A_ULPRX_PBL_LLIMIT 0x53c - -#define A_ULPRX_PBL_ULIMIT 0x540 -#define A_ULPRX_PBL_ULIMIT 0x540 - -#define A_ULPRX_TDDP_TAGMASK 0x524 - -#define A_ULPRX_RQ_LLIMIT 0x534 -#define A_ULPRX_RQ_LLIMIT 0x534 - -#define A_ULPRX_RQ_ULIMIT 0x538 -#define A_ULPRX_RQ_ULIMIT 0x538 - -#define A_ULPRX_PBL_ULIMIT 0x540 -#define A_ULPRX_PBL_ULIMIT 0x540 - -#define A_ULPTX_CONFIG 0x580 - -#define S_CFG_CQE_SOP_MASK 1 -#define V_CFG_CQE_SOP_MASK(x) ((x) << S_CFG_CQE_SOP_MASK) -#define F_CFG_CQE_SOP_MASK V_CFG_CQE_SOP_MASK(1U) - -#define S_CFG_RR_ARB 0 -#define V_CFG_RR_ARB(x) ((x) << S_CFG_RR_ARB) -#define F_CFG_RR_ARB V_CFG_RR_ARB(1U) - -#define A_ULPTX_INT_ENABLE 0x584 - -#define S_PBL_BOUND_ERR_CH1 1 -#define V_PBL_BOUND_ERR_CH1(x) ((x) << S_PBL_BOUND_ERR_CH1) -#define F_PBL_BOUND_ERR_CH1 V_PBL_BOUND_ERR_CH1(1U) - -#define S_PBL_BOUND_ERR_CH0 0 -#define V_PBL_BOUND_ERR_CH0(x) ((x) << S_PBL_BOUND_ERR_CH0) -#define F_PBL_BOUND_ERR_CH0 V_PBL_BOUND_ERR_CH0(1U) - -#define A_ULPTX_INT_CAUSE 0x588 - -#define A_ULPTX_TPT_LLIMIT 0x58c - -#define A_ULPTX_TPT_ULIMIT 0x590 - -#define A_ULPTX_PBL_LLIMIT 0x594 - -#define A_ULPTX_PBL_ULIMIT 0x598 - -#define A_ULPTX_DMA_WEIGHT 0x5ac - -#define S_D1_WEIGHT 16 -#define M_D1_WEIGHT 0xffff -#define V_D1_WEIGHT(x) ((x) << S_D1_WEIGHT) - -#define S_D0_WEIGHT 0 -#define M_D0_WEIGHT 0xffff -#define V_D0_WEIGHT(x) ((x) << S_D0_WEIGHT) - -#define A_PM1_RX_CFG 0x5c0 -#define A_PM1_RX_MODE 0x5c4 - -#define A_PM1_RX_INT_ENABLE 0x5d8 - -#define S_ZERO_E_CMD_ERROR 18 -#define V_ZERO_E_CMD_ERROR(x) ((x) << S_ZERO_E_CMD_ERROR) -#define F_ZERO_E_CMD_ERROR V_ZERO_E_CMD_ERROR(1U) - -#define S_IESPI0_FIFO2X_RX_FRAMING_ERROR 17 -#define V_IESPI0_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_IESPI0_FIFO2X_RX_FRAMING_ERROR) -#define F_IESPI0_FIFO2X_RX_FRAMING_ERROR V_IESPI0_FIFO2X_RX_FRAMING_ERROR(1U) - -#define S_IESPI1_FIFO2X_RX_FRAMING_ERROR 16 -#define V_IESPI1_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_IESPI1_FIFO2X_RX_FRAMING_ERROR) -#define F_IESPI1_FIFO2X_RX_FRAMING_ERROR V_IESPI1_FIFO2X_RX_FRAMING_ERROR(1U) - -#define S_IESPI0_RX_FRAMING_ERROR 15 -#define V_IESPI0_RX_FRAMING_ERROR(x) ((x) << S_IESPI0_RX_FRAMING_ERROR) -#define F_IESPI0_RX_FRAMING_ERROR V_IESPI0_RX_FRAMING_ERROR(1U) - -#define S_IESPI1_RX_FRAMING_ERROR 14 -#define V_IESPI1_RX_FRAMING_ERROR(x) ((x) << S_IESPI1_RX_FRAMING_ERROR) -#define F_IESPI1_RX_FRAMING_ERROR V_IESPI1_RX_FRAMING_ERROR(1U) - -#define S_IESPI0_TX_FRAMING_ERROR 13 -#define V_IESPI0_TX_FRAMING_ERROR(x) ((x) << S_IESPI0_TX_FRAMING_ERROR) -#define F_IESPI0_TX_FRAMING_ERROR V_IESPI0_TX_FRAMING_ERROR(1U) - -#define S_IESPI1_TX_FRAMING_ERROR 12 -#define V_IESPI1_TX_FRAMING_ERROR(x) ((x) << S_IESPI1_TX_FRAMING_ERROR) -#define F_IESPI1_TX_FRAMING_ERROR V_IESPI1_TX_FRAMING_ERROR(1U) - -#define S_OCSPI0_RX_FRAMING_ERROR 11 -#define V_OCSPI0_RX_FRAMING_ERROR(x) ((x) << S_OCSPI0_RX_FRAMING_ERROR) -#define F_OCSPI0_RX_FRAMING_ERROR V_OCSPI0_RX_FRAMING_ERROR(1U) - -#define S_OCSPI1_RX_FRAMING_ERROR 10 -#define V_OCSPI1_RX_FRAMING_ERROR(x) ((x) << S_OCSPI1_RX_FRAMING_ERROR) -#define F_OCSPI1_RX_FRAMING_ERROR V_OCSPI1_RX_FRAMING_ERROR(1U) - -#define S_OCSPI0_TX_FRAMING_ERROR 9 -#define V_OCSPI0_TX_FRAMING_ERROR(x) ((x) << S_OCSPI0_TX_FRAMING_ERROR) -#define F_OCSPI0_TX_FRAMING_ERROR V_OCSPI0_TX_FRAMING_ERROR(1U) - -#define S_OCSPI1_TX_FRAMING_ERROR 8 -#define V_OCSPI1_TX_FRAMING_ERROR(x) ((x) << S_OCSPI1_TX_FRAMING_ERROR) -#define F_OCSPI1_TX_FRAMING_ERROR V_OCSPI1_TX_FRAMING_ERROR(1U) - -#define S_OCSPI0_OFIFO2X_TX_FRAMING_ERROR 7 -#define V_OCSPI0_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OCSPI0_OFIFO2X_TX_FRAMING_ERROR) -#define F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR V_OCSPI0_OFIFO2X_TX_FRAMING_ERROR(1U) - -#define S_OCSPI1_OFIFO2X_TX_FRAMING_ERROR 6 -#define V_OCSPI1_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OCSPI1_OFIFO2X_TX_FRAMING_ERROR) -#define F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR V_OCSPI1_OFIFO2X_TX_FRAMING_ERROR(1U) - -#define S_IESPI_PAR_ERROR 3 -#define M_IESPI_PAR_ERROR 0x7 - -#define V_IESPI_PAR_ERROR(x) ((x) << S_IESPI_PAR_ERROR) - -#define S_OCSPI_PAR_ERROR 0 -#define M_OCSPI_PAR_ERROR 0x7 - -#define V_OCSPI_PAR_ERROR(x) ((x) << S_OCSPI_PAR_ERROR) - -#define A_PM1_RX_INT_CAUSE 0x5dc - -#define A_PM1_TX_CFG 0x5e0 -#define A_PM1_TX_MODE 0x5e4 - -#define A_PM1_TX_INT_ENABLE 0x5f8 - -#define S_ZERO_C_CMD_ERROR 18 -#define V_ZERO_C_CMD_ERROR(x) ((x) << S_ZERO_C_CMD_ERROR) -#define F_ZERO_C_CMD_ERROR V_ZERO_C_CMD_ERROR(1U) - -#define S_ICSPI0_FIFO2X_RX_FRAMING_ERROR 17 -#define V_ICSPI0_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_ICSPI0_FIFO2X_RX_FRAMING_ERROR) -#define F_ICSPI0_FIFO2X_RX_FRAMING_ERROR V_ICSPI0_FIFO2X_RX_FRAMING_ERROR(1U) - -#define S_ICSPI1_FIFO2X_RX_FRAMING_ERROR 16 -#define V_ICSPI1_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_ICSPI1_FIFO2X_RX_FRAMING_ERROR) -#define F_ICSPI1_FIFO2X_RX_FRAMING_ERROR V_ICSPI1_FIFO2X_RX_FRAMING_ERROR(1U) - -#define S_ICSPI0_RX_FRAMING_ERROR 15 -#define V_ICSPI0_RX_FRAMING_ERROR(x) ((x) << S_ICSPI0_RX_FRAMING_ERROR) -#define F_ICSPI0_RX_FRAMING_ERROR V_ICSPI0_RX_FRAMING_ERROR(1U) - -#define S_ICSPI1_RX_FRAMING_ERROR 14 -#define V_ICSPI1_RX_FRAMING_ERROR(x) ((x) << S_ICSPI1_RX_FRAMING_ERROR) -#define F_ICSPI1_RX_FRAMING_ERROR V_ICSPI1_RX_FRAMING_ERROR(1U) - -#define S_ICSPI0_TX_FRAMING_ERROR 13 -#define V_ICSPI0_TX_FRAMING_ERROR(x) ((x) << S_ICSPI0_TX_FRAMING_ERROR) -#define F_ICSPI0_TX_FRAMING_ERROR V_ICSPI0_TX_FRAMING_ERROR(1U) - -#define S_ICSPI1_TX_FRAMING_ERROR 12 -#define V_ICSPI1_TX_FRAMING_ERROR(x) ((x) << S_ICSPI1_TX_FRAMING_ERROR) -#define F_ICSPI1_TX_FRAMING_ERROR V_ICSPI1_TX_FRAMING_ERROR(1U) - -#define S_OESPI0_RX_FRAMING_ERROR 11 -#define V_OESPI0_RX_FRAMING_ERROR(x) ((x) << S_OESPI0_RX_FRAMING_ERROR) -#define F_OESPI0_RX_FRAMING_ERROR V_OESPI0_RX_FRAMING_ERROR(1U) - -#define S_OESPI1_RX_FRAMING_ERROR 10 -#define V_OESPI1_RX_FRAMING_ERROR(x) ((x) << S_OESPI1_RX_FRAMING_ERROR) -#define F_OESPI1_RX_FRAMING_ERROR V_OESPI1_RX_FRAMING_ERROR(1U) - -#define S_OESPI0_TX_FRAMING_ERROR 9 -#define V_OESPI0_TX_FRAMING_ERROR(x) ((x) << S_OESPI0_TX_FRAMING_ERROR) -#define F_OESPI0_TX_FRAMING_ERROR V_OESPI0_TX_FRAMING_ERROR(1U) - -#define S_OESPI1_TX_FRAMING_ERROR 8 -#define V_OESPI1_TX_FRAMING_ERROR(x) ((x) << S_OESPI1_TX_FRAMING_ERROR) -#define F_OESPI1_TX_FRAMING_ERROR V_OESPI1_TX_FRAMING_ERROR(1U) - -#define S_OESPI0_OFIFO2X_TX_FRAMING_ERROR 7 -#define V_OESPI0_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OESPI0_OFIFO2X_TX_FRAMING_ERROR) -#define F_OESPI0_OFIFO2X_TX_FRAMING_ERROR V_OESPI0_OFIFO2X_TX_FRAMING_ERROR(1U) - -#define S_OESPI1_OFIFO2X_TX_FRAMING_ERROR 6 -#define V_OESPI1_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OESPI1_OFIFO2X_TX_FRAMING_ERROR) -#define F_OESPI1_OFIFO2X_TX_FRAMING_ERROR V_OESPI1_OFIFO2X_TX_FRAMING_ERROR(1U) - -#define S_ICSPI_PAR_ERROR 3 -#define M_ICSPI_PAR_ERROR 0x7 - -#define V_ICSPI_PAR_ERROR(x) ((x) << S_ICSPI_PAR_ERROR) - -#define S_OESPI_PAR_ERROR 0 -#define M_OESPI_PAR_ERROR 0x7 - -#define V_OESPI_PAR_ERROR(x) ((x) << S_OESPI_PAR_ERROR) - -#define A_PM1_TX_INT_CAUSE 0x5fc - -#define A_MPS_CFG 0x600 - -#define S_TPRXPORTEN 4 -#define V_TPRXPORTEN(x) ((x) << S_TPRXPORTEN) -#define F_TPRXPORTEN V_TPRXPORTEN(1U) - -#define S_TPTXPORT1EN 3 -#define V_TPTXPORT1EN(x) ((x) << S_TPTXPORT1EN) -#define F_TPTXPORT1EN V_TPTXPORT1EN(1U) - -#define S_TPTXPORT0EN 2 -#define V_TPTXPORT0EN(x) ((x) << S_TPTXPORT0EN) -#define F_TPTXPORT0EN V_TPTXPORT0EN(1U) - -#define S_PORT1ACTIVE 1 -#define V_PORT1ACTIVE(x) ((x) << S_PORT1ACTIVE) -#define F_PORT1ACTIVE V_PORT1ACTIVE(1U) - -#define S_PORT0ACTIVE 0 -#define V_PORT0ACTIVE(x) ((x) << S_PORT0ACTIVE) -#define F_PORT0ACTIVE V_PORT0ACTIVE(1U) - -#define S_ENFORCEPKT 11 -#define V_ENFORCEPKT(x) ((x) << S_ENFORCEPKT) -#define F_ENFORCEPKT V_ENFORCEPKT(1U) - -#define A_MPS_INT_ENABLE 0x61c - -#define S_MCAPARERRENB 6 -#define M_MCAPARERRENB 0x7 - -#define V_MCAPARERRENB(x) ((x) << S_MCAPARERRENB) - -#define S_RXTPPARERRENB 4 -#define M_RXTPPARERRENB 0x3 - -#define V_RXTPPARERRENB(x) ((x) << S_RXTPPARERRENB) - -#define S_TX1TPPARERRENB 2 -#define M_TX1TPPARERRENB 0x3 - -#define V_TX1TPPARERRENB(x) ((x) << S_TX1TPPARERRENB) - -#define S_TX0TPPARERRENB 0 -#define M_TX0TPPARERRENB 0x3 - -#define V_TX0TPPARERRENB(x) ((x) << S_TX0TPPARERRENB) - -#define A_MPS_INT_CAUSE 0x620 - -#define S_MCAPARERR 6 -#define M_MCAPARERR 0x7 - -#define V_MCAPARERR(x) ((x) << S_MCAPARERR) - -#define S_RXTPPARERR 4 -#define M_RXTPPARERR 0x3 - -#define V_RXTPPARERR(x) ((x) << S_RXTPPARERR) - -#define S_TX1TPPARERR 2 -#define M_TX1TPPARERR 0x3 - -#define V_TX1TPPARERR(x) ((x) << S_TX1TPPARERR) - -#define S_TX0TPPARERR 0 -#define M_TX0TPPARERR 0x3 - -#define V_TX0TPPARERR(x) ((x) << S_TX0TPPARERR) - -#define A_CPL_SWITCH_CNTRL 0x640 - -#define A_CPL_INTR_ENABLE 0x650 - -#define S_CIM_OP_MAP_PERR 5 -#define V_CIM_OP_MAP_PERR(x) ((x) << S_CIM_OP_MAP_PERR) -#define F_CIM_OP_MAP_PERR V_CIM_OP_MAP_PERR(1U) - -#define S_CIM_OVFL_ERROR 4 -#define V_CIM_OVFL_ERROR(x) ((x) << S_CIM_OVFL_ERROR) -#define F_CIM_OVFL_ERROR V_CIM_OVFL_ERROR(1U) - -#define S_TP_FRAMING_ERROR 3 -#define V_TP_FRAMING_ERROR(x) ((x) << S_TP_FRAMING_ERROR) -#define F_TP_FRAMING_ERROR V_TP_FRAMING_ERROR(1U) - -#define S_SGE_FRAMING_ERROR 2 -#define V_SGE_FRAMING_ERROR(x) ((x) << S_SGE_FRAMING_ERROR) -#define F_SGE_FRAMING_ERROR V_SGE_FRAMING_ERROR(1U) - -#define S_CIM_FRAMING_ERROR 1 -#define V_CIM_FRAMING_ERROR(x) ((x) << S_CIM_FRAMING_ERROR) -#define F_CIM_FRAMING_ERROR V_CIM_FRAMING_ERROR(1U) - -#define S_ZERO_SWITCH_ERROR 0 -#define V_ZERO_SWITCH_ERROR(x) ((x) << S_ZERO_SWITCH_ERROR) -#define F_ZERO_SWITCH_ERROR V_ZERO_SWITCH_ERROR(1U) - -#define A_CPL_INTR_CAUSE 0x654 - -#define A_CPL_MAP_TBL_DATA 0x65c - -#define A_SMB_GLOBAL_TIME_CFG 0x660 - -#define A_I2C_CFG 0x6a0 - -#define S_I2C_CLKDIV 0 -#define M_I2C_CLKDIV 0xfff -#define V_I2C_CLKDIV(x) ((x) << S_I2C_CLKDIV) - -#define A_MI1_CFG 0x6b0 - -#define S_CLKDIV 5 -#define M_CLKDIV 0xff -#define V_CLKDIV(x) ((x) << S_CLKDIV) - -#define S_ST 3 - -#define M_ST 0x3 - -#define V_ST(x) ((x) << S_ST) - -#define G_ST(x) (((x) >> S_ST) & M_ST) - -#define S_PREEN 2 -#define V_PREEN(x) ((x) << S_PREEN) -#define F_PREEN V_PREEN(1U) - -#define S_MDIINV 1 -#define V_MDIINV(x) ((x) << S_MDIINV) -#define F_MDIINV V_MDIINV(1U) - -#define S_MDIEN 0 -#define V_MDIEN(x) ((x) << S_MDIEN) -#define F_MDIEN V_MDIEN(1U) - -#define A_MI1_ADDR 0x6b4 - -#define S_PHYADDR 5 -#define M_PHYADDR 0x1f -#define V_PHYADDR(x) ((x) << S_PHYADDR) - -#define S_REGADDR 0 -#define M_REGADDR 0x1f -#define V_REGADDR(x) ((x) << S_REGADDR) - -#define A_MI1_DATA 0x6b8 - -#define A_MI1_OP 0x6bc - -#define S_MDI_OP 0 -#define M_MDI_OP 0x3 -#define V_MDI_OP(x) ((x) << S_MDI_OP) - -#define A_SF_DATA 0x6d8 - -#define A_SF_OP 0x6dc - -#define S_BYTECNT 1 -#define M_BYTECNT 0x3 -#define V_BYTECNT(x) ((x) << S_BYTECNT) - -#define A_PL_INT_ENABLE0 0x6e0 - -#define S_T3DBG 23 -#define V_T3DBG(x) ((x) << S_T3DBG) -#define F_T3DBG V_T3DBG(1U) - -#define S_XGMAC0_1 20 -#define V_XGMAC0_1(x) ((x) << S_XGMAC0_1) -#define F_XGMAC0_1 V_XGMAC0_1(1U) - -#define S_XGMAC0_0 19 -#define V_XGMAC0_0(x) ((x) << S_XGMAC0_0) -#define F_XGMAC0_0 V_XGMAC0_0(1U) - -#define S_MC5A 18 -#define V_MC5A(x) ((x) << S_MC5A) -#define F_MC5A V_MC5A(1U) - -#define S_CPL_SWITCH 12 -#define V_CPL_SWITCH(x) ((x) << S_CPL_SWITCH) -#define F_CPL_SWITCH V_CPL_SWITCH(1U) - -#define S_MPS0 11 -#define V_MPS0(x) ((x) << S_MPS0) -#define F_MPS0 V_MPS0(1U) - -#define S_PM1_TX 10 -#define V_PM1_TX(x) ((x) << S_PM1_TX) -#define F_PM1_TX V_PM1_TX(1U) - -#define S_PM1_RX 9 -#define V_PM1_RX(x) ((x) << S_PM1_RX) -#define F_PM1_RX V_PM1_RX(1U) - -#define S_ULP2_TX 8 -#define V_ULP2_TX(x) ((x) << S_ULP2_TX) -#define F_ULP2_TX V_ULP2_TX(1U) - -#define S_ULP2_RX 7 -#define V_ULP2_RX(x) ((x) << S_ULP2_RX) -#define F_ULP2_RX V_ULP2_RX(1U) - -#define S_TP1 6 -#define V_TP1(x) ((x) << S_TP1) -#define F_TP1 V_TP1(1U) - -#define S_CIM 5 -#define V_CIM(x) ((x) << S_CIM) -#define F_CIM V_CIM(1U) - -#define S_MC7_CM 4 -#define V_MC7_CM(x) ((x) << S_MC7_CM) -#define F_MC7_CM V_MC7_CM(1U) - -#define S_MC7_PMTX 3 -#define V_MC7_PMTX(x) ((x) << S_MC7_PMTX) -#define F_MC7_PMTX V_MC7_PMTX(1U) - -#define S_MC7_PMRX 2 -#define V_MC7_PMRX(x) ((x) << S_MC7_PMRX) -#define F_MC7_PMRX V_MC7_PMRX(1U) - -#define S_PCIM0 1 -#define V_PCIM0(x) ((x) << S_PCIM0) -#define F_PCIM0 V_PCIM0(1U) - -#define S_SGE3 0 -#define V_SGE3(x) ((x) << S_SGE3) -#define F_SGE3 V_SGE3(1U) - -#define A_PL_INT_CAUSE0 0x6e4 - -#define A_PL_RST 0x6f0 - -#define S_FATALPERREN 4 -#define V_FATALPERREN(x) ((x) << S_FATALPERREN) -#define F_FATALPERREN V_FATALPERREN(1U) - -#define S_CRSTWRM 1 -#define V_CRSTWRM(x) ((x) << S_CRSTWRM) -#define F_CRSTWRM V_CRSTWRM(1U) - -#define A_PL_REV 0x6f4 - -#define A_PL_CLI 0x6f8 - -#define A_MC5_DB_CONFIG 0x704 - -#define S_TMTYPEHI 30 -#define V_TMTYPEHI(x) ((x) << S_TMTYPEHI) -#define F_TMTYPEHI V_TMTYPEHI(1U) - -#define S_TMPARTSIZE 28 -#define M_TMPARTSIZE 0x3 -#define V_TMPARTSIZE(x) ((x) << S_TMPARTSIZE) -#define G_TMPARTSIZE(x) (((x) >> S_TMPARTSIZE) & M_TMPARTSIZE) - -#define S_TMTYPE 26 -#define M_TMTYPE 0x3 -#define V_TMTYPE(x) ((x) << S_TMTYPE) -#define G_TMTYPE(x) (((x) >> S_TMTYPE) & M_TMTYPE) - -#define S_COMPEN 17 -#define V_COMPEN(x) ((x) << S_COMPEN) -#define F_COMPEN V_COMPEN(1U) - -#define S_PRTYEN 6 -#define V_PRTYEN(x) ((x) << S_PRTYEN) -#define F_PRTYEN V_PRTYEN(1U) - -#define S_MBUSEN 5 -#define V_MBUSEN(x) ((x) << S_MBUSEN) -#define F_MBUSEN V_MBUSEN(1U) - -#define S_DBGIEN 4 -#define V_DBGIEN(x) ((x) << S_DBGIEN) -#define F_DBGIEN V_DBGIEN(1U) - -#define S_TMRDY 2 -#define V_TMRDY(x) ((x) << S_TMRDY) -#define F_TMRDY V_TMRDY(1U) - -#define S_TMRST 1 -#define V_TMRST(x) ((x) << S_TMRST) -#define F_TMRST V_TMRST(1U) - -#define S_TMMODE 0 -#define V_TMMODE(x) ((x) << S_TMMODE) -#define F_TMMODE V_TMMODE(1U) - -#define F_TMMODE V_TMMODE(1U) - -#define A_MC5_DB_ROUTING_TABLE_INDEX 0x70c - -#define A_MC5_DB_FILTER_TABLE 0x710 - -#define A_MC5_DB_SERVER_INDEX 0x714 - -#define A_MC5_DB_RSP_LATENCY 0x720 - -#define S_RDLAT 16 -#define M_RDLAT 0x1f -#define V_RDLAT(x) ((x) << S_RDLAT) - -#define S_LRNLAT 8 -#define M_LRNLAT 0x1f -#define V_LRNLAT(x) ((x) << S_LRNLAT) - -#define S_SRCHLAT 0 -#define M_SRCHLAT 0x1f -#define V_SRCHLAT(x) ((x) << S_SRCHLAT) - -#define A_MC5_DB_PART_ID_INDEX 0x72c - -#define A_MC5_DB_INT_ENABLE 0x740 - -#define S_DELACTEMPTY 18 -#define V_DELACTEMPTY(x) ((x) << S_DELACTEMPTY) -#define F_DELACTEMPTY V_DELACTEMPTY(1U) - -#define S_DISPQPARERR 17 -#define V_DISPQPARERR(x) ((x) << S_DISPQPARERR) -#define F_DISPQPARERR V_DISPQPARERR(1U) - -#define S_REQQPARERR 16 -#define V_REQQPARERR(x) ((x) << S_REQQPARERR) -#define F_REQQPARERR V_REQQPARERR(1U) - -#define S_UNKNOWNCMD 15 -#define V_UNKNOWNCMD(x) ((x) << S_UNKNOWNCMD) -#define F_UNKNOWNCMD V_UNKNOWNCMD(1U) - -#define S_NFASRCHFAIL 8 -#define V_NFASRCHFAIL(x) ((x) << S_NFASRCHFAIL) -#define F_NFASRCHFAIL V_NFASRCHFAIL(1U) - -#define S_ACTRGNFULL 7 -#define V_ACTRGNFULL(x) ((x) << S_ACTRGNFULL) -#define F_ACTRGNFULL V_ACTRGNFULL(1U) - -#define S_PARITYERR 6 -#define V_PARITYERR(x) ((x) << S_PARITYERR) -#define F_PARITYERR V_PARITYERR(1U) - -#define A_MC5_DB_INT_CAUSE 0x744 - -#define A_MC5_DB_DBGI_CONFIG 0x774 - -#define A_MC5_DB_DBGI_REQ_CMD 0x778 - -#define A_MC5_DB_DBGI_REQ_ADDR0 0x77c - -#define A_MC5_DB_DBGI_REQ_ADDR1 0x780 - -#define A_MC5_DB_DBGI_REQ_ADDR2 0x784 - -#define A_MC5_DB_DBGI_REQ_DATA0 0x788 - -#define A_MC5_DB_DBGI_REQ_DATA1 0x78c - -#define A_MC5_DB_DBGI_REQ_DATA2 0x790 - -#define A_MC5_DB_DBGI_RSP_STATUS 0x7b0 - -#define S_DBGIRSPVALID 0 -#define V_DBGIRSPVALID(x) ((x) << S_DBGIRSPVALID) -#define F_DBGIRSPVALID V_DBGIRSPVALID(1U) - -#define A_MC5_DB_DBGI_RSP_DATA0 0x7b4 - -#define A_MC5_DB_DBGI_RSP_DATA1 0x7b8 - -#define A_MC5_DB_DBGI_RSP_DATA2 0x7bc - -#define A_MC5_DB_POPEN_DATA_WR_CMD 0x7cc - -#define A_MC5_DB_POPEN_MASK_WR_CMD 0x7d0 - -#define A_MC5_DB_AOPEN_SRCH_CMD 0x7d4 - -#define A_MC5_DB_AOPEN_LRN_CMD 0x7d8 - -#define A_MC5_DB_SYN_SRCH_CMD 0x7dc - -#define A_MC5_DB_SYN_LRN_CMD 0x7e0 - -#define A_MC5_DB_ACK_SRCH_CMD 0x7e4 - -#define A_MC5_DB_ACK_LRN_CMD 0x7e8 - -#define A_MC5_DB_ILOOKUP_CMD 0x7ec - -#define A_MC5_DB_ELOOKUP_CMD 0x7f0 - -#define A_MC5_DB_DATA_WRITE_CMD 0x7f4 - -#define A_MC5_DB_DATA_READ_CMD 0x7f8 - -#define XGMAC0_0_BASE_ADDR 0x800 - -#define A_XGM_TX_CTRL 0x800 - -#define S_TXEN 0 -#define V_TXEN(x) ((x) << S_TXEN) -#define F_TXEN V_TXEN(1U) - -#define A_XGM_TX_CFG 0x804 - -#define S_TXPAUSEEN 0 -#define V_TXPAUSEEN(x) ((x) << S_TXPAUSEEN) -#define F_TXPAUSEEN V_TXPAUSEEN(1U) - -#define A_XGM_TX_PAUSE_QUANTA 0x808 - -#define A_XGM_RX_CTRL 0x80c - -#define S_RXEN 0 -#define V_RXEN(x) ((x) << S_RXEN) -#define F_RXEN V_RXEN(1U) - -#define A_XGM_RX_CFG 0x810 - -#define S_DISPAUSEFRAMES 9 -#define V_DISPAUSEFRAMES(x) ((x) << S_DISPAUSEFRAMES) -#define F_DISPAUSEFRAMES V_DISPAUSEFRAMES(1U) - -#define S_EN1536BFRAMES 8 -#define V_EN1536BFRAMES(x) ((x) << S_EN1536BFRAMES) -#define F_EN1536BFRAMES V_EN1536BFRAMES(1U) - -#define S_ENJUMBO 7 -#define V_ENJUMBO(x) ((x) << S_ENJUMBO) -#define F_ENJUMBO V_ENJUMBO(1U) - -#define S_RMFCS 6 -#define V_RMFCS(x) ((x) << S_RMFCS) -#define F_RMFCS V_RMFCS(1U) - -#define S_ENHASHMCAST 2 -#define V_ENHASHMCAST(x) ((x) << S_ENHASHMCAST) -#define F_ENHASHMCAST V_ENHASHMCAST(1U) - -#define S_COPYALLFRAMES 0 -#define V_COPYALLFRAMES(x) ((x) << S_COPYALLFRAMES) -#define F_COPYALLFRAMES V_COPYALLFRAMES(1U) - -#define S_DISBCAST 1 -#define V_DISBCAST(x) ((x) << S_DISBCAST) -#define F_DISBCAST V_DISBCAST(1U) - -#define A_XGM_RX_HASH_LOW 0x814 - -#define A_XGM_RX_HASH_HIGH 0x818 - -#define A_XGM_RX_EXACT_MATCH_LOW_1 0x81c - -#define A_XGM_RX_EXACT_MATCH_HIGH_1 0x820 - -#define A_XGM_RX_EXACT_MATCH_LOW_2 0x824 - -#define A_XGM_RX_EXACT_MATCH_LOW_3 0x82c - -#define A_XGM_RX_EXACT_MATCH_LOW_4 0x834 - -#define A_XGM_RX_EXACT_MATCH_LOW_5 0x83c - -#define A_XGM_RX_EXACT_MATCH_LOW_6 0x844 - -#define A_XGM_RX_EXACT_MATCH_LOW_7 0x84c - -#define A_XGM_RX_EXACT_MATCH_LOW_8 0x854 - -#define A_XGM_INT_STATUS 0x86c - -#define S_LINKFAULTCHANGE 9 -#define V_LINKFAULTCHANGE(x) ((x) << S_LINKFAULTCHANGE) -#define F_LINKFAULTCHANGE V_LINKFAULTCHANGE(1U) - -#define A_XGM_XGM_INT_ENABLE 0x874 -#define A_XGM_XGM_INT_DISABLE 0x878 - -#define A_XGM_STAT_CTRL 0x880 - -#define S_CLRSTATS 2 -#define V_CLRSTATS(x) ((x) << S_CLRSTATS) -#define F_CLRSTATS V_CLRSTATS(1U) - -#define A_XGM_RXFIFO_CFG 0x884 - -#define S_RXFIFO_EMPTY 31 -#define V_RXFIFO_EMPTY(x) ((x) << S_RXFIFO_EMPTY) -#define F_RXFIFO_EMPTY V_RXFIFO_EMPTY(1U) - -#define S_RXFIFOPAUSEHWM 17 -#define M_RXFIFOPAUSEHWM 0xfff - -#define V_RXFIFOPAUSEHWM(x) ((x) << S_RXFIFOPAUSEHWM) - -#define G_RXFIFOPAUSEHWM(x) (((x) >> S_RXFIFOPAUSEHWM) & M_RXFIFOPAUSEHWM) - -#define S_RXFIFOPAUSELWM 5 -#define M_RXFIFOPAUSELWM 0xfff - -#define V_RXFIFOPAUSELWM(x) ((x) << S_RXFIFOPAUSELWM) - -#define G_RXFIFOPAUSELWM(x) (((x) >> S_RXFIFOPAUSELWM) & M_RXFIFOPAUSELWM) - -#define S_RXSTRFRWRD 1 -#define V_RXSTRFRWRD(x) ((x) << S_RXSTRFRWRD) -#define F_RXSTRFRWRD V_RXSTRFRWRD(1U) - -#define S_DISERRFRAMES 0 -#define V_DISERRFRAMES(x) ((x) << S_DISERRFRAMES) -#define F_DISERRFRAMES V_DISERRFRAMES(1U) - -#define A_XGM_TXFIFO_CFG 0x888 - -#define S_UNDERUNFIX 22 -#define V_UNDERUNFIX(x) ((x) << S_UNDERUNFIX) -#define F_UNDERUNFIX V_UNDERUNFIX(1U) - -#define S_TXIPG 13 -#define M_TXIPG 0xff -#define V_TXIPG(x) ((x) << S_TXIPG) -#define G_TXIPG(x) (((x) >> S_TXIPG) & M_TXIPG) - -#define S_TXFIFOTHRESH 4 -#define M_TXFIFOTHRESH 0x1ff - -#define V_TXFIFOTHRESH(x) ((x) << S_TXFIFOTHRESH) - -#define S_ENDROPPKT 21 -#define V_ENDROPPKT(x) ((x) << S_ENDROPPKT) -#define F_ENDROPPKT V_ENDROPPKT(1U) - -#define A_XGM_SERDES_CTRL 0x890 -#define A_XGM_SERDES_CTRL0 0x8e0 - -#define S_SERDESRESET_ 24 -#define V_SERDESRESET_(x) ((x) << S_SERDESRESET_) -#define F_SERDESRESET_ V_SERDESRESET_(1U) - -#define S_RXENABLE 4 -#define V_RXENABLE(x) ((x) << S_RXENABLE) -#define F_RXENABLE V_RXENABLE(1U) - -#define S_TXENABLE 3 -#define V_TXENABLE(x) ((x) << S_TXENABLE) -#define F_TXENABLE V_TXENABLE(1U) - -#define A_XGM_PAUSE_TIMER 0x890 - -#define A_XGM_RGMII_IMP 0x89c - -#define S_XGM_IMPSETUPDATE 6 -#define V_XGM_IMPSETUPDATE(x) ((x) << S_XGM_IMPSETUPDATE) -#define F_XGM_IMPSETUPDATE V_XGM_IMPSETUPDATE(1U) - -#define S_RGMIIIMPPD 3 -#define M_RGMIIIMPPD 0x7 -#define V_RGMIIIMPPD(x) ((x) << S_RGMIIIMPPD) - -#define S_RGMIIIMPPU 0 -#define M_RGMIIIMPPU 0x7 -#define V_RGMIIIMPPU(x) ((x) << S_RGMIIIMPPU) - -#define S_CALRESET 8 -#define V_CALRESET(x) ((x) << S_CALRESET) -#define F_CALRESET V_CALRESET(1U) - -#define S_CALUPDATE 7 -#define V_CALUPDATE(x) ((x) << S_CALUPDATE) -#define F_CALUPDATE V_CALUPDATE(1U) - -#define A_XGM_XAUI_IMP 0x8a0 - -#define S_CALBUSY 31 -#define V_CALBUSY(x) ((x) << S_CALBUSY) -#define F_CALBUSY V_CALBUSY(1U) - -#define S_XGM_CALFAULT 29 -#define V_XGM_CALFAULT(x) ((x) << S_XGM_CALFAULT) -#define F_XGM_CALFAULT V_XGM_CALFAULT(1U) - -#define S_CALIMP 24 -#define M_CALIMP 0x1f -#define V_CALIMP(x) ((x) << S_CALIMP) -#define G_CALIMP(x) (((x) >> S_CALIMP) & M_CALIMP) - -#define S_XAUIIMP 0 -#define M_XAUIIMP 0x7 -#define V_XAUIIMP(x) ((x) << S_XAUIIMP) - -#define A_XGM_RX_MAX_PKT_SIZE 0x8a8 - -#define S_RXMAXFRAMERSIZE 17 -#define M_RXMAXFRAMERSIZE 0x3fff -#define V_RXMAXFRAMERSIZE(x) ((x) << S_RXMAXFRAMERSIZE) -#define G_RXMAXFRAMERSIZE(x) (((x) >> S_RXMAXFRAMERSIZE) & M_RXMAXFRAMERSIZE) - -#define S_RXENFRAMER 14 -#define V_RXENFRAMER(x) ((x) << S_RXENFRAMER) -#define F_RXENFRAMER V_RXENFRAMER(1U) - -#define S_RXMAXPKTSIZE 0 -#define M_RXMAXPKTSIZE 0x3fff -#define V_RXMAXPKTSIZE(x) ((x) << S_RXMAXPKTSIZE) -#define G_RXMAXPKTSIZE(x) (((x) >> S_RXMAXPKTSIZE) & M_RXMAXPKTSIZE) - -#define A_XGM_RESET_CTRL 0x8ac - -#define S_XGMAC_STOP_EN 4 -#define V_XGMAC_STOP_EN(x) ((x) << S_XGMAC_STOP_EN) -#define F_XGMAC_STOP_EN V_XGMAC_STOP_EN(1U) - -#define S_XG2G_RESET_ 3 -#define V_XG2G_RESET_(x) ((x) << S_XG2G_RESET_) -#define F_XG2G_RESET_ V_XG2G_RESET_(1U) - -#define S_RGMII_RESET_ 2 -#define V_RGMII_RESET_(x) ((x) << S_RGMII_RESET_) -#define F_RGMII_RESET_ V_RGMII_RESET_(1U) - -#define S_PCS_RESET_ 1 -#define V_PCS_RESET_(x) ((x) << S_PCS_RESET_) -#define F_PCS_RESET_ V_PCS_RESET_(1U) - -#define S_MAC_RESET_ 0 -#define V_MAC_RESET_(x) ((x) << S_MAC_RESET_) -#define F_MAC_RESET_ V_MAC_RESET_(1U) - -#define A_XGM_PORT_CFG 0x8b8 - -#define S_CLKDIVRESET_ 3 -#define V_CLKDIVRESET_(x) ((x) << S_CLKDIVRESET_) -#define F_CLKDIVRESET_ V_CLKDIVRESET_(1U) - -#define S_PORTSPEED 1 -#define M_PORTSPEED 0x3 - -#define V_PORTSPEED(x) ((x) << S_PORTSPEED) - -#define S_ENRGMII 0 -#define V_ENRGMII(x) ((x) << S_ENRGMII) -#define F_ENRGMII V_ENRGMII(1U) - -#define A_XGM_INT_ENABLE 0x8d4 - -#define S_TXFIFO_PRTY_ERR 17 -#define M_TXFIFO_PRTY_ERR 0x7 - -#define V_TXFIFO_PRTY_ERR(x) ((x) << S_TXFIFO_PRTY_ERR) - -#define S_RXFIFO_PRTY_ERR 14 -#define M_RXFIFO_PRTY_ERR 0x7 - -#define V_RXFIFO_PRTY_ERR(x) ((x) << S_RXFIFO_PRTY_ERR) - -#define S_TXFIFO_UNDERRUN 13 -#define V_TXFIFO_UNDERRUN(x) ((x) << S_TXFIFO_UNDERRUN) -#define F_TXFIFO_UNDERRUN V_TXFIFO_UNDERRUN(1U) - -#define S_RXFIFO_OVERFLOW 12 -#define V_RXFIFO_OVERFLOW(x) ((x) << S_RXFIFO_OVERFLOW) -#define F_RXFIFO_OVERFLOW V_RXFIFO_OVERFLOW(1U) - -#define S_SERDES_LOS 4 -#define M_SERDES_LOS 0xf - -#define V_SERDES_LOS(x) ((x) << S_SERDES_LOS) - -#define S_XAUIPCSCTCERR 3 -#define V_XAUIPCSCTCERR(x) ((x) << S_XAUIPCSCTCERR) -#define F_XAUIPCSCTCERR V_XAUIPCSCTCERR(1U) - -#define S_XAUIPCSALIGNCHANGE 2 -#define V_XAUIPCSALIGNCHANGE(x) ((x) << S_XAUIPCSALIGNCHANGE) -#define F_XAUIPCSALIGNCHANGE V_XAUIPCSALIGNCHANGE(1U) - -#define S_XGM_INT 0 -#define V_XGM_INT(x) ((x) << S_XGM_INT) -#define F_XGM_INT V_XGM_INT(1U) - -#define A_XGM_INT_CAUSE 0x8d8 - -#define A_XGM_XAUI_ACT_CTRL 0x8dc - -#define S_TXACTENABLE 1 -#define V_TXACTENABLE(x) ((x) << S_TXACTENABLE) -#define F_TXACTENABLE V_TXACTENABLE(1U) - -#define A_XGM_SERDES_CTRL0 0x8e0 - -#define S_RESET3 23 -#define V_RESET3(x) ((x) << S_RESET3) -#define F_RESET3 V_RESET3(1U) - -#define S_RESET2 22 -#define V_RESET2(x) ((x) << S_RESET2) -#define F_RESET2 V_RESET2(1U) - -#define S_RESET1 21 -#define V_RESET1(x) ((x) << S_RESET1) -#define F_RESET1 V_RESET1(1U) - -#define S_RESET0 20 -#define V_RESET0(x) ((x) << S_RESET0) -#define F_RESET0 V_RESET0(1U) - -#define S_PWRDN3 19 -#define V_PWRDN3(x) ((x) << S_PWRDN3) -#define F_PWRDN3 V_PWRDN3(1U) - -#define S_PWRDN2 18 -#define V_PWRDN2(x) ((x) << S_PWRDN2) -#define F_PWRDN2 V_PWRDN2(1U) - -#define S_PWRDN1 17 -#define V_PWRDN1(x) ((x) << S_PWRDN1) -#define F_PWRDN1 V_PWRDN1(1U) - -#define S_PWRDN0 16 -#define V_PWRDN0(x) ((x) << S_PWRDN0) -#define F_PWRDN0 V_PWRDN0(1U) - -#define S_RESETPLL23 15 -#define V_RESETPLL23(x) ((x) << S_RESETPLL23) -#define F_RESETPLL23 V_RESETPLL23(1U) - -#define S_RESETPLL01 14 -#define V_RESETPLL01(x) ((x) << S_RESETPLL01) -#define F_RESETPLL01 V_RESETPLL01(1U) - -#define A_XGM_SERDES_STAT0 0x8f0 -#define A_XGM_SERDES_STAT1 0x8f4 -#define A_XGM_SERDES_STAT2 0x8f8 - -#define S_LOWSIG0 0 -#define V_LOWSIG0(x) ((x) << S_LOWSIG0) -#define F_LOWSIG0 V_LOWSIG0(1U) - -#define A_XGM_SERDES_STAT3 0x8fc - -#define A_XGM_STAT_TX_BYTE_LOW 0x900 - -#define A_XGM_STAT_TX_BYTE_HIGH 0x904 - -#define A_XGM_STAT_TX_FRAME_LOW 0x908 - -#define A_XGM_STAT_TX_FRAME_HIGH 0x90c - -#define A_XGM_STAT_TX_BCAST 0x910 - -#define A_XGM_STAT_TX_MCAST 0x914 - -#define A_XGM_STAT_TX_PAUSE 0x918 - -#define A_XGM_STAT_TX_64B_FRAMES 0x91c - -#define A_XGM_STAT_TX_65_127B_FRAMES 0x920 - -#define A_XGM_STAT_TX_128_255B_FRAMES 0x924 - -#define A_XGM_STAT_TX_256_511B_FRAMES 0x928 - -#define A_XGM_STAT_TX_512_1023B_FRAMES 0x92c - -#define A_XGM_STAT_TX_1024_1518B_FRAMES 0x930 - -#define A_XGM_STAT_TX_1519_MAXB_FRAMES 0x934 - -#define A_XGM_STAT_TX_ERR_FRAMES 0x938 - -#define A_XGM_STAT_RX_BYTES_LOW 0x93c - -#define A_XGM_STAT_RX_BYTES_HIGH 0x940 - -#define A_XGM_STAT_RX_FRAMES_LOW 0x944 - -#define A_XGM_STAT_RX_FRAMES_HIGH 0x948 - -#define A_XGM_STAT_RX_BCAST_FRAMES 0x94c - -#define A_XGM_STAT_RX_MCAST_FRAMES 0x950 - -#define A_XGM_STAT_RX_PAUSE_FRAMES 0x954 - -#define A_XGM_STAT_RX_64B_FRAMES 0x958 - -#define A_XGM_STAT_RX_65_127B_FRAMES 0x95c - -#define A_XGM_STAT_RX_128_255B_FRAMES 0x960 - -#define A_XGM_STAT_RX_256_511B_FRAMES 0x964 - -#define A_XGM_STAT_RX_512_1023B_FRAMES 0x968 - -#define A_XGM_STAT_RX_1024_1518B_FRAMES 0x96c - -#define A_XGM_STAT_RX_1519_MAXB_FRAMES 0x970 - -#define A_XGM_STAT_RX_SHORT_FRAMES 0x974 - -#define A_XGM_STAT_RX_OVERSIZE_FRAMES 0x978 - -#define A_XGM_STAT_RX_JABBER_FRAMES 0x97c - -#define A_XGM_STAT_RX_CRC_ERR_FRAMES 0x980 - -#define A_XGM_STAT_RX_LENGTH_ERR_FRAMES 0x984 - -#define A_XGM_STAT_RX_SYM_CODE_ERR_FRAMES 0x988 - -#define A_XGM_SERDES_STATUS0 0x98c - -#define A_XGM_SERDES_STATUS1 0x990 - -#define S_CMULOCK 31 -#define V_CMULOCK(x) ((x) << S_CMULOCK) -#define F_CMULOCK V_CMULOCK(1U) - -#define A_XGM_RX_MAX_PKT_SIZE_ERR_CNT 0x9a4 - -#define A_XGM_TX_SPI4_SOP_EOP_CNT 0x9a8 - -#define S_TXSPI4SOPCNT 16 -#define M_TXSPI4SOPCNT 0xffff -#define V_TXSPI4SOPCNT(x) ((x) << S_TXSPI4SOPCNT) -#define G_TXSPI4SOPCNT(x) (((x) >> S_TXSPI4SOPCNT) & M_TXSPI4SOPCNT) - -#define A_XGM_RX_SPI4_SOP_EOP_CNT 0x9ac - -#define XGMAC0_1_BASE_ADDR 0xa00 diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c deleted file mode 100644 index d6fa1777a343..000000000000 --- a/drivers/net/cxgb3/sge.c +++ /dev/null @@ -1,3303 +0,0 @@ -/* - * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "common.h" -#include "regs.h" -#include "sge_defs.h" -#include "t3_cpl.h" -#include "firmware_exports.h" -#include "cxgb3_offload.h" - -#define USE_GTS 0 - -#define SGE_RX_SM_BUF_SIZE 1536 - -#define SGE_RX_COPY_THRES 256 -#define SGE_RX_PULL_LEN 128 - -#define SGE_PG_RSVD SMP_CACHE_BYTES -/* - * Page chunk size for FL0 buffers if FL0 is to be populated with page chunks. - * It must be a divisor of PAGE_SIZE. If set to 0 FL0 will use sk_buffs - * directly. - */ -#define FL0_PG_CHUNK_SIZE 2048 -#define FL0_PG_ORDER 0 -#define FL0_PG_ALLOC_SIZE (PAGE_SIZE << FL0_PG_ORDER) -#define FL1_PG_CHUNK_SIZE (PAGE_SIZE > 8192 ? 16384 : 8192) -#define FL1_PG_ORDER (PAGE_SIZE > 8192 ? 0 : 1) -#define FL1_PG_ALLOC_SIZE (PAGE_SIZE << FL1_PG_ORDER) - -#define SGE_RX_DROP_THRES 16 -#define RX_RECLAIM_PERIOD (HZ/4) - -/* - * Max number of Rx buffers we replenish at a time. - */ -#define MAX_RX_REFILL 16U -/* - * Period of the Tx buffer reclaim timer. This timer does not need to run - * frequently as Tx buffers are usually reclaimed by new Tx packets. - */ -#define TX_RECLAIM_PERIOD (HZ / 4) -#define TX_RECLAIM_TIMER_CHUNK 64U -#define TX_RECLAIM_CHUNK 16U - -/* WR size in bytes */ -#define WR_LEN (WR_FLITS * 8) - -/* - * Types of Tx queues in each queue set. Order here matters, do not change. - */ -enum { TXQ_ETH, TXQ_OFLD, TXQ_CTRL }; - -/* Values for sge_txq.flags */ -enum { - TXQ_RUNNING = 1 << 0, /* fetch engine is running */ - TXQ_LAST_PKT_DB = 1 << 1, /* last packet rang the doorbell */ -}; - -struct tx_desc { - __be64 flit[TX_DESC_FLITS]; -}; - -struct rx_desc { - __be32 addr_lo; - __be32 len_gen; - __be32 gen2; - __be32 addr_hi; -}; - -struct tx_sw_desc { /* SW state per Tx descriptor */ - struct sk_buff *skb; - u8 eop; /* set if last descriptor for packet */ - u8 addr_idx; /* buffer index of first SGL entry in descriptor */ - u8 fragidx; /* first page fragment associated with descriptor */ - s8 sflit; /* start flit of first SGL entry in descriptor */ -}; - -struct rx_sw_desc { /* SW state per Rx descriptor */ - union { - struct sk_buff *skb; - struct fl_pg_chunk pg_chunk; - }; - DEFINE_DMA_UNMAP_ADDR(dma_addr); -}; - -struct rsp_desc { /* response queue descriptor */ - struct rss_header rss_hdr; - __be32 flags; - __be32 len_cq; - u8 imm_data[47]; - u8 intr_gen; -}; - -/* - * Holds unmapping information for Tx packets that need deferred unmapping. - * This structure lives at skb->head and must be allocated by callers. - */ -struct deferred_unmap_info { - struct pci_dev *pdev; - dma_addr_t addr[MAX_SKB_FRAGS + 1]; -}; - -/* - * Maps a number of flits to the number of Tx descriptors that can hold them. - * The formula is - * - * desc = 1 + (flits - 2) / (WR_FLITS - 1). - * - * HW allows up to 4 descriptors to be combined into a WR. - */ -static u8 flit_desc_map[] = { - 0, -#if SGE_NUM_GENBITS == 1 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 -#elif SGE_NUM_GENBITS == 2 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -#else -# error "SGE_NUM_GENBITS must be 1 or 2" -#endif -}; - -static inline struct sge_qset *fl_to_qset(const struct sge_fl *q, int qidx) -{ - return container_of(q, struct sge_qset, fl[qidx]); -} - -static inline struct sge_qset *rspq_to_qset(const struct sge_rspq *q) -{ - return container_of(q, struct sge_qset, rspq); -} - -static inline struct sge_qset *txq_to_qset(const struct sge_txq *q, int qidx) -{ - return container_of(q, struct sge_qset, txq[qidx]); -} - -/** - * refill_rspq - replenish an SGE response queue - * @adapter: the adapter - * @q: the response queue to replenish - * @credits: how many new responses to make available - * - * Replenishes a response queue by making the supplied number of responses - * available to HW. - */ -static inline void refill_rspq(struct adapter *adapter, - const struct sge_rspq *q, unsigned int credits) -{ - rmb(); - t3_write_reg(adapter, A_SG_RSPQ_CREDIT_RETURN, - V_RSPQ(q->cntxt_id) | V_CREDITS(credits)); -} - -/** - * need_skb_unmap - does the platform need unmapping of sk_buffs? - * - * Returns true if the platform needs sk_buff unmapping. The compiler - * optimizes away unnecessary code if this returns true. - */ -static inline int need_skb_unmap(void) -{ -#ifdef CONFIG_NEED_DMA_MAP_STATE - return 1; -#else - return 0; -#endif -} - -/** - * unmap_skb - unmap a packet main body and its page fragments - * @skb: the packet - * @q: the Tx queue containing Tx descriptors for the packet - * @cidx: index of Tx descriptor - * @pdev: the PCI device - * - * Unmap the main body of an sk_buff and its page fragments, if any. - * Because of the fairly complicated structure of our SGLs and the desire - * to conserve space for metadata, the information necessary to unmap an - * sk_buff is spread across the sk_buff itself (buffer lengths), the HW Tx - * descriptors (the physical addresses of the various data buffers), and - * the SW descriptor state (assorted indices). The send functions - * initialize the indices for the first packet descriptor so we can unmap - * the buffers held in the first Tx descriptor here, and we have enough - * information at this point to set the state for the next Tx descriptor. - * - * Note that it is possible to clean up the first descriptor of a packet - * before the send routines have written the next descriptors, but this - * race does not cause any problem. We just end up writing the unmapping - * info for the descriptor first. - */ -static inline void unmap_skb(struct sk_buff *skb, struct sge_txq *q, - unsigned int cidx, struct pci_dev *pdev) -{ - const struct sg_ent *sgp; - struct tx_sw_desc *d = &q->sdesc[cidx]; - int nfrags, frag_idx, curflit, j = d->addr_idx; - - sgp = (struct sg_ent *)&q->desc[cidx].flit[d->sflit]; - frag_idx = d->fragidx; - - if (frag_idx == 0 && skb_headlen(skb)) { - pci_unmap_single(pdev, be64_to_cpu(sgp->addr[0]), - skb_headlen(skb), PCI_DMA_TODEVICE); - j = 1; - } - - curflit = d->sflit + 1 + j; - nfrags = skb_shinfo(skb)->nr_frags; - - while (frag_idx < nfrags && curflit < WR_FLITS) { - pci_unmap_page(pdev, be64_to_cpu(sgp->addr[j]), - skb_shinfo(skb)->frags[frag_idx].size, - PCI_DMA_TODEVICE); - j ^= 1; - if (j == 0) { - sgp++; - curflit++; - } - curflit++; - frag_idx++; - } - - if (frag_idx < nfrags) { /* SGL continues into next Tx descriptor */ - d = cidx + 1 == q->size ? q->sdesc : d + 1; - d->fragidx = frag_idx; - d->addr_idx = j; - d->sflit = curflit - WR_FLITS - j; /* sflit can be -1 */ - } -} - -/** - * free_tx_desc - reclaims Tx descriptors and their buffers - * @adapter: the adapter - * @q: the Tx queue to reclaim descriptors from - * @n: the number of descriptors to reclaim - * - * Reclaims Tx descriptors from an SGE Tx queue and frees the associated - * Tx buffers. Called with the Tx queue lock held. - */ -static void free_tx_desc(struct adapter *adapter, struct sge_txq *q, - unsigned int n) -{ - struct tx_sw_desc *d; - struct pci_dev *pdev = adapter->pdev; - unsigned int cidx = q->cidx; - - const int need_unmap = need_skb_unmap() && - q->cntxt_id >= FW_TUNNEL_SGEEC_START; - - d = &q->sdesc[cidx]; - while (n--) { - if (d->skb) { /* an SGL is present */ - if (need_unmap) - unmap_skb(d->skb, q, cidx, pdev); - if (d->eop) { - kfree_skb(d->skb); - d->skb = NULL; - } - } - ++d; - if (++cidx == q->size) { - cidx = 0; - d = q->sdesc; - } - } - q->cidx = cidx; -} - -/** - * reclaim_completed_tx - reclaims completed Tx descriptors - * @adapter: the adapter - * @q: the Tx queue to reclaim completed descriptors from - * @chunk: maximum number of descriptors to reclaim - * - * Reclaims Tx descriptors that the SGE has indicated it has processed, - * and frees the associated buffers if possible. Called with the Tx - * queue's lock held. - */ -static inline unsigned int reclaim_completed_tx(struct adapter *adapter, - struct sge_txq *q, - unsigned int chunk) -{ - unsigned int reclaim = q->processed - q->cleaned; - - reclaim = min(chunk, reclaim); - if (reclaim) { - free_tx_desc(adapter, q, reclaim); - q->cleaned += reclaim; - q->in_use -= reclaim; - } - return q->processed - q->cleaned; -} - -/** - * should_restart_tx - are there enough resources to restart a Tx queue? - * @q: the Tx queue - * - * Checks if there are enough descriptors to restart a suspended Tx queue. - */ -static inline int should_restart_tx(const struct sge_txq *q) -{ - unsigned int r = q->processed - q->cleaned; - - return q->in_use - r < (q->size >> 1); -} - -static void clear_rx_desc(struct pci_dev *pdev, const struct sge_fl *q, - struct rx_sw_desc *d) -{ - if (q->use_pages && d->pg_chunk.page) { - (*d->pg_chunk.p_cnt)--; - if (!*d->pg_chunk.p_cnt) - pci_unmap_page(pdev, - d->pg_chunk.mapping, - q->alloc_size, PCI_DMA_FROMDEVICE); - - put_page(d->pg_chunk.page); - d->pg_chunk.page = NULL; - } else { - pci_unmap_single(pdev, dma_unmap_addr(d, dma_addr), - q->buf_size, PCI_DMA_FROMDEVICE); - kfree_skb(d->skb); - d->skb = NULL; - } -} - -/** - * free_rx_bufs - free the Rx buffers on an SGE free list - * @pdev: the PCI device associated with the adapter - * @rxq: the SGE free list to clean up - * - * Release the buffers on an SGE free-buffer Rx queue. HW fetching from - * this queue should be stopped before calling this function. - */ -static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q) -{ - unsigned int cidx = q->cidx; - - while (q->credits--) { - struct rx_sw_desc *d = &q->sdesc[cidx]; - - - clear_rx_desc(pdev, q, d); - if (++cidx == q->size) - cidx = 0; - } - - if (q->pg_chunk.page) { - __free_pages(q->pg_chunk.page, q->order); - q->pg_chunk.page = NULL; - } -} - -/** - * add_one_rx_buf - add a packet buffer to a free-buffer list - * @va: buffer start VA - * @len: the buffer length - * @d: the HW Rx descriptor to write - * @sd: the SW Rx descriptor to write - * @gen: the generation bit value - * @pdev: the PCI device associated with the adapter - * - * Add a buffer of the given length to the supplied HW and SW Rx - * descriptors. - */ -static inline int add_one_rx_buf(void *va, unsigned int len, - struct rx_desc *d, struct rx_sw_desc *sd, - unsigned int gen, struct pci_dev *pdev) -{ - dma_addr_t mapping; - - mapping = pci_map_single(pdev, va, len, PCI_DMA_FROMDEVICE); - if (unlikely(pci_dma_mapping_error(pdev, mapping))) - return -ENOMEM; - - dma_unmap_addr_set(sd, dma_addr, mapping); - - d->addr_lo = cpu_to_be32(mapping); - d->addr_hi = cpu_to_be32((u64) mapping >> 32); - wmb(); - d->len_gen = cpu_to_be32(V_FLD_GEN1(gen)); - d->gen2 = cpu_to_be32(V_FLD_GEN2(gen)); - return 0; -} - -static inline int add_one_rx_chunk(dma_addr_t mapping, struct rx_desc *d, - unsigned int gen) -{ - d->addr_lo = cpu_to_be32(mapping); - d->addr_hi = cpu_to_be32((u64) mapping >> 32); - wmb(); - d->len_gen = cpu_to_be32(V_FLD_GEN1(gen)); - d->gen2 = cpu_to_be32(V_FLD_GEN2(gen)); - return 0; -} - -static int alloc_pg_chunk(struct adapter *adapter, struct sge_fl *q, - struct rx_sw_desc *sd, gfp_t gfp, - unsigned int order) -{ - if (!q->pg_chunk.page) { - dma_addr_t mapping; - - q->pg_chunk.page = alloc_pages(gfp, order); - if (unlikely(!q->pg_chunk.page)) - return -ENOMEM; - q->pg_chunk.va = page_address(q->pg_chunk.page); - q->pg_chunk.p_cnt = q->pg_chunk.va + (PAGE_SIZE << order) - - SGE_PG_RSVD; - q->pg_chunk.offset = 0; - mapping = pci_map_page(adapter->pdev, q->pg_chunk.page, - 0, q->alloc_size, PCI_DMA_FROMDEVICE); - q->pg_chunk.mapping = mapping; - } - sd->pg_chunk = q->pg_chunk; - - prefetch(sd->pg_chunk.p_cnt); - - q->pg_chunk.offset += q->buf_size; - if (q->pg_chunk.offset == (PAGE_SIZE << order)) - q->pg_chunk.page = NULL; - else { - q->pg_chunk.va += q->buf_size; - get_page(q->pg_chunk.page); - } - - if (sd->pg_chunk.offset == 0) - *sd->pg_chunk.p_cnt = 1; - else - *sd->pg_chunk.p_cnt += 1; - - return 0; -} - -static inline void ring_fl_db(struct adapter *adap, struct sge_fl *q) -{ - if (q->pend_cred >= q->credits / 4) { - q->pend_cred = 0; - wmb(); - t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id)); - } -} - -/** - * refill_fl - refill an SGE free-buffer list - * @adapter: the adapter - * @q: the free-list to refill - * @n: the number of new buffers to allocate - * @gfp: the gfp flags for allocating new buffers - * - * (Re)populate an SGE free-buffer list with up to @n new packet buffers, - * allocated with the supplied gfp flags. The caller must assure that - * @n does not exceed the queue's capacity. - */ -static int refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp) -{ - struct rx_sw_desc *sd = &q->sdesc[q->pidx]; - struct rx_desc *d = &q->desc[q->pidx]; - unsigned int count = 0; - - while (n--) { - dma_addr_t mapping; - int err; - - if (q->use_pages) { - if (unlikely(alloc_pg_chunk(adap, q, sd, gfp, - q->order))) { -nomem: q->alloc_failed++; - break; - } - mapping = sd->pg_chunk.mapping + sd->pg_chunk.offset; - dma_unmap_addr_set(sd, dma_addr, mapping); - - add_one_rx_chunk(mapping, d, q->gen); - pci_dma_sync_single_for_device(adap->pdev, mapping, - q->buf_size - SGE_PG_RSVD, - PCI_DMA_FROMDEVICE); - } else { - void *buf_start; - - struct sk_buff *skb = alloc_skb(q->buf_size, gfp); - if (!skb) - goto nomem; - - sd->skb = skb; - buf_start = skb->data; - err = add_one_rx_buf(buf_start, q->buf_size, d, sd, - q->gen, adap->pdev); - if (unlikely(err)) { - clear_rx_desc(adap->pdev, q, sd); - break; - } - } - - d++; - sd++; - if (++q->pidx == q->size) { - q->pidx = 0; - q->gen ^= 1; - sd = q->sdesc; - d = q->desc; - } - count++; - } - - q->credits += count; - q->pend_cred += count; - ring_fl_db(adap, q); - - return count; -} - -static inline void __refill_fl(struct adapter *adap, struct sge_fl *fl) -{ - refill_fl(adap, fl, min(MAX_RX_REFILL, fl->size - fl->credits), - GFP_ATOMIC | __GFP_COMP); -} - -/** - * recycle_rx_buf - recycle a receive buffer - * @adapter: the adapter - * @q: the SGE free list - * @idx: index of buffer to recycle - * - * Recycles the specified buffer on the given free list by adding it at - * the next available slot on the list. - */ -static void recycle_rx_buf(struct adapter *adap, struct sge_fl *q, - unsigned int idx) -{ - struct rx_desc *from = &q->desc[idx]; - struct rx_desc *to = &q->desc[q->pidx]; - - q->sdesc[q->pidx] = q->sdesc[idx]; - to->addr_lo = from->addr_lo; /* already big endian */ - to->addr_hi = from->addr_hi; /* likewise */ - wmb(); - to->len_gen = cpu_to_be32(V_FLD_GEN1(q->gen)); - to->gen2 = cpu_to_be32(V_FLD_GEN2(q->gen)); - - if (++q->pidx == q->size) { - q->pidx = 0; - q->gen ^= 1; - } - - q->credits++; - q->pend_cred++; - ring_fl_db(adap, q); -} - -/** - * alloc_ring - allocate resources for an SGE descriptor ring - * @pdev: the PCI device - * @nelem: the number of descriptors - * @elem_size: the size of each descriptor - * @sw_size: the size of the SW state associated with each ring element - * @phys: the physical address of the allocated ring - * @metadata: address of the array holding the SW state for the ring - * - * Allocates resources for an SGE descriptor ring, such as Tx queues, - * free buffer lists, or response queues. Each SGE ring requires - * space for its HW descriptors plus, optionally, space for the SW state - * associated with each HW entry (the metadata). The function returns - * three values: the virtual address for the HW ring (the return value - * of the function), the physical address of the HW ring, and the address - * of the SW ring. - */ -static void *alloc_ring(struct pci_dev *pdev, size_t nelem, size_t elem_size, - size_t sw_size, dma_addr_t * phys, void *metadata) -{ - size_t len = nelem * elem_size; - void *s = NULL; - void *p = dma_alloc_coherent(&pdev->dev, len, phys, GFP_KERNEL); - - if (!p) - return NULL; - if (sw_size && metadata) { - s = kcalloc(nelem, sw_size, GFP_KERNEL); - - if (!s) { - dma_free_coherent(&pdev->dev, len, p, *phys); - return NULL; - } - *(void **)metadata = s; - } - memset(p, 0, len); - return p; -} - -/** - * t3_reset_qset - reset a sge qset - * @q: the queue set - * - * Reset the qset structure. - * the NAPI structure is preserved in the event of - * the qset's reincarnation, for example during EEH recovery. - */ -static void t3_reset_qset(struct sge_qset *q) -{ - if (q->adap && - !(q->adap->flags & NAPI_INIT)) { - memset(q, 0, sizeof(*q)); - return; - } - - q->adap = NULL; - memset(&q->rspq, 0, sizeof(q->rspq)); - memset(q->fl, 0, sizeof(struct sge_fl) * SGE_RXQ_PER_SET); - memset(q->txq, 0, sizeof(struct sge_txq) * SGE_TXQ_PER_SET); - q->txq_stopped = 0; - q->tx_reclaim_timer.function = NULL; /* for t3_stop_sge_timers() */ - q->rx_reclaim_timer.function = NULL; - q->nomem = 0; - napi_free_frags(&q->napi); -} - - -/** - * free_qset - free the resources of an SGE queue set - * @adapter: the adapter owning the queue set - * @q: the queue set - * - * Release the HW and SW resources associated with an SGE queue set, such - * as HW contexts, packet buffers, and descriptor rings. Traffic to the - * queue set must be quiesced prior to calling this. - */ -static void t3_free_qset(struct adapter *adapter, struct sge_qset *q) -{ - int i; - struct pci_dev *pdev = adapter->pdev; - - for (i = 0; i < SGE_RXQ_PER_SET; ++i) - if (q->fl[i].desc) { - spin_lock_irq(&adapter->sge.reg_lock); - t3_sge_disable_fl(adapter, q->fl[i].cntxt_id); - spin_unlock_irq(&adapter->sge.reg_lock); - free_rx_bufs(pdev, &q->fl[i]); - kfree(q->fl[i].sdesc); - dma_free_coherent(&pdev->dev, - q->fl[i].size * - sizeof(struct rx_desc), q->fl[i].desc, - q->fl[i].phys_addr); - } - - for (i = 0; i < SGE_TXQ_PER_SET; ++i) - if (q->txq[i].desc) { - spin_lock_irq(&adapter->sge.reg_lock); - t3_sge_enable_ecntxt(adapter, q->txq[i].cntxt_id, 0); - spin_unlock_irq(&adapter->sge.reg_lock); - if (q->txq[i].sdesc) { - free_tx_desc(adapter, &q->txq[i], - q->txq[i].in_use); - kfree(q->txq[i].sdesc); - } - dma_free_coherent(&pdev->dev, - q->txq[i].size * - sizeof(struct tx_desc), - q->txq[i].desc, q->txq[i].phys_addr); - __skb_queue_purge(&q->txq[i].sendq); - } - - if (q->rspq.desc) { - spin_lock_irq(&adapter->sge.reg_lock); - t3_sge_disable_rspcntxt(adapter, q->rspq.cntxt_id); - spin_unlock_irq(&adapter->sge.reg_lock); - dma_free_coherent(&pdev->dev, - q->rspq.size * sizeof(struct rsp_desc), - q->rspq.desc, q->rspq.phys_addr); - } - - t3_reset_qset(q); -} - -/** - * init_qset_cntxt - initialize an SGE queue set context info - * @qs: the queue set - * @id: the queue set id - * - * Initializes the TIDs and context ids for the queues of a queue set. - */ -static void init_qset_cntxt(struct sge_qset *qs, unsigned int id) -{ - qs->rspq.cntxt_id = id; - qs->fl[0].cntxt_id = 2 * id; - qs->fl[1].cntxt_id = 2 * id + 1; - qs->txq[TXQ_ETH].cntxt_id = FW_TUNNEL_SGEEC_START + id; - qs->txq[TXQ_ETH].token = FW_TUNNEL_TID_START + id; - qs->txq[TXQ_OFLD].cntxt_id = FW_OFLD_SGEEC_START + id; - qs->txq[TXQ_CTRL].cntxt_id = FW_CTRL_SGEEC_START + id; - qs->txq[TXQ_CTRL].token = FW_CTRL_TID_START + id; -} - -/** - * sgl_len - calculates the size of an SGL of the given capacity - * @n: the number of SGL entries - * - * Calculates the number of flits needed for a scatter/gather list that - * can hold the given number of entries. - */ -static inline unsigned int sgl_len(unsigned int n) -{ - /* alternatively: 3 * (n / 2) + 2 * (n & 1) */ - return (3 * n) / 2 + (n & 1); -} - -/** - * flits_to_desc - returns the num of Tx descriptors for the given flits - * @n: the number of flits - * - * Calculates the number of Tx descriptors needed for the supplied number - * of flits. - */ -static inline unsigned int flits_to_desc(unsigned int n) -{ - BUG_ON(n >= ARRAY_SIZE(flit_desc_map)); - return flit_desc_map[n]; -} - -/** - * get_packet - return the next ingress packet buffer from a free list - * @adap: the adapter that received the packet - * @fl: the SGE free list holding the packet - * @len: the packet length including any SGE padding - * @drop_thres: # of remaining buffers before we start dropping packets - * - * Get the next packet from a free list and complete setup of the - * sk_buff. If the packet is small we make a copy and recycle the - * original buffer, otherwise we use the original buffer itself. If a - * positive drop threshold is supplied packets are dropped and their - * buffers recycled if (a) the number of remaining buffers is under the - * threshold and the packet is too big to copy, or (b) the packet should - * be copied but there is no memory for the copy. - */ -static struct sk_buff *get_packet(struct adapter *adap, struct sge_fl *fl, - unsigned int len, unsigned int drop_thres) -{ - struct sk_buff *skb = NULL; - struct rx_sw_desc *sd = &fl->sdesc[fl->cidx]; - - prefetch(sd->skb->data); - fl->credits--; - - if (len <= SGE_RX_COPY_THRES) { - skb = alloc_skb(len, GFP_ATOMIC); - if (likely(skb != NULL)) { - __skb_put(skb, len); - pci_dma_sync_single_for_cpu(adap->pdev, - dma_unmap_addr(sd, dma_addr), len, - PCI_DMA_FROMDEVICE); - memcpy(skb->data, sd->skb->data, len); - pci_dma_sync_single_for_device(adap->pdev, - dma_unmap_addr(sd, dma_addr), len, - PCI_DMA_FROMDEVICE); - } else if (!drop_thres) - goto use_orig_buf; -recycle: - recycle_rx_buf(adap, fl, fl->cidx); - return skb; - } - - if (unlikely(fl->credits < drop_thres) && - refill_fl(adap, fl, min(MAX_RX_REFILL, fl->size - fl->credits - 1), - GFP_ATOMIC | __GFP_COMP) == 0) - goto recycle; - -use_orig_buf: - pci_unmap_single(adap->pdev, dma_unmap_addr(sd, dma_addr), - fl->buf_size, PCI_DMA_FROMDEVICE); - skb = sd->skb; - skb_put(skb, len); - __refill_fl(adap, fl); - return skb; -} - -/** - * get_packet_pg - return the next ingress packet buffer from a free list - * @adap: the adapter that received the packet - * @fl: the SGE free list holding the packet - * @len: the packet length including any SGE padding - * @drop_thres: # of remaining buffers before we start dropping packets - * - * Get the next packet from a free list populated with page chunks. - * If the packet is small we make a copy and recycle the original buffer, - * otherwise we attach the original buffer as a page fragment to a fresh - * sk_buff. If a positive drop threshold is supplied packets are dropped - * and their buffers recycled if (a) the number of remaining buffers is - * under the threshold and the packet is too big to copy, or (b) there's - * no system memory. - * - * Note: this function is similar to @get_packet but deals with Rx buffers - * that are page chunks rather than sk_buffs. - */ -static struct sk_buff *get_packet_pg(struct adapter *adap, struct sge_fl *fl, - struct sge_rspq *q, unsigned int len, - unsigned int drop_thres) -{ - struct sk_buff *newskb, *skb; - struct rx_sw_desc *sd = &fl->sdesc[fl->cidx]; - - dma_addr_t dma_addr = dma_unmap_addr(sd, dma_addr); - - newskb = skb = q->pg_skb; - if (!skb && (len <= SGE_RX_COPY_THRES)) { - newskb = alloc_skb(len, GFP_ATOMIC); - if (likely(newskb != NULL)) { - __skb_put(newskb, len); - pci_dma_sync_single_for_cpu(adap->pdev, dma_addr, len, - PCI_DMA_FROMDEVICE); - memcpy(newskb->data, sd->pg_chunk.va, len); - pci_dma_sync_single_for_device(adap->pdev, dma_addr, - len, - PCI_DMA_FROMDEVICE); - } else if (!drop_thres) - return NULL; -recycle: - fl->credits--; - recycle_rx_buf(adap, fl, fl->cidx); - q->rx_recycle_buf++; - return newskb; - } - - if (unlikely(q->rx_recycle_buf || (!skb && fl->credits <= drop_thres))) - goto recycle; - - prefetch(sd->pg_chunk.p_cnt); - - if (!skb) - newskb = alloc_skb(SGE_RX_PULL_LEN, GFP_ATOMIC); - - if (unlikely(!newskb)) { - if (!drop_thres) - return NULL; - goto recycle; - } - - pci_dma_sync_single_for_cpu(adap->pdev, dma_addr, len, - PCI_DMA_FROMDEVICE); - (*sd->pg_chunk.p_cnt)--; - if (!*sd->pg_chunk.p_cnt && sd->pg_chunk.page != fl->pg_chunk.page) - pci_unmap_page(adap->pdev, - sd->pg_chunk.mapping, - fl->alloc_size, - PCI_DMA_FROMDEVICE); - if (!skb) { - __skb_put(newskb, SGE_RX_PULL_LEN); - memcpy(newskb->data, sd->pg_chunk.va, SGE_RX_PULL_LEN); - skb_fill_page_desc(newskb, 0, sd->pg_chunk.page, - sd->pg_chunk.offset + SGE_RX_PULL_LEN, - len - SGE_RX_PULL_LEN); - newskb->len = len; - newskb->data_len = len - SGE_RX_PULL_LEN; - newskb->truesize += newskb->data_len; - } else { - skb_fill_page_desc(newskb, skb_shinfo(newskb)->nr_frags, - sd->pg_chunk.page, - sd->pg_chunk.offset, len); - newskb->len += len; - newskb->data_len += len; - newskb->truesize += len; - } - - fl->credits--; - /* - * We do not refill FLs here, we let the caller do it to overlap a - * prefetch. - */ - return newskb; -} - -/** - * get_imm_packet - return the next ingress packet buffer from a response - * @resp: the response descriptor containing the packet data - * - * Return a packet containing the immediate data of the given response. - */ -static inline struct sk_buff *get_imm_packet(const struct rsp_desc *resp) -{ - struct sk_buff *skb = alloc_skb(IMMED_PKT_SIZE, GFP_ATOMIC); - - if (skb) { - __skb_put(skb, IMMED_PKT_SIZE); - skb_copy_to_linear_data(skb, resp->imm_data, IMMED_PKT_SIZE); - } - return skb; -} - -/** - * calc_tx_descs - calculate the number of Tx descriptors for a packet - * @skb: the packet - * - * Returns the number of Tx descriptors needed for the given Ethernet - * packet. Ethernet packets require addition of WR and CPL headers. - */ -static inline unsigned int calc_tx_descs(const struct sk_buff *skb) -{ - unsigned int flits; - - if (skb->len <= WR_LEN - sizeof(struct cpl_tx_pkt)) - return 1; - - flits = sgl_len(skb_shinfo(skb)->nr_frags + 1) + 2; - if (skb_shinfo(skb)->gso_size) - flits++; - return flits_to_desc(flits); -} - -/** - * make_sgl - populate a scatter/gather list for a packet - * @skb: the packet - * @sgp: the SGL to populate - * @start: start address of skb main body data to include in the SGL - * @len: length of skb main body data to include in the SGL - * @pdev: the PCI device - * - * Generates a scatter/gather list for the buffers that make up a packet - * and returns the SGL size in 8-byte words. The caller must size the SGL - * appropriately. - */ -static inline unsigned int make_sgl(const struct sk_buff *skb, - struct sg_ent *sgp, unsigned char *start, - unsigned int len, struct pci_dev *pdev) -{ - dma_addr_t mapping; - unsigned int i, j = 0, nfrags; - - if (len) { - mapping = pci_map_single(pdev, start, len, PCI_DMA_TODEVICE); - sgp->len[0] = cpu_to_be32(len); - sgp->addr[0] = cpu_to_be64(mapping); - j = 1; - } - - nfrags = skb_shinfo(skb)->nr_frags; - for (i = 0; i < nfrags; i++) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - - mapping = pci_map_page(pdev, frag->page, frag->page_offset, - frag->size, PCI_DMA_TODEVICE); - sgp->len[j] = cpu_to_be32(frag->size); - sgp->addr[j] = cpu_to_be64(mapping); - j ^= 1; - if (j == 0) - ++sgp; - } - if (j) - sgp->len[j] = 0; - return ((nfrags + (len != 0)) * 3) / 2 + j; -} - -/** - * check_ring_tx_db - check and potentially ring a Tx queue's doorbell - * @adap: the adapter - * @q: the Tx queue - * - * Ring the doorbel if a Tx queue is asleep. There is a natural race, - * where the HW is going to sleep just after we checked, however, - * then the interrupt handler will detect the outstanding TX packet - * and ring the doorbell for us. - * - * When GTS is disabled we unconditionally ring the doorbell. - */ -static inline void check_ring_tx_db(struct adapter *adap, struct sge_txq *q) -{ -#if USE_GTS - clear_bit(TXQ_LAST_PKT_DB, &q->flags); - if (test_and_set_bit(TXQ_RUNNING, &q->flags) == 0) { - set_bit(TXQ_LAST_PKT_DB, &q->flags); - t3_write_reg(adap, A_SG_KDOORBELL, - F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); - } -#else - wmb(); /* write descriptors before telling HW */ - t3_write_reg(adap, A_SG_KDOORBELL, - F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); -#endif -} - -static inline void wr_gen2(struct tx_desc *d, unsigned int gen) -{ -#if SGE_NUM_GENBITS == 2 - d->flit[TX_DESC_FLITS - 1] = cpu_to_be64(gen); -#endif -} - -/** - * write_wr_hdr_sgl - write a WR header and, optionally, SGL - * @ndesc: number of Tx descriptors spanned by the SGL - * @skb: the packet corresponding to the WR - * @d: first Tx descriptor to be written - * @pidx: index of above descriptors - * @q: the SGE Tx queue - * @sgl: the SGL - * @flits: number of flits to the start of the SGL in the first descriptor - * @sgl_flits: the SGL size in flits - * @gen: the Tx descriptor generation - * @wr_hi: top 32 bits of WR header based on WR type (big endian) - * @wr_lo: low 32 bits of WR header based on WR type (big endian) - * - * Write a work request header and an associated SGL. If the SGL is - * small enough to fit into one Tx descriptor it has already been written - * and we just need to write the WR header. Otherwise we distribute the - * SGL across the number of descriptors it spans. - */ -static void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb, - struct tx_desc *d, unsigned int pidx, - const struct sge_txq *q, - const struct sg_ent *sgl, - unsigned int flits, unsigned int sgl_flits, - unsigned int gen, __be32 wr_hi, - __be32 wr_lo) -{ - struct work_request_hdr *wrp = (struct work_request_hdr *)d; - struct tx_sw_desc *sd = &q->sdesc[pidx]; - - sd->skb = skb; - if (need_skb_unmap()) { - sd->fragidx = 0; - sd->addr_idx = 0; - sd->sflit = flits; - } - - if (likely(ndesc == 1)) { - sd->eop = 1; - wrp->wr_hi = htonl(F_WR_SOP | F_WR_EOP | V_WR_DATATYPE(1) | - V_WR_SGLSFLT(flits)) | wr_hi; - wmb(); - wrp->wr_lo = htonl(V_WR_LEN(flits + sgl_flits) | - V_WR_GEN(gen)) | wr_lo; - wr_gen2(d, gen); - } else { - unsigned int ogen = gen; - const u64 *fp = (const u64 *)sgl; - struct work_request_hdr *wp = wrp; - - wrp->wr_hi = htonl(F_WR_SOP | V_WR_DATATYPE(1) | - V_WR_SGLSFLT(flits)) | wr_hi; - - while (sgl_flits) { - unsigned int avail = WR_FLITS - flits; - - if (avail > sgl_flits) - avail = sgl_flits; - memcpy(&d->flit[flits], fp, avail * sizeof(*fp)); - sgl_flits -= avail; - ndesc--; - if (!sgl_flits) - break; - - fp += avail; - d++; - sd->eop = 0; - sd++; - if (++pidx == q->size) { - pidx = 0; - gen ^= 1; - d = q->desc; - sd = q->sdesc; - } - - sd->skb = skb; - wrp = (struct work_request_hdr *)d; - wrp->wr_hi = htonl(V_WR_DATATYPE(1) | - V_WR_SGLSFLT(1)) | wr_hi; - wrp->wr_lo = htonl(V_WR_LEN(min(WR_FLITS, - sgl_flits + 1)) | - V_WR_GEN(gen)) | wr_lo; - wr_gen2(d, gen); - flits = 1; - } - sd->eop = 1; - wrp->wr_hi |= htonl(F_WR_EOP); - wmb(); - wp->wr_lo = htonl(V_WR_LEN(WR_FLITS) | V_WR_GEN(ogen)) | wr_lo; - wr_gen2((struct tx_desc *)wp, ogen); - WARN_ON(ndesc != 0); - } -} - -/** - * write_tx_pkt_wr - write a TX_PKT work request - * @adap: the adapter - * @skb: the packet to send - * @pi: the egress interface - * @pidx: index of the first Tx descriptor to write - * @gen: the generation value to use - * @q: the Tx queue - * @ndesc: number of descriptors the packet will occupy - * @compl: the value of the COMPL bit to use - * - * Generate a TX_PKT work request to send the supplied packet. - */ -static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb, - const struct port_info *pi, - unsigned int pidx, unsigned int gen, - struct sge_txq *q, unsigned int ndesc, - unsigned int compl) -{ - unsigned int flits, sgl_flits, cntrl, tso_info; - struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1]; - struct tx_desc *d = &q->desc[pidx]; - struct cpl_tx_pkt *cpl = (struct cpl_tx_pkt *)d; - - cpl->len = htonl(skb->len); - cntrl = V_TXPKT_INTF(pi->port_id); - - if (vlan_tx_tag_present(skb)) - cntrl |= F_TXPKT_VLAN_VLD | V_TXPKT_VLAN(vlan_tx_tag_get(skb)); - - tso_info = V_LSO_MSS(skb_shinfo(skb)->gso_size); - if (tso_info) { - int eth_type; - struct cpl_tx_pkt_lso *hdr = (struct cpl_tx_pkt_lso *)cpl; - - d->flit[2] = 0; - cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT_LSO); - hdr->cntrl = htonl(cntrl); - eth_type = skb_network_offset(skb) == ETH_HLEN ? - CPL_ETH_II : CPL_ETH_II_VLAN; - tso_info |= V_LSO_ETH_TYPE(eth_type) | - V_LSO_IPHDR_WORDS(ip_hdr(skb)->ihl) | - V_LSO_TCPHDR_WORDS(tcp_hdr(skb)->doff); - hdr->lso_info = htonl(tso_info); - flits = 3; - } else { - cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT); - cntrl |= F_TXPKT_IPCSUM_DIS; /* SW calculates IP csum */ - cntrl |= V_TXPKT_L4CSUM_DIS(skb->ip_summed != CHECKSUM_PARTIAL); - cpl->cntrl = htonl(cntrl); - - if (skb->len <= WR_LEN - sizeof(*cpl)) { - q->sdesc[pidx].skb = NULL; - if (!skb->data_len) - skb_copy_from_linear_data(skb, &d->flit[2], - skb->len); - else - skb_copy_bits(skb, 0, &d->flit[2], skb->len); - - flits = (skb->len + 7) / 8 + 2; - cpl->wr.wr_hi = htonl(V_WR_BCNTLFLT(skb->len & 7) | - V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) - | F_WR_SOP | F_WR_EOP | compl); - wmb(); - cpl->wr.wr_lo = htonl(V_WR_LEN(flits) | V_WR_GEN(gen) | - V_WR_TID(q->token)); - wr_gen2(d, gen); - kfree_skb(skb); - return; - } - - flits = 2; - } - - sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl; - sgl_flits = make_sgl(skb, sgp, skb->data, skb_headlen(skb), adap->pdev); - - write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, gen, - htonl(V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) | compl), - htonl(V_WR_TID(q->token))); -} - -static inline void t3_stop_tx_queue(struct netdev_queue *txq, - struct sge_qset *qs, struct sge_txq *q) -{ - netif_tx_stop_queue(txq); - set_bit(TXQ_ETH, &qs->txq_stopped); - q->stops++; -} - -/** - * eth_xmit - add a packet to the Ethernet Tx queue - * @skb: the packet - * @dev: the egress net device - * - * Add a packet to an SGE Tx queue. Runs with softirqs disabled. - */ -netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) -{ - int qidx; - unsigned int ndesc, pidx, credits, gen, compl; - const struct port_info *pi = netdev_priv(dev); - struct adapter *adap = pi->adapter; - struct netdev_queue *txq; - struct sge_qset *qs; - struct sge_txq *q; - - /* - * The chip min packet length is 9 octets but play safe and reject - * anything shorter than an Ethernet header. - */ - if (unlikely(skb->len < ETH_HLEN)) { - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - qidx = skb_get_queue_mapping(skb); - qs = &pi->qs[qidx]; - q = &qs->txq[TXQ_ETH]; - txq = netdev_get_tx_queue(dev, qidx); - - reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK); - - credits = q->size - q->in_use; - ndesc = calc_tx_descs(skb); - - if (unlikely(credits < ndesc)) { - t3_stop_tx_queue(txq, qs, q); - dev_err(&adap->pdev->dev, - "%s: Tx ring %u full while queue awake!\n", - dev->name, q->cntxt_id & 7); - return NETDEV_TX_BUSY; - } - - q->in_use += ndesc; - if (unlikely(credits - ndesc < q->stop_thres)) { - t3_stop_tx_queue(txq, qs, q); - - if (should_restart_tx(q) && - test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) { - q->restarts++; - netif_tx_start_queue(txq); - } - } - - gen = q->gen; - q->unacked += ndesc; - compl = (q->unacked & 8) << (S_WR_COMPL - 3); - q->unacked &= 7; - pidx = q->pidx; - q->pidx += ndesc; - if (q->pidx >= q->size) { - q->pidx -= q->size; - q->gen ^= 1; - } - - /* update port statistics */ - if (skb->ip_summed == CHECKSUM_COMPLETE) - qs->port_stats[SGE_PSTAT_TX_CSUM]++; - if (skb_shinfo(skb)->gso_size) - qs->port_stats[SGE_PSTAT_TSO]++; - if (vlan_tx_tag_present(skb)) - qs->port_stats[SGE_PSTAT_VLANINS]++; - - /* - * We do not use Tx completion interrupts to free DMAd Tx packets. - * This is good for performance but means that we rely on new Tx - * packets arriving to run the destructors of completed packets, - * which open up space in their sockets' send queues. Sometimes - * we do not get such new packets causing Tx to stall. A single - * UDP transmitter is a good example of this situation. We have - * a clean up timer that periodically reclaims completed packets - * but it doesn't run often enough (nor do we want it to) to prevent - * lengthy stalls. A solution to this problem is to run the - * destructor early, after the packet is queued but before it's DMAd. - * A cons is that we lie to socket memory accounting, but the amount - * of extra memory is reasonable (limited by the number of Tx - * descriptors), the packets do actually get freed quickly by new - * packets almost always, and for protocols like TCP that wait for - * acks to really free up the data the extra memory is even less. - * On the positive side we run the destructors on the sending CPU - * rather than on a potentially different completing CPU, usually a - * good thing. We also run them without holding our Tx queue lock, - * unlike what reclaim_completed_tx() would otherwise do. - * - * Run the destructor before telling the DMA engine about the packet - * to make sure it doesn't complete and get freed prematurely. - */ - if (likely(!skb_shared(skb))) - skb_orphan(skb); - - write_tx_pkt_wr(adap, skb, pi, pidx, gen, q, ndesc, compl); - check_ring_tx_db(adap, q); - return NETDEV_TX_OK; -} - -/** - * write_imm - write a packet into a Tx descriptor as immediate data - * @d: the Tx descriptor to write - * @skb: the packet - * @len: the length of packet data to write as immediate data - * @gen: the generation bit value to write - * - * Writes a packet as immediate data into a Tx descriptor. The packet - * contains a work request at its beginning. We must write the packet - * carefully so the SGE doesn't read it accidentally before it's written - * in its entirety. - */ -static inline void write_imm(struct tx_desc *d, struct sk_buff *skb, - unsigned int len, unsigned int gen) -{ - struct work_request_hdr *from = (struct work_request_hdr *)skb->data; - struct work_request_hdr *to = (struct work_request_hdr *)d; - - if (likely(!skb->data_len)) - memcpy(&to[1], &from[1], len - sizeof(*from)); - else - skb_copy_bits(skb, sizeof(*from), &to[1], len - sizeof(*from)); - - to->wr_hi = from->wr_hi | htonl(F_WR_SOP | F_WR_EOP | - V_WR_BCNTLFLT(len & 7)); - wmb(); - to->wr_lo = from->wr_lo | htonl(V_WR_GEN(gen) | - V_WR_LEN((len + 7) / 8)); - wr_gen2(d, gen); - kfree_skb(skb); -} - -/** - * check_desc_avail - check descriptor availability on a send queue - * @adap: the adapter - * @q: the send queue - * @skb: the packet needing the descriptors - * @ndesc: the number of Tx descriptors needed - * @qid: the Tx queue number in its queue set (TXQ_OFLD or TXQ_CTRL) - * - * Checks if the requested number of Tx descriptors is available on an - * SGE send queue. If the queue is already suspended or not enough - * descriptors are available the packet is queued for later transmission. - * Must be called with the Tx queue locked. - * - * Returns 0 if enough descriptors are available, 1 if there aren't - * enough descriptors and the packet has been queued, and 2 if the caller - * needs to retry because there weren't enough descriptors at the - * beginning of the call but some freed up in the mean time. - */ -static inline int check_desc_avail(struct adapter *adap, struct sge_txq *q, - struct sk_buff *skb, unsigned int ndesc, - unsigned int qid) -{ - if (unlikely(!skb_queue_empty(&q->sendq))) { - addq_exit:__skb_queue_tail(&q->sendq, skb); - return 1; - } - if (unlikely(q->size - q->in_use < ndesc)) { - struct sge_qset *qs = txq_to_qset(q, qid); - - set_bit(qid, &qs->txq_stopped); - smp_mb__after_clear_bit(); - - if (should_restart_tx(q) && - test_and_clear_bit(qid, &qs->txq_stopped)) - return 2; - - q->stops++; - goto addq_exit; - } - return 0; -} - -/** - * reclaim_completed_tx_imm - reclaim completed control-queue Tx descs - * @q: the SGE control Tx queue - * - * This is a variant of reclaim_completed_tx() that is used for Tx queues - * that send only immediate data (presently just the control queues) and - * thus do not have any sk_buffs to release. - */ -static inline void reclaim_completed_tx_imm(struct sge_txq *q) -{ - unsigned int reclaim = q->processed - q->cleaned; - - q->in_use -= reclaim; - q->cleaned += reclaim; -} - -static inline int immediate(const struct sk_buff *skb) -{ - return skb->len <= WR_LEN; -} - -/** - * ctrl_xmit - send a packet through an SGE control Tx queue - * @adap: the adapter - * @q: the control queue - * @skb: the packet - * - * Send a packet through an SGE control Tx queue. Packets sent through - * a control queue must fit entirely as immediate data in a single Tx - * descriptor and have no page fragments. - */ -static int ctrl_xmit(struct adapter *adap, struct sge_txq *q, - struct sk_buff *skb) -{ - int ret; - struct work_request_hdr *wrp = (struct work_request_hdr *)skb->data; - - if (unlikely(!immediate(skb))) { - WARN_ON(1); - dev_kfree_skb(skb); - return NET_XMIT_SUCCESS; - } - - wrp->wr_hi |= htonl(F_WR_SOP | F_WR_EOP); - wrp->wr_lo = htonl(V_WR_TID(q->token)); - - spin_lock(&q->lock); - again:reclaim_completed_tx_imm(q); - - ret = check_desc_avail(adap, q, skb, 1, TXQ_CTRL); - if (unlikely(ret)) { - if (ret == 1) { - spin_unlock(&q->lock); - return NET_XMIT_CN; - } - goto again; - } - - write_imm(&q->desc[q->pidx], skb, skb->len, q->gen); - - q->in_use++; - if (++q->pidx >= q->size) { - q->pidx = 0; - q->gen ^= 1; - } - spin_unlock(&q->lock); - wmb(); - t3_write_reg(adap, A_SG_KDOORBELL, - F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); - return NET_XMIT_SUCCESS; -} - -/** - * restart_ctrlq - restart a suspended control queue - * @qs: the queue set cotaining the control queue - * - * Resumes transmission on a suspended Tx control queue. - */ -static void restart_ctrlq(unsigned long data) -{ - struct sk_buff *skb; - struct sge_qset *qs = (struct sge_qset *)data; - struct sge_txq *q = &qs->txq[TXQ_CTRL]; - - spin_lock(&q->lock); - again:reclaim_completed_tx_imm(q); - - while (q->in_use < q->size && - (skb = __skb_dequeue(&q->sendq)) != NULL) { - - write_imm(&q->desc[q->pidx], skb, skb->len, q->gen); - - if (++q->pidx >= q->size) { - q->pidx = 0; - q->gen ^= 1; - } - q->in_use++; - } - - if (!skb_queue_empty(&q->sendq)) { - set_bit(TXQ_CTRL, &qs->txq_stopped); - smp_mb__after_clear_bit(); - - if (should_restart_tx(q) && - test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped)) - goto again; - q->stops++; - } - - spin_unlock(&q->lock); - wmb(); - t3_write_reg(qs->adap, A_SG_KDOORBELL, - F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); -} - -/* - * Send a management message through control queue 0 - */ -int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb) -{ - int ret; - local_bh_disable(); - ret = ctrl_xmit(adap, &adap->sge.qs[0].txq[TXQ_CTRL], skb); - local_bh_enable(); - - return ret; -} - -/** - * deferred_unmap_destructor - unmap a packet when it is freed - * @skb: the packet - * - * This is the packet destructor used for Tx packets that need to remain - * mapped until they are freed rather than until their Tx descriptors are - * freed. - */ -static void deferred_unmap_destructor(struct sk_buff *skb) -{ - int i; - const dma_addr_t *p; - const struct skb_shared_info *si; - const struct deferred_unmap_info *dui; - - dui = (struct deferred_unmap_info *)skb->head; - p = dui->addr; - - if (skb->tail - skb->transport_header) - pci_unmap_single(dui->pdev, *p++, - skb->tail - skb->transport_header, - PCI_DMA_TODEVICE); - - si = skb_shinfo(skb); - for (i = 0; i < si->nr_frags; i++) - pci_unmap_page(dui->pdev, *p++, si->frags[i].size, - PCI_DMA_TODEVICE); -} - -static void setup_deferred_unmapping(struct sk_buff *skb, struct pci_dev *pdev, - const struct sg_ent *sgl, int sgl_flits) -{ - dma_addr_t *p; - struct deferred_unmap_info *dui; - - dui = (struct deferred_unmap_info *)skb->head; - dui->pdev = pdev; - for (p = dui->addr; sgl_flits >= 3; sgl++, sgl_flits -= 3) { - *p++ = be64_to_cpu(sgl->addr[0]); - *p++ = be64_to_cpu(sgl->addr[1]); - } - if (sgl_flits) - *p = be64_to_cpu(sgl->addr[0]); -} - -/** - * write_ofld_wr - write an offload work request - * @adap: the adapter - * @skb: the packet to send - * @q: the Tx queue - * @pidx: index of the first Tx descriptor to write - * @gen: the generation value to use - * @ndesc: number of descriptors the packet will occupy - * - * Write an offload work request to send the supplied packet. The packet - * data already carry the work request with most fields populated. - */ -static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb, - struct sge_txq *q, unsigned int pidx, - unsigned int gen, unsigned int ndesc) -{ - unsigned int sgl_flits, flits; - struct work_request_hdr *from; - struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1]; - struct tx_desc *d = &q->desc[pidx]; - - if (immediate(skb)) { - q->sdesc[pidx].skb = NULL; - write_imm(d, skb, skb->len, gen); - return; - } - - /* Only TX_DATA builds SGLs */ - - from = (struct work_request_hdr *)skb->data; - memcpy(&d->flit[1], &from[1], - skb_transport_offset(skb) - sizeof(*from)); - - flits = skb_transport_offset(skb) / 8; - sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl; - sgl_flits = make_sgl(skb, sgp, skb_transport_header(skb), - skb->tail - skb->transport_header, - adap->pdev); - if (need_skb_unmap()) { - setup_deferred_unmapping(skb, adap->pdev, sgp, sgl_flits); - skb->destructor = deferred_unmap_destructor; - } - - write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, - gen, from->wr_hi, from->wr_lo); -} - -/** - * calc_tx_descs_ofld - calculate # of Tx descriptors for an offload packet - * @skb: the packet - * - * Returns the number of Tx descriptors needed for the given offload - * packet. These packets are already fully constructed. - */ -static inline unsigned int calc_tx_descs_ofld(const struct sk_buff *skb) -{ - unsigned int flits, cnt; - - if (skb->len <= WR_LEN) - return 1; /* packet fits as immediate data */ - - flits = skb_transport_offset(skb) / 8; /* headers */ - cnt = skb_shinfo(skb)->nr_frags; - if (skb->tail != skb->transport_header) - cnt++; - return flits_to_desc(flits + sgl_len(cnt)); -} - -/** - * ofld_xmit - send a packet through an offload queue - * @adap: the adapter - * @q: the Tx offload queue - * @skb: the packet - * - * Send an offload packet through an SGE offload queue. - */ -static int ofld_xmit(struct adapter *adap, struct sge_txq *q, - struct sk_buff *skb) -{ - int ret; - unsigned int ndesc = calc_tx_descs_ofld(skb), pidx, gen; - - spin_lock(&q->lock); -again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK); - - ret = check_desc_avail(adap, q, skb, ndesc, TXQ_OFLD); - if (unlikely(ret)) { - if (ret == 1) { - skb->priority = ndesc; /* save for restart */ - spin_unlock(&q->lock); - return NET_XMIT_CN; - } - goto again; - } - - gen = q->gen; - q->in_use += ndesc; - pidx = q->pidx; - q->pidx += ndesc; - if (q->pidx >= q->size) { - q->pidx -= q->size; - q->gen ^= 1; - } - spin_unlock(&q->lock); - - write_ofld_wr(adap, skb, q, pidx, gen, ndesc); - check_ring_tx_db(adap, q); - return NET_XMIT_SUCCESS; -} - -/** - * restart_offloadq - restart a suspended offload queue - * @qs: the queue set cotaining the offload queue - * - * Resumes transmission on a suspended Tx offload queue. - */ -static void restart_offloadq(unsigned long data) -{ - struct sk_buff *skb; - struct sge_qset *qs = (struct sge_qset *)data; - struct sge_txq *q = &qs->txq[TXQ_OFLD]; - const struct port_info *pi = netdev_priv(qs->netdev); - struct adapter *adap = pi->adapter; - - spin_lock(&q->lock); -again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK); - - while ((skb = skb_peek(&q->sendq)) != NULL) { - unsigned int gen, pidx; - unsigned int ndesc = skb->priority; - - if (unlikely(q->size - q->in_use < ndesc)) { - set_bit(TXQ_OFLD, &qs->txq_stopped); - smp_mb__after_clear_bit(); - - if (should_restart_tx(q) && - test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped)) - goto again; - q->stops++; - break; - } - - gen = q->gen; - q->in_use += ndesc; - pidx = q->pidx; - q->pidx += ndesc; - if (q->pidx >= q->size) { - q->pidx -= q->size; - q->gen ^= 1; - } - __skb_unlink(skb, &q->sendq); - spin_unlock(&q->lock); - - write_ofld_wr(adap, skb, q, pidx, gen, ndesc); - spin_lock(&q->lock); - } - spin_unlock(&q->lock); - -#if USE_GTS - set_bit(TXQ_RUNNING, &q->flags); - set_bit(TXQ_LAST_PKT_DB, &q->flags); -#endif - wmb(); - t3_write_reg(adap, A_SG_KDOORBELL, - F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); -} - -/** - * queue_set - return the queue set a packet should use - * @skb: the packet - * - * Maps a packet to the SGE queue set it should use. The desired queue - * set is carried in bits 1-3 in the packet's priority. - */ -static inline int queue_set(const struct sk_buff *skb) -{ - return skb->priority >> 1; -} - -/** - * is_ctrl_pkt - return whether an offload packet is a control packet - * @skb: the packet - * - * Determines whether an offload packet should use an OFLD or a CTRL - * Tx queue. This is indicated by bit 0 in the packet's priority. - */ -static inline int is_ctrl_pkt(const struct sk_buff *skb) -{ - return skb->priority & 1; -} - -/** - * t3_offload_tx - send an offload packet - * @tdev: the offload device to send to - * @skb: the packet - * - * Sends an offload packet. We use the packet priority to select the - * appropriate Tx queue as follows: bit 0 indicates whether the packet - * should be sent as regular or control, bits 1-3 select the queue set. - */ -int t3_offload_tx(struct t3cdev *tdev, struct sk_buff *skb) -{ - struct adapter *adap = tdev2adap(tdev); - struct sge_qset *qs = &adap->sge.qs[queue_set(skb)]; - - if (unlikely(is_ctrl_pkt(skb))) - return ctrl_xmit(adap, &qs->txq[TXQ_CTRL], skb); - - return ofld_xmit(adap, &qs->txq[TXQ_OFLD], skb); -} - -/** - * offload_enqueue - add an offload packet to an SGE offload receive queue - * @q: the SGE response queue - * @skb: the packet - * - * Add a new offload packet to an SGE response queue's offload packet - * queue. If the packet is the first on the queue it schedules the RX - * softirq to process the queue. - */ -static inline void offload_enqueue(struct sge_rspq *q, struct sk_buff *skb) -{ - int was_empty = skb_queue_empty(&q->rx_queue); - - __skb_queue_tail(&q->rx_queue, skb); - - if (was_empty) { - struct sge_qset *qs = rspq_to_qset(q); - - napi_schedule(&qs->napi); - } -} - -/** - * deliver_partial_bundle - deliver a (partial) bundle of Rx offload pkts - * @tdev: the offload device that will be receiving the packets - * @q: the SGE response queue that assembled the bundle - * @skbs: the partial bundle - * @n: the number of packets in the bundle - * - * Delivers a (partial) bundle of Rx offload packets to an offload device. - */ -static inline void deliver_partial_bundle(struct t3cdev *tdev, - struct sge_rspq *q, - struct sk_buff *skbs[], int n) -{ - if (n) { - q->offload_bundles++; - tdev->recv(tdev, skbs, n); - } -} - -/** - * ofld_poll - NAPI handler for offload packets in interrupt mode - * @dev: the network device doing the polling - * @budget: polling budget - * - * The NAPI handler for offload packets when a response queue is serviced - * by the hard interrupt handler, i.e., when it's operating in non-polling - * mode. Creates small packet batches and sends them through the offload - * receive handler. Batches need to be of modest size as we do prefetches - * on the packets in each. - */ -static int ofld_poll(struct napi_struct *napi, int budget) -{ - struct sge_qset *qs = container_of(napi, struct sge_qset, napi); - struct sge_rspq *q = &qs->rspq; - struct adapter *adapter = qs->adap; - int work_done = 0; - - while (work_done < budget) { - struct sk_buff *skb, *tmp, *skbs[RX_BUNDLE_SIZE]; - struct sk_buff_head queue; - int ngathered; - - spin_lock_irq(&q->lock); - __skb_queue_head_init(&queue); - skb_queue_splice_init(&q->rx_queue, &queue); - if (skb_queue_empty(&queue)) { - napi_complete(napi); - spin_unlock_irq(&q->lock); - return work_done; - } - spin_unlock_irq(&q->lock); - - ngathered = 0; - skb_queue_walk_safe(&queue, skb, tmp) { - if (work_done >= budget) - break; - work_done++; - - __skb_unlink(skb, &queue); - prefetch(skb->data); - skbs[ngathered] = skb; - if (++ngathered == RX_BUNDLE_SIZE) { - q->offload_bundles++; - adapter->tdev.recv(&adapter->tdev, skbs, - ngathered); - ngathered = 0; - } - } - if (!skb_queue_empty(&queue)) { - /* splice remaining packets back onto Rx queue */ - spin_lock_irq(&q->lock); - skb_queue_splice(&queue, &q->rx_queue); - spin_unlock_irq(&q->lock); - } - deliver_partial_bundle(&adapter->tdev, q, skbs, ngathered); - } - - return work_done; -} - -/** - * rx_offload - process a received offload packet - * @tdev: the offload device receiving the packet - * @rq: the response queue that received the packet - * @skb: the packet - * @rx_gather: a gather list of packets if we are building a bundle - * @gather_idx: index of the next available slot in the bundle - * - * Process an ingress offload pakcet and add it to the offload ingress - * queue. Returns the index of the next available slot in the bundle. - */ -static inline int rx_offload(struct t3cdev *tdev, struct sge_rspq *rq, - struct sk_buff *skb, struct sk_buff *rx_gather[], - unsigned int gather_idx) -{ - skb_reset_mac_header(skb); - skb_reset_network_header(skb); - skb_reset_transport_header(skb); - - if (rq->polling) { - rx_gather[gather_idx++] = skb; - if (gather_idx == RX_BUNDLE_SIZE) { - tdev->recv(tdev, rx_gather, RX_BUNDLE_SIZE); - gather_idx = 0; - rq->offload_bundles++; - } - } else - offload_enqueue(rq, skb); - - return gather_idx; -} - -/** - * restart_tx - check whether to restart suspended Tx queues - * @qs: the queue set to resume - * - * Restarts suspended Tx queues of an SGE queue set if they have enough - * free resources to resume operation. - */ -static void restart_tx(struct sge_qset *qs) -{ - if (test_bit(TXQ_ETH, &qs->txq_stopped) && - should_restart_tx(&qs->txq[TXQ_ETH]) && - test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) { - qs->txq[TXQ_ETH].restarts++; - if (netif_running(qs->netdev)) - netif_tx_wake_queue(qs->tx_q); - } - - if (test_bit(TXQ_OFLD, &qs->txq_stopped) && - should_restart_tx(&qs->txq[TXQ_OFLD]) && - test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped)) { - qs->txq[TXQ_OFLD].restarts++; - tasklet_schedule(&qs->txq[TXQ_OFLD].qresume_tsk); - } - if (test_bit(TXQ_CTRL, &qs->txq_stopped) && - should_restart_tx(&qs->txq[TXQ_CTRL]) && - test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped)) { - qs->txq[TXQ_CTRL].restarts++; - tasklet_schedule(&qs->txq[TXQ_CTRL].qresume_tsk); - } -} - -/** - * cxgb3_arp_process - process an ARP request probing a private IP address - * @adapter: the adapter - * @skb: the skbuff containing the ARP request - * - * Check if the ARP request is probing the private IP address - * dedicated to iSCSI, generate an ARP reply if so. - */ -static void cxgb3_arp_process(struct port_info *pi, struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - struct arphdr *arp; - unsigned char *arp_ptr; - unsigned char *sha; - __be32 sip, tip; - - if (!dev) - return; - - skb_reset_network_header(skb); - arp = arp_hdr(skb); - - if (arp->ar_op != htons(ARPOP_REQUEST)) - return; - - arp_ptr = (unsigned char *)(arp + 1); - sha = arp_ptr; - arp_ptr += dev->addr_len; - memcpy(&sip, arp_ptr, sizeof(sip)); - arp_ptr += sizeof(sip); - arp_ptr += dev->addr_len; - memcpy(&tip, arp_ptr, sizeof(tip)); - - if (tip != pi->iscsi_ipv4addr) - return; - - arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha, - pi->iscsic.mac_addr, sha); - -} - -static inline int is_arp(struct sk_buff *skb) -{ - return skb->protocol == htons(ETH_P_ARP); -} - -static void cxgb3_process_iscsi_prov_pack(struct port_info *pi, - struct sk_buff *skb) -{ - if (is_arp(skb)) { - cxgb3_arp_process(pi, skb); - return; - } - - if (pi->iscsic.recv) - pi->iscsic.recv(pi, skb); - -} - -/** - * rx_eth - process an ingress ethernet packet - * @adap: the adapter - * @rq: the response queue that received the packet - * @skb: the packet - * @pad: amount of padding at the start of the buffer - * - * Process an ingress ethernet pakcet and deliver it to the stack. - * The padding is 2 if the packet was delivered in an Rx buffer and 0 - * if it was immediate data in a response. - */ -static void rx_eth(struct adapter *adap, struct sge_rspq *rq, - struct sk_buff *skb, int pad, int lro) -{ - struct cpl_rx_pkt *p = (struct cpl_rx_pkt *)(skb->data + pad); - struct sge_qset *qs = rspq_to_qset(rq); - struct port_info *pi; - - skb_pull(skb, sizeof(*p) + pad); - skb->protocol = eth_type_trans(skb, adap->port[p->iff]); - pi = netdev_priv(skb->dev); - if ((skb->dev->features & NETIF_F_RXCSUM) && p->csum_valid && - p->csum == htons(0xffff) && !p->fragment) { - qs->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++; - skb->ip_summed = CHECKSUM_UNNECESSARY; - } else - skb_checksum_none_assert(skb); - skb_record_rx_queue(skb, qs - &adap->sge.qs[pi->first_qset]); - - if (p->vlan_valid) { - qs->port_stats[SGE_PSTAT_VLANEX]++; - __vlan_hwaccel_put_tag(skb, ntohs(p->vlan)); - } - if (rq->polling) { - if (lro) - napi_gro_receive(&qs->napi, skb); - else { - if (unlikely(pi->iscsic.flags)) - cxgb3_process_iscsi_prov_pack(pi, skb); - netif_receive_skb(skb); - } - } else - netif_rx(skb); -} - -static inline int is_eth_tcp(u32 rss) -{ - return G_HASHTYPE(ntohl(rss)) == RSS_HASH_4_TUPLE; -} - -/** - * lro_add_page - add a page chunk to an LRO session - * @adap: the adapter - * @qs: the associated queue set - * @fl: the free list containing the page chunk to add - * @len: packet length - * @complete: Indicates the last fragment of a frame - * - * Add a received packet contained in a page chunk to an existing LRO - * session. - */ -static void lro_add_page(struct adapter *adap, struct sge_qset *qs, - struct sge_fl *fl, int len, int complete) -{ - struct rx_sw_desc *sd = &fl->sdesc[fl->cidx]; - struct port_info *pi = netdev_priv(qs->netdev); - struct sk_buff *skb = NULL; - struct cpl_rx_pkt *cpl; - struct skb_frag_struct *rx_frag; - int nr_frags; - int offset = 0; - - if (!qs->nomem) { - skb = napi_get_frags(&qs->napi); - qs->nomem = !skb; - } - - fl->credits--; - - pci_dma_sync_single_for_cpu(adap->pdev, - dma_unmap_addr(sd, dma_addr), - fl->buf_size - SGE_PG_RSVD, - PCI_DMA_FROMDEVICE); - - (*sd->pg_chunk.p_cnt)--; - if (!*sd->pg_chunk.p_cnt && sd->pg_chunk.page != fl->pg_chunk.page) - pci_unmap_page(adap->pdev, - sd->pg_chunk.mapping, - fl->alloc_size, - PCI_DMA_FROMDEVICE); - - if (!skb) { - put_page(sd->pg_chunk.page); - if (complete) - qs->nomem = 0; - return; - } - - rx_frag = skb_shinfo(skb)->frags; - nr_frags = skb_shinfo(skb)->nr_frags; - - if (!nr_frags) { - offset = 2 + sizeof(struct cpl_rx_pkt); - cpl = qs->lro_va = sd->pg_chunk.va + 2; - - if ((qs->netdev->features & NETIF_F_RXCSUM) && - cpl->csum_valid && cpl->csum == htons(0xffff)) { - skb->ip_summed = CHECKSUM_UNNECESSARY; - qs->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++; - } else - skb->ip_summed = CHECKSUM_NONE; - } else - cpl = qs->lro_va; - - len -= offset; - - rx_frag += nr_frags; - rx_frag->page = sd->pg_chunk.page; - rx_frag->page_offset = sd->pg_chunk.offset + offset; - rx_frag->size = len; - - skb->len += len; - skb->data_len += len; - skb->truesize += len; - skb_shinfo(skb)->nr_frags++; - - if (!complete) - return; - - skb_record_rx_queue(skb, qs - &adap->sge.qs[pi->first_qset]); - - if (cpl->vlan_valid) - __vlan_hwaccel_put_tag(skb, ntohs(cpl->vlan)); - napi_gro_frags(&qs->napi); -} - -/** - * handle_rsp_cntrl_info - handles control information in a response - * @qs: the queue set corresponding to the response - * @flags: the response control flags - * - * Handles the control information of an SGE response, such as GTS - * indications and completion credits for the queue set's Tx queues. - * HW coalesces credits, we don't do any extra SW coalescing. - */ -static inline void handle_rsp_cntrl_info(struct sge_qset *qs, u32 flags) -{ - unsigned int credits; - -#if USE_GTS - if (flags & F_RSPD_TXQ0_GTS) - clear_bit(TXQ_RUNNING, &qs->txq[TXQ_ETH].flags); -#endif - - credits = G_RSPD_TXQ0_CR(flags); - if (credits) - qs->txq[TXQ_ETH].processed += credits; - - credits = G_RSPD_TXQ2_CR(flags); - if (credits) - qs->txq[TXQ_CTRL].processed += credits; - -# if USE_GTS - if (flags & F_RSPD_TXQ1_GTS) - clear_bit(TXQ_RUNNING, &qs->txq[TXQ_OFLD].flags); -# endif - credits = G_RSPD_TXQ1_CR(flags); - if (credits) - qs->txq[TXQ_OFLD].processed += credits; -} - -/** - * check_ring_db - check if we need to ring any doorbells - * @adapter: the adapter - * @qs: the queue set whose Tx queues are to be examined - * @sleeping: indicates which Tx queue sent GTS - * - * Checks if some of a queue set's Tx queues need to ring their doorbells - * to resume transmission after idling while they still have unprocessed - * descriptors. - */ -static void check_ring_db(struct adapter *adap, struct sge_qset *qs, - unsigned int sleeping) -{ - if (sleeping & F_RSPD_TXQ0_GTS) { - struct sge_txq *txq = &qs->txq[TXQ_ETH]; - - if (txq->cleaned + txq->in_use != txq->processed && - !test_and_set_bit(TXQ_LAST_PKT_DB, &txq->flags)) { - set_bit(TXQ_RUNNING, &txq->flags); - t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX | - V_EGRCNTX(txq->cntxt_id)); - } - } - - if (sleeping & F_RSPD_TXQ1_GTS) { - struct sge_txq *txq = &qs->txq[TXQ_OFLD]; - - if (txq->cleaned + txq->in_use != txq->processed && - !test_and_set_bit(TXQ_LAST_PKT_DB, &txq->flags)) { - set_bit(TXQ_RUNNING, &txq->flags); - t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX | - V_EGRCNTX(txq->cntxt_id)); - } - } -} - -/** - * is_new_response - check if a response is newly written - * @r: the response descriptor - * @q: the response queue - * - * Returns true if a response descriptor contains a yet unprocessed - * response. - */ -static inline int is_new_response(const struct rsp_desc *r, - const struct sge_rspq *q) -{ - return (r->intr_gen & F_RSPD_GEN2) == q->gen; -} - -static inline void clear_rspq_bufstate(struct sge_rspq * const q) -{ - q->pg_skb = NULL; - q->rx_recycle_buf = 0; -} - -#define RSPD_GTS_MASK (F_RSPD_TXQ0_GTS | F_RSPD_TXQ1_GTS) -#define RSPD_CTRL_MASK (RSPD_GTS_MASK | \ - V_RSPD_TXQ0_CR(M_RSPD_TXQ0_CR) | \ - V_RSPD_TXQ1_CR(M_RSPD_TXQ1_CR) | \ - V_RSPD_TXQ2_CR(M_RSPD_TXQ2_CR)) - -/* How long to delay the next interrupt in case of memory shortage, in 0.1us. */ -#define NOMEM_INTR_DELAY 2500 - -/** - * process_responses - process responses from an SGE response queue - * @adap: the adapter - * @qs: the queue set to which the response queue belongs - * @budget: how many responses can be processed in this round - * - * Process responses from an SGE response queue up to the supplied budget. - * Responses include received packets as well as credits and other events - * for the queues that belong to the response queue's queue set. - * A negative budget is effectively unlimited. - * - * Additionally choose the interrupt holdoff time for the next interrupt - * on this queue. If the system is under memory shortage use a fairly - * long delay to help recovery. - */ -static int process_responses(struct adapter *adap, struct sge_qset *qs, - int budget) -{ - struct sge_rspq *q = &qs->rspq; - struct rsp_desc *r = &q->desc[q->cidx]; - int budget_left = budget; - unsigned int sleeping = 0; - struct sk_buff *offload_skbs[RX_BUNDLE_SIZE]; - int ngathered = 0; - - q->next_holdoff = q->holdoff_tmr; - - while (likely(budget_left && is_new_response(r, q))) { - int packet_complete, eth, ethpad = 2; - int lro = !!(qs->netdev->features & NETIF_F_GRO); - struct sk_buff *skb = NULL; - u32 len, flags; - __be32 rss_hi, rss_lo; - - rmb(); - eth = r->rss_hdr.opcode == CPL_RX_PKT; - rss_hi = *(const __be32 *)r; - rss_lo = r->rss_hdr.rss_hash_val; - flags = ntohl(r->flags); - - if (unlikely(flags & F_RSPD_ASYNC_NOTIF)) { - skb = alloc_skb(AN_PKT_SIZE, GFP_ATOMIC); - if (!skb) - goto no_mem; - - memcpy(__skb_put(skb, AN_PKT_SIZE), r, AN_PKT_SIZE); - skb->data[0] = CPL_ASYNC_NOTIF; - rss_hi = htonl(CPL_ASYNC_NOTIF << 24); - q->async_notif++; - } else if (flags & F_RSPD_IMM_DATA_VALID) { - skb = get_imm_packet(r); - if (unlikely(!skb)) { -no_mem: - q->next_holdoff = NOMEM_INTR_DELAY; - q->nomem++; - /* consume one credit since we tried */ - budget_left--; - break; - } - q->imm_data++; - ethpad = 0; - } else if ((len = ntohl(r->len_cq)) != 0) { - struct sge_fl *fl; - - lro &= eth && is_eth_tcp(rss_hi); - - fl = (len & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0]; - if (fl->use_pages) { - void *addr = fl->sdesc[fl->cidx].pg_chunk.va; - - prefetch(addr); -#if L1_CACHE_BYTES < 128 - prefetch(addr + L1_CACHE_BYTES); -#endif - __refill_fl(adap, fl); - if (lro > 0) { - lro_add_page(adap, qs, fl, - G_RSPD_LEN(len), - flags & F_RSPD_EOP); - goto next_fl; - } - - skb = get_packet_pg(adap, fl, q, - G_RSPD_LEN(len), - eth ? - SGE_RX_DROP_THRES : 0); - q->pg_skb = skb; - } else - skb = get_packet(adap, fl, G_RSPD_LEN(len), - eth ? SGE_RX_DROP_THRES : 0); - if (unlikely(!skb)) { - if (!eth) - goto no_mem; - q->rx_drops++; - } else if (unlikely(r->rss_hdr.opcode == CPL_TRACE_PKT)) - __skb_pull(skb, 2); -next_fl: - if (++fl->cidx == fl->size) - fl->cidx = 0; - } else - q->pure_rsps++; - - if (flags & RSPD_CTRL_MASK) { - sleeping |= flags & RSPD_GTS_MASK; - handle_rsp_cntrl_info(qs, flags); - } - - r++; - if (unlikely(++q->cidx == q->size)) { - q->cidx = 0; - q->gen ^= 1; - r = q->desc; - } - prefetch(r); - - if (++q->credits >= (q->size / 4)) { - refill_rspq(adap, q, q->credits); - q->credits = 0; - } - - packet_complete = flags & - (F_RSPD_EOP | F_RSPD_IMM_DATA_VALID | - F_RSPD_ASYNC_NOTIF); - - if (skb != NULL && packet_complete) { - if (eth) - rx_eth(adap, q, skb, ethpad, lro); - else { - q->offload_pkts++; - /* Preserve the RSS info in csum & priority */ - skb->csum = rss_hi; - skb->priority = rss_lo; - ngathered = rx_offload(&adap->tdev, q, skb, - offload_skbs, - ngathered); - } - - if (flags & F_RSPD_EOP) - clear_rspq_bufstate(q); - } - --budget_left; - } - - deliver_partial_bundle(&adap->tdev, q, offload_skbs, ngathered); - - if (sleeping) - check_ring_db(adap, qs, sleeping); - - smp_mb(); /* commit Tx queue .processed updates */ - if (unlikely(qs->txq_stopped != 0)) - restart_tx(qs); - - budget -= budget_left; - return budget; -} - -static inline int is_pure_response(const struct rsp_desc *r) -{ - __be32 n = r->flags & htonl(F_RSPD_ASYNC_NOTIF | F_RSPD_IMM_DATA_VALID); - - return (n | r->len_cq) == 0; -} - -/** - * napi_rx_handler - the NAPI handler for Rx processing - * @napi: the napi instance - * @budget: how many packets we can process in this round - * - * Handler for new data events when using NAPI. - */ -static int napi_rx_handler(struct napi_struct *napi, int budget) -{ - struct sge_qset *qs = container_of(napi, struct sge_qset, napi); - struct adapter *adap = qs->adap; - int work_done = process_responses(adap, qs, budget); - - if (likely(work_done < budget)) { - napi_complete(napi); - - /* - * Because we don't atomically flush the following - * write it is possible that in very rare cases it can - * reach the device in a way that races with a new - * response being written plus an error interrupt - * causing the NAPI interrupt handler below to return - * unhandled status to the OS. To protect against - * this would require flushing the write and doing - * both the write and the flush with interrupts off. - * Way too expensive and unjustifiable given the - * rarity of the race. - * - * The race cannot happen at all with MSI-X. - */ - t3_write_reg(adap, A_SG_GTS, V_RSPQ(qs->rspq.cntxt_id) | - V_NEWTIMER(qs->rspq.next_holdoff) | - V_NEWINDEX(qs->rspq.cidx)); - } - return work_done; -} - -/* - * Returns true if the device is already scheduled for polling. - */ -static inline int napi_is_scheduled(struct napi_struct *napi) -{ - return test_bit(NAPI_STATE_SCHED, &napi->state); -} - -/** - * process_pure_responses - process pure responses from a response queue - * @adap: the adapter - * @qs: the queue set owning the response queue - * @r: the first pure response to process - * - * A simpler version of process_responses() that handles only pure (i.e., - * non data-carrying) responses. Such respones are too light-weight to - * justify calling a softirq under NAPI, so we handle them specially in - * the interrupt handler. The function is called with a pointer to a - * response, which the caller must ensure is a valid pure response. - * - * Returns 1 if it encounters a valid data-carrying response, 0 otherwise. - */ -static int process_pure_responses(struct adapter *adap, struct sge_qset *qs, - struct rsp_desc *r) -{ - struct sge_rspq *q = &qs->rspq; - unsigned int sleeping = 0; - - do { - u32 flags = ntohl(r->flags); - - r++; - if (unlikely(++q->cidx == q->size)) { - q->cidx = 0; - q->gen ^= 1; - r = q->desc; - } - prefetch(r); - - if (flags & RSPD_CTRL_MASK) { - sleeping |= flags & RSPD_GTS_MASK; - handle_rsp_cntrl_info(qs, flags); - } - - q->pure_rsps++; - if (++q->credits >= (q->size / 4)) { - refill_rspq(adap, q, q->credits); - q->credits = 0; - } - if (!is_new_response(r, q)) - break; - rmb(); - } while (is_pure_response(r)); - - if (sleeping) - check_ring_db(adap, qs, sleeping); - - smp_mb(); /* commit Tx queue .processed updates */ - if (unlikely(qs->txq_stopped != 0)) - restart_tx(qs); - - return is_new_response(r, q); -} - -/** - * handle_responses - decide what to do with new responses in NAPI mode - * @adap: the adapter - * @q: the response queue - * - * This is used by the NAPI interrupt handlers to decide what to do with - * new SGE responses. If there are no new responses it returns -1. If - * there are new responses and they are pure (i.e., non-data carrying) - * it handles them straight in hard interrupt context as they are very - * cheap and don't deliver any packets. Finally, if there are any data - * signaling responses it schedules the NAPI handler. Returns 1 if it - * schedules NAPI, 0 if all new responses were pure. - * - * The caller must ascertain NAPI is not already running. - */ -static inline int handle_responses(struct adapter *adap, struct sge_rspq *q) -{ - struct sge_qset *qs = rspq_to_qset(q); - struct rsp_desc *r = &q->desc[q->cidx]; - - if (!is_new_response(r, q)) - return -1; - rmb(); - if (is_pure_response(r) && process_pure_responses(adap, qs, r) == 0) { - t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) | - V_NEWTIMER(q->holdoff_tmr) | V_NEWINDEX(q->cidx)); - return 0; - } - napi_schedule(&qs->napi); - return 1; -} - -/* - * The MSI-X interrupt handler for an SGE response queue for the non-NAPI case - * (i.e., response queue serviced in hard interrupt). - */ -static irqreturn_t t3_sge_intr_msix(int irq, void *cookie) -{ - struct sge_qset *qs = cookie; - struct adapter *adap = qs->adap; - struct sge_rspq *q = &qs->rspq; - - spin_lock(&q->lock); - if (process_responses(adap, qs, -1) == 0) - q->unhandled_irqs++; - t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) | - V_NEWTIMER(q->next_holdoff) | V_NEWINDEX(q->cidx)); - spin_unlock(&q->lock); - return IRQ_HANDLED; -} - -/* - * The MSI-X interrupt handler for an SGE response queue for the NAPI case - * (i.e., response queue serviced by NAPI polling). - */ -static irqreturn_t t3_sge_intr_msix_napi(int irq, void *cookie) -{ - struct sge_qset *qs = cookie; - struct sge_rspq *q = &qs->rspq; - - spin_lock(&q->lock); - - if (handle_responses(qs->adap, q) < 0) - q->unhandled_irqs++; - spin_unlock(&q->lock); - return IRQ_HANDLED; -} - -/* - * The non-NAPI MSI interrupt handler. This needs to handle data events from - * SGE response queues as well as error and other async events as they all use - * the same MSI vector. We use one SGE response queue per port in this mode - * and protect all response queues with queue 0's lock. - */ -static irqreturn_t t3_intr_msi(int irq, void *cookie) -{ - int new_packets = 0; - struct adapter *adap = cookie; - struct sge_rspq *q = &adap->sge.qs[0].rspq; - - spin_lock(&q->lock); - - if (process_responses(adap, &adap->sge.qs[0], -1)) { - t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) | - V_NEWTIMER(q->next_holdoff) | V_NEWINDEX(q->cidx)); - new_packets = 1; - } - - if (adap->params.nports == 2 && - process_responses(adap, &adap->sge.qs[1], -1)) { - struct sge_rspq *q1 = &adap->sge.qs[1].rspq; - - t3_write_reg(adap, A_SG_GTS, V_RSPQ(q1->cntxt_id) | - V_NEWTIMER(q1->next_holdoff) | - V_NEWINDEX(q1->cidx)); - new_packets = 1; - } - - if (!new_packets && t3_slow_intr_handler(adap) == 0) - q->unhandled_irqs++; - - spin_unlock(&q->lock); - return IRQ_HANDLED; -} - -static int rspq_check_napi(struct sge_qset *qs) -{ - struct sge_rspq *q = &qs->rspq; - - if (!napi_is_scheduled(&qs->napi) && - is_new_response(&q->desc[q->cidx], q)) { - napi_schedule(&qs->napi); - return 1; - } - return 0; -} - -/* - * The MSI interrupt handler for the NAPI case (i.e., response queues serviced - * by NAPI polling). Handles data events from SGE response queues as well as - * error and other async events as they all use the same MSI vector. We use - * one SGE response queue per port in this mode and protect all response - * queues with queue 0's lock. - */ -static irqreturn_t t3_intr_msi_napi(int irq, void *cookie) -{ - int new_packets; - struct adapter *adap = cookie; - struct sge_rspq *q = &adap->sge.qs[0].rspq; - - spin_lock(&q->lock); - - new_packets = rspq_check_napi(&adap->sge.qs[0]); - if (adap->params.nports == 2) - new_packets += rspq_check_napi(&adap->sge.qs[1]); - if (!new_packets && t3_slow_intr_handler(adap) == 0) - q->unhandled_irqs++; - - spin_unlock(&q->lock); - return IRQ_HANDLED; -} - -/* - * A helper function that processes responses and issues GTS. - */ -static inline int process_responses_gts(struct adapter *adap, - struct sge_rspq *rq) -{ - int work; - - work = process_responses(adap, rspq_to_qset(rq), -1); - t3_write_reg(adap, A_SG_GTS, V_RSPQ(rq->cntxt_id) | - V_NEWTIMER(rq->next_holdoff) | V_NEWINDEX(rq->cidx)); - return work; -} - -/* - * The legacy INTx interrupt handler. This needs to handle data events from - * SGE response queues as well as error and other async events as they all use - * the same interrupt pin. We use one SGE response queue per port in this mode - * and protect all response queues with queue 0's lock. - */ -static irqreturn_t t3_intr(int irq, void *cookie) -{ - int work_done, w0, w1; - struct adapter *adap = cookie; - struct sge_rspq *q0 = &adap->sge.qs[0].rspq; - struct sge_rspq *q1 = &adap->sge.qs[1].rspq; - - spin_lock(&q0->lock); - - w0 = is_new_response(&q0->desc[q0->cidx], q0); - w1 = adap->params.nports == 2 && - is_new_response(&q1->desc[q1->cidx], q1); - - if (likely(w0 | w1)) { - t3_write_reg(adap, A_PL_CLI, 0); - t3_read_reg(adap, A_PL_CLI); /* flush */ - - if (likely(w0)) - process_responses_gts(adap, q0); - - if (w1) - process_responses_gts(adap, q1); - - work_done = w0 | w1; - } else - work_done = t3_slow_intr_handler(adap); - - spin_unlock(&q0->lock); - return IRQ_RETVAL(work_done != 0); -} - -/* - * Interrupt handler for legacy INTx interrupts for T3B-based cards. - * Handles data events from SGE response queues as well as error and other - * async events as they all use the same interrupt pin. We use one SGE - * response queue per port in this mode and protect all response queues with - * queue 0's lock. - */ -static irqreturn_t t3b_intr(int irq, void *cookie) -{ - u32 map; - struct adapter *adap = cookie; - struct sge_rspq *q0 = &adap->sge.qs[0].rspq; - - t3_write_reg(adap, A_PL_CLI, 0); - map = t3_read_reg(adap, A_SG_DATA_INTR); - - if (unlikely(!map)) /* shared interrupt, most likely */ - return IRQ_NONE; - - spin_lock(&q0->lock); - - if (unlikely(map & F_ERRINTR)) - t3_slow_intr_handler(adap); - - if (likely(map & 1)) - process_responses_gts(adap, q0); - - if (map & 2) - process_responses_gts(adap, &adap->sge.qs[1].rspq); - - spin_unlock(&q0->lock); - return IRQ_HANDLED; -} - -/* - * NAPI interrupt handler for legacy INTx interrupts for T3B-based cards. - * Handles data events from SGE response queues as well as error and other - * async events as they all use the same interrupt pin. We use one SGE - * response queue per port in this mode and protect all response queues with - * queue 0's lock. - */ -static irqreturn_t t3b_intr_napi(int irq, void *cookie) -{ - u32 map; - struct adapter *adap = cookie; - struct sge_qset *qs0 = &adap->sge.qs[0]; - struct sge_rspq *q0 = &qs0->rspq; - - t3_write_reg(adap, A_PL_CLI, 0); - map = t3_read_reg(adap, A_SG_DATA_INTR); - - if (unlikely(!map)) /* shared interrupt, most likely */ - return IRQ_NONE; - - spin_lock(&q0->lock); - - if (unlikely(map & F_ERRINTR)) - t3_slow_intr_handler(adap); - - if (likely(map & 1)) - napi_schedule(&qs0->napi); - - if (map & 2) - napi_schedule(&adap->sge.qs[1].napi); - - spin_unlock(&q0->lock); - return IRQ_HANDLED; -} - -/** - * t3_intr_handler - select the top-level interrupt handler - * @adap: the adapter - * @polling: whether using NAPI to service response queues - * - * Selects the top-level interrupt handler based on the type of interrupts - * (MSI-X, MSI, or legacy) and whether NAPI will be used to service the - * response queues. - */ -irq_handler_t t3_intr_handler(struct adapter *adap, int polling) -{ - if (adap->flags & USING_MSIX) - return polling ? t3_sge_intr_msix_napi : t3_sge_intr_msix; - if (adap->flags & USING_MSI) - return polling ? t3_intr_msi_napi : t3_intr_msi; - if (adap->params.rev > 0) - return polling ? t3b_intr_napi : t3b_intr; - return t3_intr; -} - -#define SGE_PARERR (F_CPPARITYERROR | F_OCPARITYERROR | F_RCPARITYERROR | \ - F_IRPARITYERROR | V_ITPARITYERROR(M_ITPARITYERROR) | \ - V_FLPARITYERROR(M_FLPARITYERROR) | F_LODRBPARITYERROR | \ - F_HIDRBPARITYERROR | F_LORCQPARITYERROR | \ - F_HIRCQPARITYERROR) -#define SGE_FRAMINGERR (F_UC_REQ_FRAMINGERROR | F_R_REQ_FRAMINGERROR) -#define SGE_FATALERR (SGE_PARERR | SGE_FRAMINGERR | F_RSPQCREDITOVERFOW | \ - F_RSPQDISABLED) - -/** - * t3_sge_err_intr_handler - SGE async event interrupt handler - * @adapter: the adapter - * - * Interrupt handler for SGE asynchronous (non-data) events. - */ -void t3_sge_err_intr_handler(struct adapter *adapter) -{ - unsigned int v, status = t3_read_reg(adapter, A_SG_INT_CAUSE) & - ~F_FLEMPTY; - - if (status & SGE_PARERR) - CH_ALERT(adapter, "SGE parity error (0x%x)\n", - status & SGE_PARERR); - if (status & SGE_FRAMINGERR) - CH_ALERT(adapter, "SGE framing error (0x%x)\n", - status & SGE_FRAMINGERR); - - if (status & F_RSPQCREDITOVERFOW) - CH_ALERT(adapter, "SGE response queue credit overflow\n"); - - if (status & F_RSPQDISABLED) { - v = t3_read_reg(adapter, A_SG_RSPQ_FL_STATUS); - - CH_ALERT(adapter, - "packet delivered to disabled response queue " - "(0x%x)\n", (v >> S_RSPQ0DISABLED) & 0xff); - } - - if (status & (F_HIPIODRBDROPERR | F_LOPIODRBDROPERR)) - queue_work(cxgb3_wq, &adapter->db_drop_task); - - if (status & (F_HIPRIORITYDBFULL | F_LOPRIORITYDBFULL)) - queue_work(cxgb3_wq, &adapter->db_full_task); - - if (status & (F_HIPRIORITYDBEMPTY | F_LOPRIORITYDBEMPTY)) - queue_work(cxgb3_wq, &adapter->db_empty_task); - - t3_write_reg(adapter, A_SG_INT_CAUSE, status); - if (status & SGE_FATALERR) - t3_fatal_err(adapter); -} - -/** - * sge_timer_tx - 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: - * - * 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. - * - */ -static void sge_timer_tx(unsigned long data) -{ - struct sge_qset *qs = (struct sge_qset *)data; - struct port_info *pi = netdev_priv(qs->netdev); - struct adapter *adap = pi->adapter; - unsigned int tbd[SGE_TXQ_PER_SET] = {0, 0}; - unsigned long next_period; - - if (__netif_tx_trylock(qs->tx_q)) { - tbd[TXQ_ETH] = reclaim_completed_tx(adap, &qs->txq[TXQ_ETH], - TX_RECLAIM_TIMER_CHUNK); - __netif_tx_unlock(qs->tx_q); - } - - if (spin_trylock(&qs->txq[TXQ_OFLD].lock)) { - tbd[TXQ_OFLD] = reclaim_completed_tx(adap, &qs->txq[TXQ_OFLD], - TX_RECLAIM_TIMER_CHUNK); - spin_unlock(&qs->txq[TXQ_OFLD].lock); - } - - next_period = TX_RECLAIM_PERIOD >> - (max(tbd[TXQ_ETH], tbd[TXQ_OFLD]) / - TX_RECLAIM_TIMER_CHUNK); - mod_timer(&qs->tx_reclaim_timer, jiffies + next_period); -} - -/* - * sge_timer_rx - perform periodic maintenance of an SGE qset - * @data: the SGE queue set to maintain - * - * a) 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. - * - * b) Return coalesced response queue credits in case a response queue is - * starved. - * - */ -static void sge_timer_rx(unsigned long data) -{ - spinlock_t *lock; - struct sge_qset *qs = (struct sge_qset *)data; - struct port_info *pi = netdev_priv(qs->netdev); - struct adapter *adap = pi->adapter; - u32 status; - - lock = adap->params.rev > 0 ? - &qs->rspq.lock : &adap->sge.qs[0].rspq.lock; - - if (!spin_trylock_irq(lock)) - goto out; - - if (napi_is_scheduled(&qs->napi)) - goto unlock; - - if (adap->params.rev < 4) { - status = t3_read_reg(adap, A_SG_RSPQ_FL_STATUS); - - if (status & (1 << qs->rspq.cntxt_id)) { - qs->rspq.starved++; - if (qs->rspq.credits) { - qs->rspq.credits--; - refill_rspq(adap, &qs->rspq, 1); - qs->rspq.restarted++; - t3_write_reg(adap, A_SG_RSPQ_FL_STATUS, - 1 << qs->rspq.cntxt_id); - } - } - } - - if (qs->fl[0].credits < qs->fl[0].size) - __refill_fl(adap, &qs->fl[0]); - if (qs->fl[1].credits < qs->fl[1].size) - __refill_fl(adap, &qs->fl[1]); - -unlock: - spin_unlock_irq(lock); -out: - mod_timer(&qs->rx_reclaim_timer, jiffies + RX_RECLAIM_PERIOD); -} - -/** - * t3_update_qset_coalesce - update coalescing settings for a queue set - * @qs: the SGE queue set - * @p: new queue set parameters - * - * Update the coalescing settings for an SGE queue set. Nothing is done - * if the queue set is not initialized yet. - */ -void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p) -{ - qs->rspq.holdoff_tmr = max(p->coalesce_usecs * 10, 1U);/* can't be 0 */ - qs->rspq.polling = p->polling; - qs->napi.poll = p->polling ? napi_rx_handler : ofld_poll; -} - -/** - * t3_sge_alloc_qset - initialize an SGE queue set - * @adapter: the adapter - * @id: the queue set id - * @nports: how many Ethernet ports will be using this queue set - * @irq_vec_idx: the IRQ vector index for response queue interrupts - * @p: configuration parameters for this queue set - * @ntxq: number of Tx queues for the queue set - * @netdev: net device associated with this queue set - * @netdevq: net device TX queue associated with this queue set - * - * Allocate resources and initialize an SGE queue set. A queue set - * comprises a response queue, two Rx free-buffer queues, and up to 3 - * Tx queues. The Tx queues are assigned roles in the order Ethernet - * queue, offload queue, and control queue. - */ -int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, - int irq_vec_idx, const struct qset_params *p, - int ntxq, struct net_device *dev, - struct netdev_queue *netdevq) -{ - int i, avail, ret = -ENOMEM; - struct sge_qset *q = &adapter->sge.qs[id]; - - init_qset_cntxt(q, id); - setup_timer(&q->tx_reclaim_timer, sge_timer_tx, (unsigned long)q); - setup_timer(&q->rx_reclaim_timer, sge_timer_rx, (unsigned long)q); - - q->fl[0].desc = alloc_ring(adapter->pdev, p->fl_size, - sizeof(struct rx_desc), - sizeof(struct rx_sw_desc), - &q->fl[0].phys_addr, &q->fl[0].sdesc); - if (!q->fl[0].desc) - goto err; - - q->fl[1].desc = alloc_ring(adapter->pdev, p->jumbo_size, - sizeof(struct rx_desc), - sizeof(struct rx_sw_desc), - &q->fl[1].phys_addr, &q->fl[1].sdesc); - if (!q->fl[1].desc) - goto err; - - q->rspq.desc = alloc_ring(adapter->pdev, p->rspq_size, - sizeof(struct rsp_desc), 0, - &q->rspq.phys_addr, NULL); - if (!q->rspq.desc) - goto err; - - for (i = 0; i < ntxq; ++i) { - /* - * The control queue always uses immediate data so does not - * need to keep track of any sk_buffs. - */ - size_t sz = i == TXQ_CTRL ? 0 : sizeof(struct tx_sw_desc); - - q->txq[i].desc = alloc_ring(adapter->pdev, p->txq_size[i], - sizeof(struct tx_desc), sz, - &q->txq[i].phys_addr, - &q->txq[i].sdesc); - if (!q->txq[i].desc) - goto err; - - q->txq[i].gen = 1; - q->txq[i].size = p->txq_size[i]; - spin_lock_init(&q->txq[i].lock); - skb_queue_head_init(&q->txq[i].sendq); - } - - tasklet_init(&q->txq[TXQ_OFLD].qresume_tsk, restart_offloadq, - (unsigned long)q); - tasklet_init(&q->txq[TXQ_CTRL].qresume_tsk, restart_ctrlq, - (unsigned long)q); - - 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.size = p->rspq_size; - spin_lock_init(&q->rspq.lock); - skb_queue_head_init(&q->rspq.rx_queue); - - q->txq[TXQ_ETH].stop_thres = nports * - flits_to_desc(sgl_len(MAX_SKB_FRAGS + 1) + 3); - -#if FL0_PG_CHUNK_SIZE > 0 - q->fl[0].buf_size = FL0_PG_CHUNK_SIZE; -#else - q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + sizeof(struct cpl_rx_data); -#endif -#if FL1_PG_CHUNK_SIZE > 0 - q->fl[1].buf_size = FL1_PG_CHUNK_SIZE; -#else - q->fl[1].buf_size = is_offload(adapter) ? - (16 * 1024) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) : - MAX_FRAME_SIZE + 2 + sizeof(struct cpl_rx_pkt); -#endif - - q->fl[0].use_pages = FL0_PG_CHUNK_SIZE > 0; - q->fl[1].use_pages = FL1_PG_CHUNK_SIZE > 0; - q->fl[0].order = FL0_PG_ORDER; - q->fl[1].order = FL1_PG_ORDER; - q->fl[0].alloc_size = FL0_PG_ALLOC_SIZE; - q->fl[1].alloc_size = FL1_PG_ALLOC_SIZE; - - spin_lock_irq(&adapter->sge.reg_lock); - - /* FL threshold comparison uses < */ - ret = t3_sge_init_rspcntxt(adapter, q->rspq.cntxt_id, irq_vec_idx, - q->rspq.phys_addr, q->rspq.size, - q->fl[0].buf_size - SGE_PG_RSVD, 1, 0); - if (ret) - goto err_unlock; - - for (i = 0; i < SGE_RXQ_PER_SET; ++i) { - ret = t3_sge_init_flcntxt(adapter, q->fl[i].cntxt_id, 0, - q->fl[i].phys_addr, q->fl[i].size, - q->fl[i].buf_size - SGE_PG_RSVD, - p->cong_thres, 1, 0); - if (ret) - goto err_unlock; - } - - ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_ETH].cntxt_id, USE_GTS, - SGE_CNTXT_ETH, id, q->txq[TXQ_ETH].phys_addr, - q->txq[TXQ_ETH].size, q->txq[TXQ_ETH].token, - 1, 0); - if (ret) - goto err_unlock; - - if (ntxq > 1) { - ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_OFLD].cntxt_id, - USE_GTS, SGE_CNTXT_OFLD, id, - q->txq[TXQ_OFLD].phys_addr, - q->txq[TXQ_OFLD].size, 0, 1, 0); - if (ret) - goto err_unlock; - } - - if (ntxq > 2) { - ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_CTRL].cntxt_id, 0, - SGE_CNTXT_CTRL, id, - q->txq[TXQ_CTRL].phys_addr, - q->txq[TXQ_CTRL].size, - q->txq[TXQ_CTRL].token, 1, 0); - if (ret) - goto err_unlock; - } - - spin_unlock_irq(&adapter->sge.reg_lock); - - q->adap = adapter; - q->netdev = dev; - q->tx_q = netdevq; - t3_update_qset_coalesce(q, p); - - avail = refill_fl(adapter, &q->fl[0], q->fl[0].size, - GFP_KERNEL | __GFP_COMP); - if (!avail) { - CH_ALERT(adapter, "free list queue 0 initialization failed\n"); - goto err; - } - if (avail < q->fl[0].size) - CH_WARN(adapter, "free list queue 0 enabled with %d credits\n", - avail); - - avail = refill_fl(adapter, &q->fl[1], q->fl[1].size, - GFP_KERNEL | __GFP_COMP); - if (avail < q->fl[1].size) - CH_WARN(adapter, "free list queue 1 enabled with %d credits\n", - avail); - refill_rspq(adapter, &q->rspq, q->rspq.size - 1); - - t3_write_reg(adapter, A_SG_GTS, V_RSPQ(q->rspq.cntxt_id) | - V_NEWTIMER(q->rspq.holdoff_tmr)); - - return 0; - -err_unlock: - spin_unlock_irq(&adapter->sge.reg_lock); -err: - t3_free_qset(adapter, q); - return ret; -} - -/** - * t3_start_sge_timers - start SGE timer call backs - * @adap: the adapter - * - * Starts each SGE queue set's timer call back - */ -void t3_start_sge_timers(struct adapter *adap) -{ - int i; - - for (i = 0; i < SGE_QSETS; ++i) { - struct sge_qset *q = &adap->sge.qs[i]; - - if (q->tx_reclaim_timer.function) - mod_timer(&q->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD); - - if (q->rx_reclaim_timer.function) - mod_timer(&q->rx_reclaim_timer, jiffies + RX_RECLAIM_PERIOD); - } -} - -/** - * t3_stop_sge_timers - stop SGE timer call backs - * @adap: the adapter - * - * Stops each SGE queue set's timer call back - */ -void t3_stop_sge_timers(struct adapter *adap) -{ - int i; - - for (i = 0; i < SGE_QSETS; ++i) { - struct sge_qset *q = &adap->sge.qs[i]; - - if (q->tx_reclaim_timer.function) - del_timer_sync(&q->tx_reclaim_timer); - if (q->rx_reclaim_timer.function) - del_timer_sync(&q->rx_reclaim_timer); - } -} - -/** - * t3_free_sge_resources - free SGE resources - * @adap: the adapter - * - * Frees resources used by the SGE queue sets. - */ -void t3_free_sge_resources(struct adapter *adap) -{ - int i; - - for (i = 0; i < SGE_QSETS; ++i) - t3_free_qset(adap, &adap->sge.qs[i]); -} - -/** - * t3_sge_start - enable SGE - * @adap: the adapter - * - * Enables the SGE for DMAs. This is the last step in starting packet - * transfers. - */ -void t3_sge_start(struct adapter *adap) -{ - t3_set_reg_field(adap, A_SG_CONTROL, F_GLOBALENABLE, F_GLOBALENABLE); -} - -/** - * t3_sge_stop - disable SGE operation - * @adap: the adapter - * - * Disables the DMA engine. This can be called in emeregencies (e.g., - * from error interrupts) or from normal process context. In the latter - * case it also disables any pending queue restart tasklets. Note that - * if it is called in interrupt context it cannot disable the restart - * tasklets as it cannot wait, however the tasklets will have no effect - * since the doorbells are disabled and the driver will call this again - * later from process context, at which time the tasklets will be stopped - * if they are still running. - */ -void t3_sge_stop(struct adapter *adap) -{ - t3_set_reg_field(adap, A_SG_CONTROL, F_GLOBALENABLE, 0); - if (!in_interrupt()) { - int i; - - for (i = 0; i < SGE_QSETS; ++i) { - struct sge_qset *qs = &adap->sge.qs[i]; - - tasklet_kill(&qs->txq[TXQ_OFLD].qresume_tsk); - tasklet_kill(&qs->txq[TXQ_CTRL].qresume_tsk); - } - } -} - -/** - * t3_sge_init - initialize SGE - * @adap: the adapter - * @p: the SGE parameters - * - * Performs SGE initialization needed every time after a chip reset. - * We do not initialize any of the queue sets here, instead the driver - * top-level must request those individually. We also do not enable DMA - * here, that should be done after the queues have been set up. - */ -void t3_sge_init(struct adapter *adap, struct sge_params *p) -{ - unsigned int ctrl, ups = ffs(pci_resource_len(adap->pdev, 2) >> 12); - - ctrl = F_DROPPKT | V_PKTSHIFT(2) | F_FLMODE | F_AVOIDCQOVFL | - F_CQCRDTCTRL | F_CONGMODE | F_TNLFLMODE | F_FATLPERREN | - V_HOSTPAGESIZE(PAGE_SHIFT - 11) | F_BIGENDIANINGRESS | - V_USERSPACESIZE(ups ? ups - 1 : 0) | F_ISCSICOALESCING; -#if SGE_NUM_GENBITS == 1 - ctrl |= F_EGRGENCTRL; -#endif - if (adap->params.rev > 0) { - if (!(adap->flags & (USING_MSIX | USING_MSI))) - ctrl |= F_ONEINTMULTQ | F_OPTONEINTMULTQ; - } - t3_write_reg(adap, A_SG_CONTROL, ctrl); - t3_write_reg(adap, A_SG_EGR_RCQ_DRB_THRSH, V_HIRCQDRBTHRSH(512) | - V_LORCQDRBTHRSH(512)); - t3_write_reg(adap, A_SG_TIMER_TICK, core_ticks_per_usec(adap) / 10); - t3_write_reg(adap, A_SG_CMDQ_CREDIT_TH, V_THRESHOLD(32) | - V_TIMEOUT(200 * core_ticks_per_usec(adap))); - t3_write_reg(adap, A_SG_HI_DRB_HI_THRSH, - adap->params.rev < T3_REV_C ? 1000 : 500); - t3_write_reg(adap, A_SG_HI_DRB_LO_THRSH, 256); - t3_write_reg(adap, A_SG_LO_DRB_HI_THRSH, 1000); - t3_write_reg(adap, A_SG_LO_DRB_LO_THRSH, 256); - t3_write_reg(adap, A_SG_OCO_BASE, V_BASE1(0xfff)); - t3_write_reg(adap, A_SG_DRB_PRI_THRESH, 63 * 1024); -} - -/** - * t3_sge_prep - one-time SGE initialization - * @adap: the associated adapter - * @p: SGE parameters - * - * Performs one-time initialization of SGE SW state. Includes determining - * defaults for the assorted SGE parameters, which admins can change until - * they are used to initialize the SGE. - */ -void t3_sge_prep(struct adapter *adap, struct sge_params *p) -{ - int i; - - p->max_pkt_size = (16 * 1024) - sizeof(struct cpl_rx_data) - - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); - - for (i = 0; i < SGE_QSETS; ++i) { - struct qset_params *q = p->qset + i; - - q->polling = adap->params.rev > 0; - q->coalesce_usecs = 5; - q->rspq_size = 1024; - q->fl_size = 1024; - q->jumbo_size = 512; - q->txq_size[TXQ_ETH] = 1024; - q->txq_size[TXQ_OFLD] = 1024; - q->txq_size[TXQ_CTRL] = 256; - q->cong_thres = 0; - } - - spin_lock_init(&adap->sge.reg_lock); -} diff --git a/drivers/net/cxgb3/sge_defs.h b/drivers/net/cxgb3/sge_defs.h deleted file mode 100644 index 29b6c800b238..000000000000 --- a/drivers/net/cxgb3/sge_defs.h +++ /dev/null @@ -1,255 +0,0 @@ -/* - * This file is automatically generated --- any changes will be lost. - */ - -#ifndef _SGE_DEFS_H -#define _SGE_DEFS_H - -#define S_EC_CREDITS 0 -#define M_EC_CREDITS 0x7FFF -#define V_EC_CREDITS(x) ((x) << S_EC_CREDITS) -#define G_EC_CREDITS(x) (((x) >> S_EC_CREDITS) & M_EC_CREDITS) - -#define S_EC_GTS 15 -#define V_EC_GTS(x) ((x) << S_EC_GTS) -#define F_EC_GTS V_EC_GTS(1U) - -#define S_EC_INDEX 16 -#define M_EC_INDEX 0xFFFF -#define V_EC_INDEX(x) ((x) << S_EC_INDEX) -#define G_EC_INDEX(x) (((x) >> S_EC_INDEX) & M_EC_INDEX) - -#define S_EC_SIZE 0 -#define M_EC_SIZE 0xFFFF -#define V_EC_SIZE(x) ((x) << S_EC_SIZE) -#define G_EC_SIZE(x) (((x) >> S_EC_SIZE) & M_EC_SIZE) - -#define S_EC_BASE_LO 16 -#define M_EC_BASE_LO 0xFFFF -#define V_EC_BASE_LO(x) ((x) << S_EC_BASE_LO) -#define G_EC_BASE_LO(x) (((x) >> S_EC_BASE_LO) & M_EC_BASE_LO) - -#define S_EC_BASE_HI 0 -#define M_EC_BASE_HI 0xF -#define V_EC_BASE_HI(x) ((x) << S_EC_BASE_HI) -#define G_EC_BASE_HI(x) (((x) >> S_EC_BASE_HI) & M_EC_BASE_HI) - -#define S_EC_RESPQ 4 -#define M_EC_RESPQ 0x7 -#define V_EC_RESPQ(x) ((x) << S_EC_RESPQ) -#define G_EC_RESPQ(x) (((x) >> S_EC_RESPQ) & M_EC_RESPQ) - -#define S_EC_TYPE 7 -#define M_EC_TYPE 0x7 -#define V_EC_TYPE(x) ((x) << S_EC_TYPE) -#define G_EC_TYPE(x) (((x) >> S_EC_TYPE) & M_EC_TYPE) - -#define S_EC_GEN 10 -#define V_EC_GEN(x) ((x) << S_EC_GEN) -#define F_EC_GEN V_EC_GEN(1U) - -#define S_EC_UP_TOKEN 11 -#define M_EC_UP_TOKEN 0xFFFFF -#define V_EC_UP_TOKEN(x) ((x) << S_EC_UP_TOKEN) -#define G_EC_UP_TOKEN(x) (((x) >> S_EC_UP_TOKEN) & M_EC_UP_TOKEN) - -#define S_EC_VALID 31 -#define V_EC_VALID(x) ((x) << S_EC_VALID) -#define F_EC_VALID V_EC_VALID(1U) - -#define S_RQ_MSI_VEC 20 -#define M_RQ_MSI_VEC 0x3F -#define V_RQ_MSI_VEC(x) ((x) << S_RQ_MSI_VEC) -#define G_RQ_MSI_VEC(x) (((x) >> S_RQ_MSI_VEC) & M_RQ_MSI_VEC) - -#define S_RQ_INTR_EN 26 -#define V_RQ_INTR_EN(x) ((x) << S_RQ_INTR_EN) -#define F_RQ_INTR_EN V_RQ_INTR_EN(1U) - -#define S_RQ_GEN 28 -#define V_RQ_GEN(x) ((x) << S_RQ_GEN) -#define F_RQ_GEN V_RQ_GEN(1U) - -#define S_CQ_INDEX 0 -#define M_CQ_INDEX 0xFFFF -#define V_CQ_INDEX(x) ((x) << S_CQ_INDEX) -#define G_CQ_INDEX(x) (((x) >> S_CQ_INDEX) & M_CQ_INDEX) - -#define S_CQ_SIZE 16 -#define M_CQ_SIZE 0xFFFF -#define V_CQ_SIZE(x) ((x) << S_CQ_SIZE) -#define G_CQ_SIZE(x) (((x) >> S_CQ_SIZE) & M_CQ_SIZE) - -#define S_CQ_BASE_HI 0 -#define M_CQ_BASE_HI 0xFFFFF -#define V_CQ_BASE_HI(x) ((x) << S_CQ_BASE_HI) -#define G_CQ_BASE_HI(x) (((x) >> S_CQ_BASE_HI) & M_CQ_BASE_HI) - -#define S_CQ_RSPQ 20 -#define M_CQ_RSPQ 0x3F -#define V_CQ_RSPQ(x) ((x) << S_CQ_RSPQ) -#define G_CQ_RSPQ(x) (((x) >> S_CQ_RSPQ) & M_CQ_RSPQ) - -#define S_CQ_ASYNC_NOTIF 26 -#define V_CQ_ASYNC_NOTIF(x) ((x) << S_CQ_ASYNC_NOTIF) -#define F_CQ_ASYNC_NOTIF V_CQ_ASYNC_NOTIF(1U) - -#define S_CQ_ARMED 27 -#define V_CQ_ARMED(x) ((x) << S_CQ_ARMED) -#define F_CQ_ARMED V_CQ_ARMED(1U) - -#define S_CQ_ASYNC_NOTIF_SOL 28 -#define V_CQ_ASYNC_NOTIF_SOL(x) ((x) << S_CQ_ASYNC_NOTIF_SOL) -#define F_CQ_ASYNC_NOTIF_SOL V_CQ_ASYNC_NOTIF_SOL(1U) - -#define S_CQ_GEN 29 -#define V_CQ_GEN(x) ((x) << S_CQ_GEN) -#define F_CQ_GEN V_CQ_GEN(1U) - -#define S_CQ_ERR 30 -#define V_CQ_ERR(x) ((x) << S_CQ_ERR) -#define F_CQ_ERR V_CQ_ERR(1U) - -#define S_CQ_OVERFLOW_MODE 31 -#define V_CQ_OVERFLOW_MODE(x) ((x) << S_CQ_OVERFLOW_MODE) -#define F_CQ_OVERFLOW_MODE V_CQ_OVERFLOW_MODE(1U) - -#define S_CQ_CREDITS 0 -#define M_CQ_CREDITS 0xFFFF -#define V_CQ_CREDITS(x) ((x) << S_CQ_CREDITS) -#define G_CQ_CREDITS(x) (((x) >> S_CQ_CREDITS) & M_CQ_CREDITS) - -#define S_CQ_CREDIT_THRES 16 -#define M_CQ_CREDIT_THRES 0x1FFF -#define V_CQ_CREDIT_THRES(x) ((x) << S_CQ_CREDIT_THRES) -#define G_CQ_CREDIT_THRES(x) (((x) >> S_CQ_CREDIT_THRES) & M_CQ_CREDIT_THRES) - -#define S_FL_BASE_HI 0 -#define M_FL_BASE_HI 0xFFFFF -#define V_FL_BASE_HI(x) ((x) << S_FL_BASE_HI) -#define G_FL_BASE_HI(x) (((x) >> S_FL_BASE_HI) & M_FL_BASE_HI) - -#define S_FL_INDEX_LO 20 -#define M_FL_INDEX_LO 0xFFF -#define V_FL_INDEX_LO(x) ((x) << S_FL_INDEX_LO) -#define G_FL_INDEX_LO(x) (((x) >> S_FL_INDEX_LO) & M_FL_INDEX_LO) - -#define S_FL_INDEX_HI 0 -#define M_FL_INDEX_HI 0xF -#define V_FL_INDEX_HI(x) ((x) << S_FL_INDEX_HI) -#define G_FL_INDEX_HI(x) (((x) >> S_FL_INDEX_HI) & M_FL_INDEX_HI) - -#define S_FL_SIZE 4 -#define M_FL_SIZE 0xFFFF -#define V_FL_SIZE(x) ((x) << S_FL_SIZE) -#define G_FL_SIZE(x) (((x) >> S_FL_SIZE) & M_FL_SIZE) - -#define S_FL_GEN 20 -#define V_FL_GEN(x) ((x) << S_FL_GEN) -#define F_FL_GEN V_FL_GEN(1U) - -#define S_FL_ENTRY_SIZE_LO 21 -#define M_FL_ENTRY_SIZE_LO 0x7FF -#define V_FL_ENTRY_SIZE_LO(x) ((x) << S_FL_ENTRY_SIZE_LO) -#define G_FL_ENTRY_SIZE_LO(x) (((x) >> S_FL_ENTRY_SIZE_LO) & M_FL_ENTRY_SIZE_LO) - -#define S_FL_ENTRY_SIZE_HI 0 -#define M_FL_ENTRY_SIZE_HI 0x1FFFFF -#define V_FL_ENTRY_SIZE_HI(x) ((x) << S_FL_ENTRY_SIZE_HI) -#define G_FL_ENTRY_SIZE_HI(x) (((x) >> S_FL_ENTRY_SIZE_HI) & M_FL_ENTRY_SIZE_HI) - -#define S_FL_CONG_THRES 21 -#define M_FL_CONG_THRES 0x3FF -#define V_FL_CONG_THRES(x) ((x) << S_FL_CONG_THRES) -#define G_FL_CONG_THRES(x) (((x) >> S_FL_CONG_THRES) & M_FL_CONG_THRES) - -#define S_FL_GTS 31 -#define V_FL_GTS(x) ((x) << S_FL_GTS) -#define F_FL_GTS V_FL_GTS(1U) - -#define S_FLD_GEN1 31 -#define V_FLD_GEN1(x) ((x) << S_FLD_GEN1) -#define F_FLD_GEN1 V_FLD_GEN1(1U) - -#define S_FLD_GEN2 0 -#define V_FLD_GEN2(x) ((x) << S_FLD_GEN2) -#define F_FLD_GEN2 V_FLD_GEN2(1U) - -#define S_RSPD_TXQ1_CR 0 -#define M_RSPD_TXQ1_CR 0x7F -#define V_RSPD_TXQ1_CR(x) ((x) << S_RSPD_TXQ1_CR) -#define G_RSPD_TXQ1_CR(x) (((x) >> S_RSPD_TXQ1_CR) & M_RSPD_TXQ1_CR) - -#define S_RSPD_TXQ1_GTS 7 -#define V_RSPD_TXQ1_GTS(x) ((x) << S_RSPD_TXQ1_GTS) -#define F_RSPD_TXQ1_GTS V_RSPD_TXQ1_GTS(1U) - -#define S_RSPD_TXQ2_CR 8 -#define M_RSPD_TXQ2_CR 0x7F -#define V_RSPD_TXQ2_CR(x) ((x) << S_RSPD_TXQ2_CR) -#define G_RSPD_TXQ2_CR(x) (((x) >> S_RSPD_TXQ2_CR) & M_RSPD_TXQ2_CR) - -#define S_RSPD_TXQ2_GTS 15 -#define V_RSPD_TXQ2_GTS(x) ((x) << S_RSPD_TXQ2_GTS) -#define F_RSPD_TXQ2_GTS V_RSPD_TXQ2_GTS(1U) - -#define S_RSPD_TXQ0_CR 16 -#define M_RSPD_TXQ0_CR 0x7F -#define V_RSPD_TXQ0_CR(x) ((x) << S_RSPD_TXQ0_CR) -#define G_RSPD_TXQ0_CR(x) (((x) >> S_RSPD_TXQ0_CR) & M_RSPD_TXQ0_CR) - -#define S_RSPD_TXQ0_GTS 23 -#define V_RSPD_TXQ0_GTS(x) ((x) << S_RSPD_TXQ0_GTS) -#define F_RSPD_TXQ0_GTS V_RSPD_TXQ0_GTS(1U) - -#define S_RSPD_EOP 24 -#define V_RSPD_EOP(x) ((x) << S_RSPD_EOP) -#define F_RSPD_EOP V_RSPD_EOP(1U) - -#define S_RSPD_SOP 25 -#define V_RSPD_SOP(x) ((x) << S_RSPD_SOP) -#define F_RSPD_SOP V_RSPD_SOP(1U) - -#define S_RSPD_ASYNC_NOTIF 26 -#define V_RSPD_ASYNC_NOTIF(x) ((x) << S_RSPD_ASYNC_NOTIF) -#define F_RSPD_ASYNC_NOTIF V_RSPD_ASYNC_NOTIF(1U) - -#define S_RSPD_FL0_GTS 27 -#define V_RSPD_FL0_GTS(x) ((x) << S_RSPD_FL0_GTS) -#define F_RSPD_FL0_GTS V_RSPD_FL0_GTS(1U) - -#define S_RSPD_FL1_GTS 28 -#define V_RSPD_FL1_GTS(x) ((x) << S_RSPD_FL1_GTS) -#define F_RSPD_FL1_GTS V_RSPD_FL1_GTS(1U) - -#define S_RSPD_IMM_DATA_VALID 29 -#define V_RSPD_IMM_DATA_VALID(x) ((x) << S_RSPD_IMM_DATA_VALID) -#define F_RSPD_IMM_DATA_VALID V_RSPD_IMM_DATA_VALID(1U) - -#define S_RSPD_OFFLOAD 30 -#define V_RSPD_OFFLOAD(x) ((x) << S_RSPD_OFFLOAD) -#define F_RSPD_OFFLOAD V_RSPD_OFFLOAD(1U) - -#define S_RSPD_GEN1 31 -#define V_RSPD_GEN1(x) ((x) << S_RSPD_GEN1) -#define F_RSPD_GEN1 V_RSPD_GEN1(1U) - -#define S_RSPD_LEN 0 -#define M_RSPD_LEN 0x7FFFFFFF -#define V_RSPD_LEN(x) ((x) << S_RSPD_LEN) -#define G_RSPD_LEN(x) (((x) >> S_RSPD_LEN) & M_RSPD_LEN) - -#define S_RSPD_FLQ 31 -#define V_RSPD_FLQ(x) ((x) << S_RSPD_FLQ) -#define F_RSPD_FLQ V_RSPD_FLQ(1U) - -#define S_RSPD_GEN2 0 -#define V_RSPD_GEN2(x) ((x) << S_RSPD_GEN2) -#define F_RSPD_GEN2 V_RSPD_GEN2(1U) - -#define S_RSPD_INR_VEC 1 -#define M_RSPD_INR_VEC 0x7F -#define V_RSPD_INR_VEC(x) ((x) << S_RSPD_INR_VEC) -#define G_RSPD_INR_VEC(x) (((x) >> S_RSPD_INR_VEC) & M_RSPD_INR_VEC) - -#endif /* _SGE_DEFS_H */ diff --git a/drivers/net/cxgb3/t3_cpl.h b/drivers/net/cxgb3/t3_cpl.h deleted file mode 100644 index 852c399a8b0a..000000000000 --- a/drivers/net/cxgb3/t3_cpl.h +++ /dev/null @@ -1,1495 +0,0 @@ -/* - * Copyright (c) 2004-2008 Chelsio, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef T3_CPL_H -#define T3_CPL_H - -#if !defined(__LITTLE_ENDIAN_BITFIELD) && !defined(__BIG_ENDIAN_BITFIELD) -# include -#endif - -enum CPL_opcode { - CPL_PASS_OPEN_REQ = 0x1, - CPL_PASS_ACCEPT_RPL = 0x2, - CPL_ACT_OPEN_REQ = 0x3, - CPL_SET_TCB = 0x4, - CPL_SET_TCB_FIELD = 0x5, - CPL_GET_TCB = 0x6, - CPL_PCMD = 0x7, - CPL_CLOSE_CON_REQ = 0x8, - CPL_CLOSE_LISTSRV_REQ = 0x9, - CPL_ABORT_REQ = 0xA, - CPL_ABORT_RPL = 0xB, - CPL_TX_DATA = 0xC, - CPL_RX_DATA_ACK = 0xD, - CPL_TX_PKT = 0xE, - CPL_RTE_DELETE_REQ = 0xF, - CPL_RTE_WRITE_REQ = 0x10, - CPL_RTE_READ_REQ = 0x11, - CPL_L2T_WRITE_REQ = 0x12, - CPL_L2T_READ_REQ = 0x13, - CPL_SMT_WRITE_REQ = 0x14, - CPL_SMT_READ_REQ = 0x15, - CPL_TX_PKT_LSO = 0x16, - CPL_PCMD_READ = 0x17, - CPL_BARRIER = 0x18, - CPL_TID_RELEASE = 0x1A, - - CPL_CLOSE_LISTSRV_RPL = 0x20, - CPL_ERROR = 0x21, - CPL_GET_TCB_RPL = 0x22, - CPL_L2T_WRITE_RPL = 0x23, - CPL_PCMD_READ_RPL = 0x24, - CPL_PCMD_RPL = 0x25, - CPL_PEER_CLOSE = 0x26, - CPL_RTE_DELETE_RPL = 0x27, - CPL_RTE_WRITE_RPL = 0x28, - CPL_RX_DDP_COMPLETE = 0x29, - CPL_RX_PHYS_ADDR = 0x2A, - CPL_RX_PKT = 0x2B, - CPL_RX_URG_NOTIFY = 0x2C, - CPL_SET_TCB_RPL = 0x2D, - CPL_SMT_WRITE_RPL = 0x2E, - CPL_TX_DATA_ACK = 0x2F, - - CPL_ABORT_REQ_RSS = 0x30, - CPL_ABORT_RPL_RSS = 0x31, - CPL_CLOSE_CON_RPL = 0x32, - CPL_ISCSI_HDR = 0x33, - CPL_L2T_READ_RPL = 0x34, - CPL_RDMA_CQE = 0x35, - CPL_RDMA_CQE_READ_RSP = 0x36, - CPL_RDMA_CQE_ERR = 0x37, - CPL_RTE_READ_RPL = 0x38, - CPL_RX_DATA = 0x39, - - CPL_ACT_OPEN_RPL = 0x40, - CPL_PASS_OPEN_RPL = 0x41, - CPL_RX_DATA_DDP = 0x42, - CPL_SMT_READ_RPL = 0x43, - - CPL_ACT_ESTABLISH = 0x50, - CPL_PASS_ESTABLISH = 0x51, - - CPL_PASS_ACCEPT_REQ = 0x70, - - CPL_ASYNC_NOTIF = 0x80, /* fake opcode for async notifications */ - - CPL_TX_DMA_ACK = 0xA0, - CPL_RDMA_READ_REQ = 0xA1, - CPL_RDMA_TERMINATE = 0xA2, - CPL_TRACE_PKT = 0xA3, - CPL_RDMA_EC_STATUS = 0xA5, - - NUM_CPL_CMDS /* must be last and previous entries must be sorted */ -}; - -enum CPL_error { - CPL_ERR_NONE = 0, - CPL_ERR_TCAM_PARITY = 1, - CPL_ERR_TCAM_FULL = 3, - CPL_ERR_CONN_RESET = 20, - CPL_ERR_CONN_EXIST = 22, - CPL_ERR_ARP_MISS = 23, - CPL_ERR_BAD_SYN = 24, - CPL_ERR_CONN_TIMEDOUT = 30, - CPL_ERR_XMIT_TIMEDOUT = 31, - CPL_ERR_PERSIST_TIMEDOUT = 32, - CPL_ERR_FINWAIT2_TIMEDOUT = 33, - CPL_ERR_KEEPALIVE_TIMEDOUT = 34, - CPL_ERR_RTX_NEG_ADVICE = 35, - CPL_ERR_PERSIST_NEG_ADVICE = 36, - CPL_ERR_ABORT_FAILED = 42, - CPL_ERR_GENERAL = 99 -}; - -enum { - CPL_CONN_POLICY_AUTO = 0, - CPL_CONN_POLICY_ASK = 1, - CPL_CONN_POLICY_DENY = 3 -}; - -enum { - ULP_MODE_NONE = 0, - ULP_MODE_ISCSI = 2, - ULP_MODE_RDMA = 4, - ULP_MODE_TCPDDP = 5 -}; - -enum { - ULP_CRC_HEADER = 1 << 0, - ULP_CRC_DATA = 1 << 1 -}; - -enum { - CPL_PASS_OPEN_ACCEPT, - CPL_PASS_OPEN_REJECT -}; - -enum { - CPL_ABORT_SEND_RST = 0, - CPL_ABORT_NO_RST, - CPL_ABORT_POST_CLOSE_REQ = 2 -}; - -enum { /* TX_PKT_LSO ethernet types */ - CPL_ETH_II, - CPL_ETH_II_VLAN, - CPL_ETH_802_3, - CPL_ETH_802_3_VLAN -}; - -enum { /* TCP congestion control algorithms */ - CONG_ALG_RENO, - CONG_ALG_TAHOE, - CONG_ALG_NEWRENO, - CONG_ALG_HIGHSPEED -}; - -enum { /* RSS hash type */ - RSS_HASH_NONE = 0, - RSS_HASH_2_TUPLE = 1, - RSS_HASH_4_TUPLE = 2, - RSS_HASH_TCPV6 = 3 -}; - -union opcode_tid { - __be32 opcode_tid; - __u8 opcode; -}; - -#define S_OPCODE 24 -#define V_OPCODE(x) ((x) << S_OPCODE) -#define G_OPCODE(x) (((x) >> S_OPCODE) & 0xFF) -#define G_TID(x) ((x) & 0xFFFFFF) - -#define S_QNUM 0 -#define G_QNUM(x) (((x) >> S_QNUM) & 0xFFFF) - -#define S_HASHTYPE 22 -#define M_HASHTYPE 0x3 -#define G_HASHTYPE(x) (((x) >> S_HASHTYPE) & M_HASHTYPE) - -/* tid is assumed to be 24-bits */ -#define MK_OPCODE_TID(opcode, tid) (V_OPCODE(opcode) | (tid)) - -#define OPCODE_TID(cmd) ((cmd)->ot.opcode_tid) - -/* extract the TID from a CPL command */ -#define GET_TID(cmd) (G_TID(ntohl(OPCODE_TID(cmd)))) - -struct tcp_options { - __be16 mss; - __u8 wsf; -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8:5; - __u8 ecn:1; - __u8 sack:1; - __u8 tstamp:1; -#else - __u8 tstamp:1; - __u8 sack:1; - __u8 ecn:1; - __u8:5; -#endif -}; - -struct rss_header { - __u8 opcode; -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8 cpu_idx:6; - __u8 hash_type:2; -#else - __u8 hash_type:2; - __u8 cpu_idx:6; -#endif - __be16 cq_idx; - __be32 rss_hash_val; -}; - -#ifndef CHELSIO_FW -struct work_request_hdr { - __be32 wr_hi; - __be32 wr_lo; -}; - -/* wr_hi fields */ -#define S_WR_SGE_CREDITS 0 -#define M_WR_SGE_CREDITS 0xFF -#define V_WR_SGE_CREDITS(x) ((x) << S_WR_SGE_CREDITS) -#define G_WR_SGE_CREDITS(x) (((x) >> S_WR_SGE_CREDITS) & M_WR_SGE_CREDITS) - -#define S_WR_SGLSFLT 8 -#define M_WR_SGLSFLT 0xFF -#define V_WR_SGLSFLT(x) ((x) << S_WR_SGLSFLT) -#define G_WR_SGLSFLT(x) (((x) >> S_WR_SGLSFLT) & M_WR_SGLSFLT) - -#define S_WR_BCNTLFLT 16 -#define M_WR_BCNTLFLT 0xF -#define V_WR_BCNTLFLT(x) ((x) << S_WR_BCNTLFLT) -#define G_WR_BCNTLFLT(x) (((x) >> S_WR_BCNTLFLT) & M_WR_BCNTLFLT) - -#define S_WR_DATATYPE 20 -#define V_WR_DATATYPE(x) ((x) << S_WR_DATATYPE) -#define F_WR_DATATYPE V_WR_DATATYPE(1U) - -#define S_WR_COMPL 21 -#define V_WR_COMPL(x) ((x) << S_WR_COMPL) -#define F_WR_COMPL V_WR_COMPL(1U) - -#define S_WR_EOP 22 -#define V_WR_EOP(x) ((x) << S_WR_EOP) -#define F_WR_EOP V_WR_EOP(1U) - -#define S_WR_SOP 23 -#define V_WR_SOP(x) ((x) << S_WR_SOP) -#define F_WR_SOP V_WR_SOP(1U) - -#define S_WR_OP 24 -#define M_WR_OP 0xFF -#define V_WR_OP(x) ((x) << S_WR_OP) -#define G_WR_OP(x) (((x) >> S_WR_OP) & M_WR_OP) - -/* wr_lo fields */ -#define S_WR_LEN 0 -#define M_WR_LEN 0xFF -#define V_WR_LEN(x) ((x) << S_WR_LEN) -#define G_WR_LEN(x) (((x) >> S_WR_LEN) & M_WR_LEN) - -#define S_WR_TID 8 -#define M_WR_TID 0xFFFFF -#define V_WR_TID(x) ((x) << S_WR_TID) -#define G_WR_TID(x) (((x) >> S_WR_TID) & M_WR_TID) - -#define S_WR_CR_FLUSH 30 -#define V_WR_CR_FLUSH(x) ((x) << S_WR_CR_FLUSH) -#define F_WR_CR_FLUSH V_WR_CR_FLUSH(1U) - -#define S_WR_GEN 31 -#define V_WR_GEN(x) ((x) << S_WR_GEN) -#define F_WR_GEN V_WR_GEN(1U) - -# define WR_HDR struct work_request_hdr wr -# define RSS_HDR -#else -# define WR_HDR -# define RSS_HDR struct rss_header rss_hdr; -#endif - -/* option 0 lower-half fields */ -#define S_CPL_STATUS 0 -#define M_CPL_STATUS 0xFF -#define V_CPL_STATUS(x) ((x) << S_CPL_STATUS) -#define G_CPL_STATUS(x) (((x) >> S_CPL_STATUS) & M_CPL_STATUS) - -#define S_INJECT_TIMER 6 -#define V_INJECT_TIMER(x) ((x) << S_INJECT_TIMER) -#define F_INJECT_TIMER V_INJECT_TIMER(1U) - -#define S_NO_OFFLOAD 7 -#define V_NO_OFFLOAD(x) ((x) << S_NO_OFFLOAD) -#define F_NO_OFFLOAD V_NO_OFFLOAD(1U) - -#define S_ULP_MODE 8 -#define M_ULP_MODE 0xF -#define V_ULP_MODE(x) ((x) << S_ULP_MODE) -#define G_ULP_MODE(x) (((x) >> S_ULP_MODE) & M_ULP_MODE) - -#define S_RCV_BUFSIZ 12 -#define M_RCV_BUFSIZ 0x3FFF -#define V_RCV_BUFSIZ(x) ((x) << S_RCV_BUFSIZ) -#define G_RCV_BUFSIZ(x) (((x) >> S_RCV_BUFSIZ) & M_RCV_BUFSIZ) - -#define S_TOS 26 -#define M_TOS 0x3F -#define V_TOS(x) ((x) << S_TOS) -#define G_TOS(x) (((x) >> S_TOS) & M_TOS) - -/* option 0 upper-half fields */ -#define S_DELACK 0 -#define V_DELACK(x) ((x) << S_DELACK) -#define F_DELACK V_DELACK(1U) - -#define S_NO_CONG 1 -#define V_NO_CONG(x) ((x) << S_NO_CONG) -#define F_NO_CONG V_NO_CONG(1U) - -#define S_SRC_MAC_SEL 2 -#define M_SRC_MAC_SEL 0x3 -#define V_SRC_MAC_SEL(x) ((x) << S_SRC_MAC_SEL) -#define G_SRC_MAC_SEL(x) (((x) >> S_SRC_MAC_SEL) & M_SRC_MAC_SEL) - -#define S_L2T_IDX 4 -#define M_L2T_IDX 0x7FF -#define V_L2T_IDX(x) ((x) << S_L2T_IDX) -#define G_L2T_IDX(x) (((x) >> S_L2T_IDX) & M_L2T_IDX) - -#define S_TX_CHANNEL 15 -#define V_TX_CHANNEL(x) ((x) << S_TX_CHANNEL) -#define F_TX_CHANNEL V_TX_CHANNEL(1U) - -#define S_TCAM_BYPASS 16 -#define V_TCAM_BYPASS(x) ((x) << S_TCAM_BYPASS) -#define F_TCAM_BYPASS V_TCAM_BYPASS(1U) - -#define S_NAGLE 17 -#define V_NAGLE(x) ((x) << S_NAGLE) -#define F_NAGLE V_NAGLE(1U) - -#define S_WND_SCALE 18 -#define M_WND_SCALE 0xF -#define V_WND_SCALE(x) ((x) << S_WND_SCALE) -#define G_WND_SCALE(x) (((x) >> S_WND_SCALE) & M_WND_SCALE) - -#define S_KEEP_ALIVE 22 -#define V_KEEP_ALIVE(x) ((x) << S_KEEP_ALIVE) -#define F_KEEP_ALIVE V_KEEP_ALIVE(1U) - -#define S_MAX_RETRANS 23 -#define M_MAX_RETRANS 0xF -#define V_MAX_RETRANS(x) ((x) << S_MAX_RETRANS) -#define G_MAX_RETRANS(x) (((x) >> S_MAX_RETRANS) & M_MAX_RETRANS) - -#define S_MAX_RETRANS_OVERRIDE 27 -#define V_MAX_RETRANS_OVERRIDE(x) ((x) << S_MAX_RETRANS_OVERRIDE) -#define F_MAX_RETRANS_OVERRIDE V_MAX_RETRANS_OVERRIDE(1U) - -#define S_MSS_IDX 28 -#define M_MSS_IDX 0xF -#define V_MSS_IDX(x) ((x) << S_MSS_IDX) -#define G_MSS_IDX(x) (((x) >> S_MSS_IDX) & M_MSS_IDX) - -/* option 1 fields */ -#define S_RSS_ENABLE 0 -#define V_RSS_ENABLE(x) ((x) << S_RSS_ENABLE) -#define F_RSS_ENABLE V_RSS_ENABLE(1U) - -#define S_RSS_MASK_LEN 1 -#define M_RSS_MASK_LEN 0x7 -#define V_RSS_MASK_LEN(x) ((x) << S_RSS_MASK_LEN) -#define G_RSS_MASK_LEN(x) (((x) >> S_RSS_MASK_LEN) & M_RSS_MASK_LEN) - -#define S_CPU_IDX 4 -#define M_CPU_IDX 0x3F -#define V_CPU_IDX(x) ((x) << S_CPU_IDX) -#define G_CPU_IDX(x) (((x) >> S_CPU_IDX) & M_CPU_IDX) - -#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) - -#define S_CONN_POLICY 19 -#define M_CONN_POLICY 0x3 -#define V_CONN_POLICY(x) ((x) << S_CONN_POLICY) -#define G_CONN_POLICY(x) (((x) >> S_CONN_POLICY) & M_CONN_POLICY) - -#define S_SYN_DEFENSE 21 -#define V_SYN_DEFENSE(x) ((x) << S_SYN_DEFENSE) -#define F_SYN_DEFENSE V_SYN_DEFENSE(1U) - -#define S_VLAN_PRI 22 -#define M_VLAN_PRI 0x3 -#define V_VLAN_PRI(x) ((x) << S_VLAN_PRI) -#define G_VLAN_PRI(x) (((x) >> S_VLAN_PRI) & M_VLAN_PRI) - -#define S_VLAN_PRI_VALID 24 -#define V_VLAN_PRI_VALID(x) ((x) << S_VLAN_PRI_VALID) -#define F_VLAN_PRI_VALID V_VLAN_PRI_VALID(1U) - -#define S_PKT_TYPE 25 -#define M_PKT_TYPE 0x3 -#define V_PKT_TYPE(x) ((x) << S_PKT_TYPE) -#define G_PKT_TYPE(x) (((x) >> S_PKT_TYPE) & M_PKT_TYPE) - -#define S_MAC_MATCH 27 -#define M_MAC_MATCH 0x1F -#define V_MAC_MATCH(x) ((x) << S_MAC_MATCH) -#define G_MAC_MATCH(x) (((x) >> S_MAC_MATCH) & M_MAC_MATCH) - -/* option 2 fields */ -#define S_CPU_INDEX 0 -#define M_CPU_INDEX 0x7F -#define V_CPU_INDEX(x) ((x) << S_CPU_INDEX) -#define G_CPU_INDEX(x) (((x) >> S_CPU_INDEX) & M_CPU_INDEX) - -#define S_CPU_INDEX_VALID 7 -#define V_CPU_INDEX_VALID(x) ((x) << S_CPU_INDEX_VALID) -#define F_CPU_INDEX_VALID V_CPU_INDEX_VALID(1U) - -#define S_RX_COALESCE 8 -#define M_RX_COALESCE 0x3 -#define V_RX_COALESCE(x) ((x) << S_RX_COALESCE) -#define G_RX_COALESCE(x) (((x) >> S_RX_COALESCE) & M_RX_COALESCE) - -#define S_RX_COALESCE_VALID 10 -#define V_RX_COALESCE_VALID(x) ((x) << S_RX_COALESCE_VALID) -#define F_RX_COALESCE_VALID V_RX_COALESCE_VALID(1U) - -#define S_CONG_CONTROL_FLAVOR 11 -#define M_CONG_CONTROL_FLAVOR 0x3 -#define V_CONG_CONTROL_FLAVOR(x) ((x) << S_CONG_CONTROL_FLAVOR) -#define G_CONG_CONTROL_FLAVOR(x) (((x) >> S_CONG_CONTROL_FLAVOR) & M_CONG_CONTROL_FLAVOR) - -#define S_PACING_FLAVOR 13 -#define M_PACING_FLAVOR 0x3 -#define V_PACING_FLAVOR(x) ((x) << S_PACING_FLAVOR) -#define G_PACING_FLAVOR(x) (((x) >> S_PACING_FLAVOR) & M_PACING_FLAVOR) - -#define S_FLAVORS_VALID 15 -#define V_FLAVORS_VALID(x) ((x) << S_FLAVORS_VALID) -#define F_FLAVORS_VALID V_FLAVORS_VALID(1U) - -#define S_RX_FC_DISABLE 16 -#define V_RX_FC_DISABLE(x) ((x) << S_RX_FC_DISABLE) -#define F_RX_FC_DISABLE V_RX_FC_DISABLE(1U) - -#define S_RX_FC_VALID 17 -#define V_RX_FC_VALID(x) ((x) << S_RX_FC_VALID) -#define F_RX_FC_VALID V_RX_FC_VALID(1U) - -struct cpl_pass_open_req { - WR_HDR; - union opcode_tid ot; - __be16 local_port; - __be16 peer_port; - __be32 local_ip; - __be32 peer_ip; - __be32 opt0h; - __be32 opt0l; - __be32 peer_netmask; - __be32 opt1; -}; - -struct cpl_pass_open_rpl { - RSS_HDR union opcode_tid ot; - __be16 local_port; - __be16 peer_port; - __be32 local_ip; - __be32 peer_ip; - __u8 resvd[7]; - __u8 status; -}; - -struct cpl_pass_establish { - RSS_HDR union opcode_tid ot; - __be16 local_port; - __be16 peer_port; - __be32 local_ip; - __be32 peer_ip; - __be32 tos_tid; - __be16 l2t_idx; - __be16 tcp_opt; - __be32 snd_isn; - __be32 rcv_isn; -}; - -/* cpl_pass_establish.tos_tid fields */ -#define S_PASS_OPEN_TID 0 -#define M_PASS_OPEN_TID 0xFFFFFF -#define V_PASS_OPEN_TID(x) ((x) << S_PASS_OPEN_TID) -#define G_PASS_OPEN_TID(x) (((x) >> S_PASS_OPEN_TID) & M_PASS_OPEN_TID) - -#define S_PASS_OPEN_TOS 24 -#define M_PASS_OPEN_TOS 0xFF -#define V_PASS_OPEN_TOS(x) ((x) << S_PASS_OPEN_TOS) -#define G_PASS_OPEN_TOS(x) (((x) >> S_PASS_OPEN_TOS) & M_PASS_OPEN_TOS) - -/* cpl_pass_establish.l2t_idx fields */ -#define S_L2T_IDX16 5 -#define M_L2T_IDX16 0x7FF -#define V_L2T_IDX16(x) ((x) << S_L2T_IDX16) -#define G_L2T_IDX16(x) (((x) >> S_L2T_IDX16) & M_L2T_IDX16) - -/* cpl_pass_establish.tcp_opt fields (also applies act_open_establish) */ -#define G_TCPOPT_WSCALE_OK(x) (((x) >> 5) & 1) -#define G_TCPOPT_SACK(x) (((x) >> 6) & 1) -#define G_TCPOPT_TSTAMP(x) (((x) >> 7) & 1) -#define G_TCPOPT_SND_WSCALE(x) (((x) >> 8) & 0xf) -#define G_TCPOPT_MSS(x) (((x) >> 12) & 0xf) - -struct cpl_pass_accept_req { - RSS_HDR union opcode_tid ot; - __be16 local_port; - __be16 peer_port; - __be32 local_ip; - __be32 peer_ip; - __be32 tos_tid; - struct tcp_options tcp_options; - __u8 dst_mac[6]; - __be16 vlan_tag; - __u8 src_mac[6]; -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8:3; - __u8 addr_idx:3; - __u8 port_idx:1; - __u8 exact_match:1; -#else - __u8 exact_match:1; - __u8 port_idx:1; - __u8 addr_idx:3; - __u8:3; -#endif - __u8 rsvd; - __be32 rcv_isn; - __be32 rsvd2; -}; - -struct cpl_pass_accept_rpl { - WR_HDR; - union opcode_tid ot; - __be32 opt2; - __be32 rsvd; - __be32 peer_ip; - __be32 opt0h; - __be32 opt0l_status; -}; - -struct cpl_act_open_req { - WR_HDR; - union opcode_tid ot; - __be16 local_port; - __be16 peer_port; - __be32 local_ip; - __be32 peer_ip; - __be32 opt0h; - __be32 opt0l; - __be32 params; - __be32 opt2; -}; - -/* cpl_act_open_req.params fields */ -#define S_AOPEN_VLAN_PRI 9 -#define M_AOPEN_VLAN_PRI 0x3 -#define V_AOPEN_VLAN_PRI(x) ((x) << S_AOPEN_VLAN_PRI) -#define G_AOPEN_VLAN_PRI(x) (((x) >> S_AOPEN_VLAN_PRI) & M_AOPEN_VLAN_PRI) - -#define S_AOPEN_VLAN_PRI_VALID 11 -#define V_AOPEN_VLAN_PRI_VALID(x) ((x) << S_AOPEN_VLAN_PRI_VALID) -#define F_AOPEN_VLAN_PRI_VALID V_AOPEN_VLAN_PRI_VALID(1U) - -#define S_AOPEN_PKT_TYPE 12 -#define M_AOPEN_PKT_TYPE 0x3 -#define V_AOPEN_PKT_TYPE(x) ((x) << S_AOPEN_PKT_TYPE) -#define G_AOPEN_PKT_TYPE(x) (((x) >> S_AOPEN_PKT_TYPE) & M_AOPEN_PKT_TYPE) - -#define S_AOPEN_MAC_MATCH 14 -#define M_AOPEN_MAC_MATCH 0x1F -#define V_AOPEN_MAC_MATCH(x) ((x) << S_AOPEN_MAC_MATCH) -#define G_AOPEN_MAC_MATCH(x) (((x) >> S_AOPEN_MAC_MATCH) & M_AOPEN_MAC_MATCH) - -#define S_AOPEN_MAC_MATCH_VALID 19 -#define V_AOPEN_MAC_MATCH_VALID(x) ((x) << S_AOPEN_MAC_MATCH_VALID) -#define F_AOPEN_MAC_MATCH_VALID V_AOPEN_MAC_MATCH_VALID(1U) - -#define S_AOPEN_IFF_VLAN 20 -#define M_AOPEN_IFF_VLAN 0xFFF -#define V_AOPEN_IFF_VLAN(x) ((x) << S_AOPEN_IFF_VLAN) -#define G_AOPEN_IFF_VLAN(x) (((x) >> S_AOPEN_IFF_VLAN) & M_AOPEN_IFF_VLAN) - -struct cpl_act_open_rpl { - RSS_HDR union opcode_tid ot; - __be16 local_port; - __be16 peer_port; - __be32 local_ip; - __be32 peer_ip; - __be32 atid; - __u8 rsvd[3]; - __u8 status; -}; - -struct cpl_act_establish { - RSS_HDR union opcode_tid ot; - __be16 local_port; - __be16 peer_port; - __be32 local_ip; - __be32 peer_ip; - __be32 tos_tid; - __be16 l2t_idx; - __be16 tcp_opt; - __be32 snd_isn; - __be32 rcv_isn; -}; - -struct cpl_get_tcb { - WR_HDR; - union opcode_tid ot; - __be16 cpuno; - __be16 rsvd; -}; - -struct cpl_get_tcb_rpl { - RSS_HDR union opcode_tid ot; - __u8 rsvd; - __u8 status; - __be16 len; -}; - -struct cpl_set_tcb { - WR_HDR; - union opcode_tid ot; - __u8 reply; - __u8 cpu_idx; - __be16 len; -}; - -/* cpl_set_tcb.reply fields */ -#define S_NO_REPLY 7 -#define V_NO_REPLY(x) ((x) << S_NO_REPLY) -#define F_NO_REPLY V_NO_REPLY(1U) - -struct cpl_set_tcb_field { - WR_HDR; - union opcode_tid ot; - __u8 reply; - __u8 cpu_idx; - __be16 word; - __be64 mask; - __be64 val; -}; - -struct cpl_set_tcb_rpl { - RSS_HDR union opcode_tid ot; - __u8 rsvd[3]; - __u8 status; -}; - -struct cpl_pcmd { - WR_HDR; - union opcode_tid ot; - __u8 rsvd[3]; -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8 src:1; - __u8 bundle:1; - __u8 channel:1; - __u8:5; -#else - __u8:5; - __u8 channel:1; - __u8 bundle:1; - __u8 src:1; -#endif - __be32 pcmd_parm[2]; -}; - -struct cpl_pcmd_reply { - RSS_HDR union opcode_tid ot; - __u8 status; - __u8 rsvd; - __be16 len; -}; - -struct cpl_close_con_req { - WR_HDR; - union opcode_tid ot; - __be32 rsvd; -}; - -struct cpl_close_con_rpl { - RSS_HDR union opcode_tid ot; - __u8 rsvd[3]; - __u8 status; - __be32 snd_nxt; - __be32 rcv_nxt; -}; - -struct cpl_close_listserv_req { - WR_HDR; - union opcode_tid ot; - __u8 rsvd0; - __u8 cpu_idx; - __be16 rsvd1; -}; - -struct cpl_close_listserv_rpl { - RSS_HDR union opcode_tid ot; - __u8 rsvd[3]; - __u8 status; -}; - -struct cpl_abort_req_rss { - RSS_HDR union opcode_tid ot; - __be32 rsvd0; - __u8 rsvd1; - __u8 status; - __u8 rsvd2[6]; -}; - -struct cpl_abort_req { - WR_HDR; - union opcode_tid ot; - __be32 rsvd0; - __u8 rsvd1; - __u8 cmd; - __u8 rsvd2[6]; -}; - -struct cpl_abort_rpl_rss { - RSS_HDR union opcode_tid ot; - __be32 rsvd0; - __u8 rsvd1; - __u8 status; - __u8 rsvd2[6]; -}; - -struct cpl_abort_rpl { - WR_HDR; - union opcode_tid ot; - __be32 rsvd0; - __u8 rsvd1; - __u8 cmd; - __u8 rsvd2[6]; -}; - -struct cpl_peer_close { - RSS_HDR union opcode_tid ot; - __be32 rcv_nxt; -}; - -struct tx_data_wr { - __be32 wr_hi; - __be32 wr_lo; - __be32 len; - __be32 flags; - __be32 sndseq; - __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 -#define V_TX_PORT(x) ((x) << S_TX_PORT) -#define G_TX_PORT(x) (((x) >> S_TX_PORT) & M_TX_PORT) - -#define S_TX_MSS 4 -#define M_TX_MSS 0xF -#define V_TX_MSS(x) ((x) << S_TX_MSS) -#define G_TX_MSS(x) (((x) >> S_TX_MSS) & M_TX_MSS) - -#define S_TX_QOS 8 -#define M_TX_QOS 0xFF -#define V_TX_QOS(x) ((x) << S_TX_QOS) -#define G_TX_QOS(x) (((x) >> S_TX_QOS) & M_TX_QOS) - -#define S_TX_SNDBUF 16 -#define M_TX_SNDBUF 0xFFFF -#define V_TX_SNDBUF(x) ((x) << S_TX_SNDBUF) -#define G_TX_SNDBUF(x) (((x) >> S_TX_SNDBUF) & M_TX_SNDBUF) - -struct cpl_tx_data { - union opcode_tid ot; - __be32 len; - __be32 rsvd; - __be16 urg; - __be16 flags; -}; - -/* cpl_tx_data.flags fields */ -#define S_TX_ULP_SUBMODE 6 -#define M_TX_ULP_SUBMODE 0xF -#define V_TX_ULP_SUBMODE(x) ((x) << S_TX_ULP_SUBMODE) -#define G_TX_ULP_SUBMODE(x) (((x) >> S_TX_ULP_SUBMODE) & M_TX_ULP_SUBMODE) - -#define S_TX_ULP_MODE 10 -#define M_TX_ULP_MODE 0xF -#define V_TX_ULP_MODE(x) ((x) << S_TX_ULP_MODE) -#define G_TX_ULP_MODE(x) (((x) >> S_TX_ULP_MODE) & M_TX_ULP_MODE) - -#define S_TX_SHOVE 14 -#define V_TX_SHOVE(x) ((x) << S_TX_SHOVE) -#define F_TX_SHOVE V_TX_SHOVE(1U) - -#define S_TX_MORE 15 -#define V_TX_MORE(x) ((x) << S_TX_MORE) -#define F_TX_MORE V_TX_MORE(1U) - -/* additional tx_data_wr.flags fields */ -#define S_TX_CPU_IDX 0 -#define M_TX_CPU_IDX 0x3F -#define V_TX_CPU_IDX(x) ((x) << S_TX_CPU_IDX) -#define G_TX_CPU_IDX(x) (((x) >> S_TX_CPU_IDX) & M_TX_CPU_IDX) - -#define S_TX_URG 16 -#define V_TX_URG(x) ((x) << S_TX_URG) -#define F_TX_URG V_TX_URG(1U) - -#define S_TX_CLOSE 17 -#define V_TX_CLOSE(x) ((x) << S_TX_CLOSE) -#define F_TX_CLOSE V_TX_CLOSE(1U) - -#define S_TX_INIT 18 -#define V_TX_INIT(x) ((x) << S_TX_INIT) -#define F_TX_INIT V_TX_INIT(1U) - -#define S_TX_IMM_ACK 19 -#define V_TX_IMM_ACK(x) ((x) << S_TX_IMM_ACK) -#define F_TX_IMM_ACK V_TX_IMM_ACK(1U) - -#define S_TX_IMM_DMA 20 -#define V_TX_IMM_DMA(x) ((x) << S_TX_IMM_DMA) -#define F_TX_IMM_DMA V_TX_IMM_DMA(1U) - -struct cpl_tx_data_ack { - RSS_HDR union opcode_tid ot; - __be32 ack_seq; -}; - -struct cpl_wr_ack { - RSS_HDR union opcode_tid ot; - __be16 credits; - __be16 rsvd; - __be32 snd_nxt; - __be32 snd_una; -}; - -struct cpl_rdma_ec_status { - RSS_HDR union opcode_tid ot; - __u8 rsvd[3]; - __u8 status; -}; - -struct mngt_pktsched_wr { - __be32 wr_hi; - __be32 wr_lo; - __u8 mngt_opcode; - __u8 rsvd[7]; - __u8 sched; - __u8 idx; - __u8 min; - __u8 max; - __u8 binding; - __u8 rsvd1[3]; -}; - -struct cpl_iscsi_hdr { - RSS_HDR union opcode_tid ot; - __be16 pdu_len_ddp; - __be16 len; - __be32 seq; - __be16 urg; - __u8 rsvd; - __u8 status; -}; - -/* cpl_iscsi_hdr.pdu_len_ddp fields */ -#define S_ISCSI_PDU_LEN 0 -#define M_ISCSI_PDU_LEN 0x7FFF -#define V_ISCSI_PDU_LEN(x) ((x) << S_ISCSI_PDU_LEN) -#define G_ISCSI_PDU_LEN(x) (((x) >> S_ISCSI_PDU_LEN) & M_ISCSI_PDU_LEN) - -#define S_ISCSI_DDP 15 -#define V_ISCSI_DDP(x) ((x) << S_ISCSI_DDP) -#define F_ISCSI_DDP V_ISCSI_DDP(1U) - -struct cpl_rx_data { - RSS_HDR union opcode_tid ot; - __be16 rsvd; - __be16 len; - __be32 seq; - __be16 urg; -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8 dack_mode:2; - __u8 psh:1; - __u8 heartbeat:1; - __u8:4; -#else - __u8:4; - __u8 heartbeat:1; - __u8 psh:1; - __u8 dack_mode:2; -#endif - __u8 status; -}; - -struct cpl_rx_data_ack { - WR_HDR; - union opcode_tid ot; - __be32 credit_dack; -}; - -/* cpl_rx_data_ack.ack_seq fields */ -#define S_RX_CREDITS 0 -#define M_RX_CREDITS 0x7FFFFFF -#define V_RX_CREDITS(x) ((x) << S_RX_CREDITS) -#define G_RX_CREDITS(x) (((x) >> S_RX_CREDITS) & M_RX_CREDITS) - -#define S_RX_MODULATE 27 -#define V_RX_MODULATE(x) ((x) << S_RX_MODULATE) -#define F_RX_MODULATE V_RX_MODULATE(1U) - -#define S_RX_FORCE_ACK 28 -#define V_RX_FORCE_ACK(x) ((x) << S_RX_FORCE_ACK) -#define F_RX_FORCE_ACK V_RX_FORCE_ACK(1U) - -#define S_RX_DACK_MODE 29 -#define M_RX_DACK_MODE 0x3 -#define V_RX_DACK_MODE(x) ((x) << S_RX_DACK_MODE) -#define G_RX_DACK_MODE(x) (((x) >> S_RX_DACK_MODE) & M_RX_DACK_MODE) - -#define S_RX_DACK_CHANGE 31 -#define V_RX_DACK_CHANGE(x) ((x) << S_RX_DACK_CHANGE) -#define F_RX_DACK_CHANGE V_RX_DACK_CHANGE(1U) - -struct cpl_rx_urg_notify { - RSS_HDR union opcode_tid ot; - __be32 seq; -}; - -struct cpl_rx_ddp_complete { - RSS_HDR union opcode_tid ot; - __be32 ddp_report; -}; - -struct cpl_rx_data_ddp { - RSS_HDR union opcode_tid ot; - __be16 urg; - __be16 len; - __be32 seq; - union { - __be32 nxt_seq; - __be32 ddp_report; - }; - __be32 ulp_crc; - __be32 ddpvld_status; -}; - -/* cpl_rx_data_ddp.ddpvld_status fields */ -#define S_DDP_STATUS 0 -#define M_DDP_STATUS 0xFF -#define V_DDP_STATUS(x) ((x) << S_DDP_STATUS) -#define G_DDP_STATUS(x) (((x) >> S_DDP_STATUS) & M_DDP_STATUS) - -#define S_DDP_VALID 15 -#define M_DDP_VALID 0x1FFFF -#define V_DDP_VALID(x) ((x) << S_DDP_VALID) -#define G_DDP_VALID(x) (((x) >> S_DDP_VALID) & M_DDP_VALID) - -#define S_DDP_PPOD_MISMATCH 15 -#define V_DDP_PPOD_MISMATCH(x) ((x) << S_DDP_PPOD_MISMATCH) -#define F_DDP_PPOD_MISMATCH V_DDP_PPOD_MISMATCH(1U) - -#define S_DDP_PDU 16 -#define V_DDP_PDU(x) ((x) << S_DDP_PDU) -#define F_DDP_PDU V_DDP_PDU(1U) - -#define S_DDP_LLIMIT_ERR 17 -#define V_DDP_LLIMIT_ERR(x) ((x) << S_DDP_LLIMIT_ERR) -#define F_DDP_LLIMIT_ERR V_DDP_LLIMIT_ERR(1U) - -#define S_DDP_PPOD_PARITY_ERR 18 -#define V_DDP_PPOD_PARITY_ERR(x) ((x) << S_DDP_PPOD_PARITY_ERR) -#define F_DDP_PPOD_PARITY_ERR V_DDP_PPOD_PARITY_ERR(1U) - -#define S_DDP_PADDING_ERR 19 -#define V_DDP_PADDING_ERR(x) ((x) << S_DDP_PADDING_ERR) -#define F_DDP_PADDING_ERR V_DDP_PADDING_ERR(1U) - -#define S_DDP_HDRCRC_ERR 20 -#define V_DDP_HDRCRC_ERR(x) ((x) << S_DDP_HDRCRC_ERR) -#define F_DDP_HDRCRC_ERR V_DDP_HDRCRC_ERR(1U) - -#define S_DDP_DATACRC_ERR 21 -#define V_DDP_DATACRC_ERR(x) ((x) << S_DDP_DATACRC_ERR) -#define F_DDP_DATACRC_ERR V_DDP_DATACRC_ERR(1U) - -#define S_DDP_INVALID_TAG 22 -#define V_DDP_INVALID_TAG(x) ((x) << S_DDP_INVALID_TAG) -#define F_DDP_INVALID_TAG V_DDP_INVALID_TAG(1U) - -#define S_DDP_ULIMIT_ERR 23 -#define V_DDP_ULIMIT_ERR(x) ((x) << S_DDP_ULIMIT_ERR) -#define F_DDP_ULIMIT_ERR V_DDP_ULIMIT_ERR(1U) - -#define S_DDP_OFFSET_ERR 24 -#define V_DDP_OFFSET_ERR(x) ((x) << S_DDP_OFFSET_ERR) -#define F_DDP_OFFSET_ERR V_DDP_OFFSET_ERR(1U) - -#define S_DDP_COLOR_ERR 25 -#define V_DDP_COLOR_ERR(x) ((x) << S_DDP_COLOR_ERR) -#define F_DDP_COLOR_ERR V_DDP_COLOR_ERR(1U) - -#define S_DDP_TID_MISMATCH 26 -#define V_DDP_TID_MISMATCH(x) ((x) << S_DDP_TID_MISMATCH) -#define F_DDP_TID_MISMATCH V_DDP_TID_MISMATCH(1U) - -#define S_DDP_INVALID_PPOD 27 -#define V_DDP_INVALID_PPOD(x) ((x) << S_DDP_INVALID_PPOD) -#define F_DDP_INVALID_PPOD V_DDP_INVALID_PPOD(1U) - -#define S_DDP_ULP_MODE 28 -#define M_DDP_ULP_MODE 0xF -#define V_DDP_ULP_MODE(x) ((x) << S_DDP_ULP_MODE) -#define G_DDP_ULP_MODE(x) (((x) >> S_DDP_ULP_MODE) & M_DDP_ULP_MODE) - -/* cpl_rx_data_ddp.ddp_report fields */ -#define S_DDP_OFFSET 0 -#define M_DDP_OFFSET 0x3FFFFF -#define V_DDP_OFFSET(x) ((x) << S_DDP_OFFSET) -#define G_DDP_OFFSET(x) (((x) >> S_DDP_OFFSET) & M_DDP_OFFSET) - -#define S_DDP_URG 24 -#define V_DDP_URG(x) ((x) << S_DDP_URG) -#define F_DDP_URG V_DDP_URG(1U) - -#define S_DDP_PSH 25 -#define V_DDP_PSH(x) ((x) << S_DDP_PSH) -#define F_DDP_PSH V_DDP_PSH(1U) - -#define S_DDP_BUF_COMPLETE 26 -#define V_DDP_BUF_COMPLETE(x) ((x) << S_DDP_BUF_COMPLETE) -#define F_DDP_BUF_COMPLETE V_DDP_BUF_COMPLETE(1U) - -#define S_DDP_BUF_TIMED_OUT 27 -#define V_DDP_BUF_TIMED_OUT(x) ((x) << S_DDP_BUF_TIMED_OUT) -#define F_DDP_BUF_TIMED_OUT V_DDP_BUF_TIMED_OUT(1U) - -#define S_DDP_BUF_IDX 28 -#define V_DDP_BUF_IDX(x) ((x) << S_DDP_BUF_IDX) -#define F_DDP_BUF_IDX V_DDP_BUF_IDX(1U) - -struct cpl_tx_pkt { - WR_HDR; - __be32 cntrl; - __be32 len; -}; - -struct cpl_tx_pkt_lso { - WR_HDR; - __be32 cntrl; - __be32 len; - - __be32 rsvd; - __be32 lso_info; -}; - -/* cpl_tx_pkt*.cntrl fields */ -#define S_TXPKT_VLAN 0 -#define M_TXPKT_VLAN 0xFFFF -#define V_TXPKT_VLAN(x) ((x) << S_TXPKT_VLAN) -#define G_TXPKT_VLAN(x) (((x) >> S_TXPKT_VLAN) & M_TXPKT_VLAN) - -#define S_TXPKT_INTF 16 -#define M_TXPKT_INTF 0xF -#define V_TXPKT_INTF(x) ((x) << S_TXPKT_INTF) -#define G_TXPKT_INTF(x) (((x) >> S_TXPKT_INTF) & M_TXPKT_INTF) - -#define S_TXPKT_IPCSUM_DIS 20 -#define V_TXPKT_IPCSUM_DIS(x) ((x) << S_TXPKT_IPCSUM_DIS) -#define F_TXPKT_IPCSUM_DIS V_TXPKT_IPCSUM_DIS(1U) - -#define S_TXPKT_L4CSUM_DIS 21 -#define V_TXPKT_L4CSUM_DIS(x) ((x) << S_TXPKT_L4CSUM_DIS) -#define F_TXPKT_L4CSUM_DIS V_TXPKT_L4CSUM_DIS(1U) - -#define S_TXPKT_VLAN_VLD 22 -#define V_TXPKT_VLAN_VLD(x) ((x) << S_TXPKT_VLAN_VLD) -#define F_TXPKT_VLAN_VLD V_TXPKT_VLAN_VLD(1U) - -#define S_TXPKT_LOOPBACK 23 -#define V_TXPKT_LOOPBACK(x) ((x) << S_TXPKT_LOOPBACK) -#define F_TXPKT_LOOPBACK V_TXPKT_LOOPBACK(1U) - -#define S_TXPKT_OPCODE 24 -#define M_TXPKT_OPCODE 0xFF -#define V_TXPKT_OPCODE(x) ((x) << S_TXPKT_OPCODE) -#define G_TXPKT_OPCODE(x) (((x) >> S_TXPKT_OPCODE) & M_TXPKT_OPCODE) - -/* cpl_tx_pkt_lso.lso_info fields */ -#define S_LSO_MSS 0 -#define M_LSO_MSS 0x3FFF -#define V_LSO_MSS(x) ((x) << S_LSO_MSS) -#define G_LSO_MSS(x) (((x) >> S_LSO_MSS) & M_LSO_MSS) - -#define S_LSO_ETH_TYPE 14 -#define M_LSO_ETH_TYPE 0x3 -#define V_LSO_ETH_TYPE(x) ((x) << S_LSO_ETH_TYPE) -#define G_LSO_ETH_TYPE(x) (((x) >> S_LSO_ETH_TYPE) & M_LSO_ETH_TYPE) - -#define S_LSO_TCPHDR_WORDS 16 -#define M_LSO_TCPHDR_WORDS 0xF -#define V_LSO_TCPHDR_WORDS(x) ((x) << S_LSO_TCPHDR_WORDS) -#define G_LSO_TCPHDR_WORDS(x) (((x) >> S_LSO_TCPHDR_WORDS) & M_LSO_TCPHDR_WORDS) - -#define S_LSO_IPHDR_WORDS 20 -#define M_LSO_IPHDR_WORDS 0xF -#define V_LSO_IPHDR_WORDS(x) ((x) << S_LSO_IPHDR_WORDS) -#define G_LSO_IPHDR_WORDS(x) (((x) >> S_LSO_IPHDR_WORDS) & M_LSO_IPHDR_WORDS) - -#define S_LSO_IPV6 24 -#define V_LSO_IPV6(x) ((x) << S_LSO_IPV6) -#define F_LSO_IPV6 V_LSO_IPV6(1U) - -struct cpl_trace_pkt { -#ifdef CHELSIO_FW - __u8 rss_opcode; -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8 err:1; - __u8:7; -#else - __u8:7; - __u8 err:1; -#endif - __u8 rsvd0; -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8 qid:4; - __u8:4; -#else - __u8:4; - __u8 qid:4; -#endif - __be32 tstamp; -#endif /* CHELSIO_FW */ - - __u8 opcode; -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8 iff:4; - __u8:4; -#else - __u8:4; - __u8 iff:4; -#endif - __u8 rsvd[4]; - __be16 len; -}; - -struct cpl_rx_pkt { - RSS_HDR __u8 opcode; -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8 iff:4; - __u8 csum_valid:1; - __u8 ipmi_pkt:1; - __u8 vlan_valid:1; - __u8 fragment:1; -#else - __u8 fragment:1; - __u8 vlan_valid:1; - __u8 ipmi_pkt:1; - __u8 csum_valid:1; - __u8 iff:4; -#endif - __be16 csum; - __be16 vlan; - __be16 len; -}; - -struct cpl_l2t_write_req { - WR_HDR; - union opcode_tid ot; - __be32 params; - __u8 rsvd[2]; - __u8 dst_mac[6]; -}; - -/* cpl_l2t_write_req.params fields */ -#define S_L2T_W_IDX 0 -#define M_L2T_W_IDX 0x7FF -#define V_L2T_W_IDX(x) ((x) << S_L2T_W_IDX) -#define G_L2T_W_IDX(x) (((x) >> S_L2T_W_IDX) & M_L2T_W_IDX) - -#define S_L2T_W_VLAN 11 -#define M_L2T_W_VLAN 0xFFF -#define V_L2T_W_VLAN(x) ((x) << S_L2T_W_VLAN) -#define G_L2T_W_VLAN(x) (((x) >> S_L2T_W_VLAN) & M_L2T_W_VLAN) - -#define S_L2T_W_IFF 23 -#define M_L2T_W_IFF 0xF -#define V_L2T_W_IFF(x) ((x) << S_L2T_W_IFF) -#define G_L2T_W_IFF(x) (((x) >> S_L2T_W_IFF) & M_L2T_W_IFF) - -#define S_L2T_W_PRIO 27 -#define M_L2T_W_PRIO 0x7 -#define V_L2T_W_PRIO(x) ((x) << S_L2T_W_PRIO) -#define G_L2T_W_PRIO(x) (((x) >> S_L2T_W_PRIO) & M_L2T_W_PRIO) - -struct cpl_l2t_write_rpl { - RSS_HDR union opcode_tid ot; - __u8 status; - __u8 rsvd[3]; -}; - -struct cpl_l2t_read_req { - WR_HDR; - union opcode_tid ot; - __be16 rsvd; - __be16 l2t_idx; -}; - -struct cpl_l2t_read_rpl { - RSS_HDR union opcode_tid ot; - __be32 params; - __u8 rsvd[2]; - __u8 dst_mac[6]; -}; - -/* cpl_l2t_read_rpl.params fields */ -#define S_L2T_R_PRIO 0 -#define M_L2T_R_PRIO 0x7 -#define V_L2T_R_PRIO(x) ((x) << S_L2T_R_PRIO) -#define G_L2T_R_PRIO(x) (((x) >> S_L2T_R_PRIO) & M_L2T_R_PRIO) - -#define S_L2T_R_VLAN 8 -#define M_L2T_R_VLAN 0xFFF -#define V_L2T_R_VLAN(x) ((x) << S_L2T_R_VLAN) -#define G_L2T_R_VLAN(x) (((x) >> S_L2T_R_VLAN) & M_L2T_R_VLAN) - -#define S_L2T_R_IFF 20 -#define M_L2T_R_IFF 0xF -#define V_L2T_R_IFF(x) ((x) << S_L2T_R_IFF) -#define G_L2T_R_IFF(x) (((x) >> S_L2T_R_IFF) & M_L2T_R_IFF) - -#define S_L2T_STATUS 24 -#define M_L2T_STATUS 0xFF -#define V_L2T_STATUS(x) ((x) << S_L2T_STATUS) -#define G_L2T_STATUS(x) (((x) >> S_L2T_STATUS) & M_L2T_STATUS) - -struct cpl_smt_write_req { - WR_HDR; - union opcode_tid ot; - __u8 rsvd0; -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8 mtu_idx:4; - __u8 iff:4; -#else - __u8 iff:4; - __u8 mtu_idx:4; -#endif - __be16 rsvd2; - __be16 rsvd3; - __u8 src_mac1[6]; - __be16 rsvd4; - __u8 src_mac0[6]; -}; - -struct cpl_smt_write_rpl { - RSS_HDR union opcode_tid ot; - __u8 status; - __u8 rsvd[3]; -}; - -struct cpl_smt_read_req { - WR_HDR; - union opcode_tid ot; - __u8 rsvd0; -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8:4; - __u8 iff:4; -#else - __u8 iff:4; - __u8:4; -#endif - __be16 rsvd2; -}; - -struct cpl_smt_read_rpl { - RSS_HDR union opcode_tid ot; - __u8 status; -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8 mtu_idx:4; - __u8:4; -#else - __u8:4; - __u8 mtu_idx:4; -#endif - __be16 rsvd2; - __be16 rsvd3; - __u8 src_mac1[6]; - __be16 rsvd4; - __u8 src_mac0[6]; -}; - -struct cpl_rte_delete_req { - WR_HDR; - union opcode_tid ot; - __be32 params; -}; - -/* { cpl_rte_delete_req, cpl_rte_read_req }.params fields */ -#define S_RTE_REQ_LUT_IX 8 -#define M_RTE_REQ_LUT_IX 0x7FF -#define V_RTE_REQ_LUT_IX(x) ((x) << S_RTE_REQ_LUT_IX) -#define G_RTE_REQ_LUT_IX(x) (((x) >> S_RTE_REQ_LUT_IX) & M_RTE_REQ_LUT_IX) - -#define S_RTE_REQ_LUT_BASE 19 -#define M_RTE_REQ_LUT_BASE 0x7FF -#define V_RTE_REQ_LUT_BASE(x) ((x) << S_RTE_REQ_LUT_BASE) -#define G_RTE_REQ_LUT_BASE(x) (((x) >> S_RTE_REQ_LUT_BASE) & M_RTE_REQ_LUT_BASE) - -#define S_RTE_READ_REQ_SELECT 31 -#define V_RTE_READ_REQ_SELECT(x) ((x) << S_RTE_READ_REQ_SELECT) -#define F_RTE_READ_REQ_SELECT V_RTE_READ_REQ_SELECT(1U) - -struct cpl_rte_delete_rpl { - RSS_HDR union opcode_tid ot; - __u8 status; - __u8 rsvd[3]; -}; - -struct cpl_rte_write_req { - WR_HDR; - union opcode_tid ot; -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8:6; - __u8 write_tcam:1; - __u8 write_l2t_lut:1; -#else - __u8 write_l2t_lut:1; - __u8 write_tcam:1; - __u8:6; -#endif - __u8 rsvd[3]; - __be32 lut_params; - __be16 rsvd2; - __be16 l2t_idx; - __be32 netmask; - __be32 faddr; -}; - -/* cpl_rte_write_req.lut_params fields */ -#define S_RTE_WRITE_REQ_LUT_IX 10 -#define M_RTE_WRITE_REQ_LUT_IX 0x7FF -#define V_RTE_WRITE_REQ_LUT_IX(x) ((x) << S_RTE_WRITE_REQ_LUT_IX) -#define G_RTE_WRITE_REQ_LUT_IX(x) (((x) >> S_RTE_WRITE_REQ_LUT_IX) & M_RTE_WRITE_REQ_LUT_IX) - -#define S_RTE_WRITE_REQ_LUT_BASE 21 -#define M_RTE_WRITE_REQ_LUT_BASE 0x7FF -#define V_RTE_WRITE_REQ_LUT_BASE(x) ((x) << S_RTE_WRITE_REQ_LUT_BASE) -#define G_RTE_WRITE_REQ_LUT_BASE(x) (((x) >> S_RTE_WRITE_REQ_LUT_BASE) & M_RTE_WRITE_REQ_LUT_BASE) - -struct cpl_rte_write_rpl { - RSS_HDR union opcode_tid ot; - __u8 status; - __u8 rsvd[3]; -}; - -struct cpl_rte_read_req { - WR_HDR; - union opcode_tid ot; - __be32 params; -}; - -struct cpl_rte_read_rpl { - RSS_HDR union opcode_tid ot; - __u8 status; - __u8 rsvd0; - __be16 l2t_idx; -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8:7; - __u8 select:1; -#else - __u8 select:1; - __u8:7; -#endif - __u8 rsvd2[3]; - __be32 addr; -}; - -struct cpl_tid_release { - WR_HDR; - union opcode_tid ot; - __be32 rsvd; -}; - -struct cpl_barrier { - WR_HDR; - __u8 opcode; - __u8 rsvd[7]; -}; - -struct cpl_rdma_read_req { - __u8 opcode; - __u8 rsvd[15]; -}; - -struct cpl_rdma_terminate { -#ifdef CHELSIO_FW - __u8 opcode; - __u8 rsvd[2]; -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8 rspq:3; - __u8:5; -#else - __u8:5; - __u8 rspq:3; -#endif - __be32 tid_len; -#endif - __be32 msn; - __be32 mo; - __u8 data[0]; -}; - -/* cpl_rdma_terminate.tid_len fields */ -#define S_FLIT_CNT 0 -#define M_FLIT_CNT 0xFF -#define V_FLIT_CNT(x) ((x) << S_FLIT_CNT) -#define G_FLIT_CNT(x) (((x) >> S_FLIT_CNT) & M_FLIT_CNT) - -#define S_TERM_TID 8 -#define M_TERM_TID 0xFFFFF -#define V_TERM_TID(x) ((x) << S_TERM_TID) -#define G_TERM_TID(x) (((x) >> S_TERM_TID) & M_TERM_TID) - -/* ULP_TX opcodes */ -enum { ULP_MEM_READ = 2, ULP_MEM_WRITE = 3, ULP_TXPKT = 4 }; - -#define S_ULPTX_CMD 28 -#define M_ULPTX_CMD 0xF -#define V_ULPTX_CMD(x) ((x) << S_ULPTX_CMD) - -#define S_ULPTX_NFLITS 0 -#define M_ULPTX_NFLITS 0xFF -#define V_ULPTX_NFLITS(x) ((x) << S_ULPTX_NFLITS) - -struct ulp_mem_io { - WR_HDR; - __be32 cmd_lock_addr; - __be32 len; -}; - -/* ulp_mem_io.cmd_lock_addr fields */ -#define S_ULP_MEMIO_ADDR 0 -#define M_ULP_MEMIO_ADDR 0x7FFFFFF -#define V_ULP_MEMIO_ADDR(x) ((x) << S_ULP_MEMIO_ADDR) -#define S_ULP_MEMIO_LOCK 27 -#define V_ULP_MEMIO_LOCK(x) ((x) << S_ULP_MEMIO_LOCK) -#define F_ULP_MEMIO_LOCK V_ULP_MEMIO_LOCK(1U) - -/* ulp_mem_io.len fields */ -#define S_ULP_MEMIO_DATA_LEN 28 -#define M_ULP_MEMIO_DATA_LEN 0xF -#define V_ULP_MEMIO_DATA_LEN(x) ((x) << S_ULP_MEMIO_DATA_LEN) - -#endif /* T3_CPL_H */ diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c deleted file mode 100644 index 44ac2f40b644..000000000000 --- a/drivers/net/cxgb3/t3_hw.c +++ /dev/null @@ -1,3785 +0,0 @@ -/* - * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#include "common.h" -#include "regs.h" -#include "sge_defs.h" -#include "firmware_exports.h" - -static void t3_port_intr_clear(struct adapter *adapter, int idx); - -/** - * t3_wait_op_done_val - wait until an operation is completed - * @adapter: the adapter performing the operation - * @reg: the register to check for completion - * @mask: a single-bit field within @reg that indicates completion - * @polarity: the value of the field when the operation is completed - * @attempts: number of check iterations - * @delay: delay in usecs between iterations - * @valp: where to store the value of the register at completion time - * - * Wait until an operation is completed by checking a bit in a register - * up to @attempts times. If @valp is not NULL the value of the register - * at the time it indicated completion is stored there. Returns 0 if the - * operation completes and -EAGAIN otherwise. - */ - -int t3_wait_op_done_val(struct adapter *adapter, int reg, u32 mask, - int polarity, int attempts, int delay, u32 *valp) -{ - while (1) { - u32 val = t3_read_reg(adapter, reg); - - if (!!(val & mask) == polarity) { - if (valp) - *valp = val; - return 0; - } - if (--attempts == 0) - return -EAGAIN; - if (delay) - udelay(delay); - } -} - -/** - * t3_write_regs - write a bunch of registers - * @adapter: the adapter to program - * @p: an array of register address/register value pairs - * @n: the number of address/value pairs - * @offset: register address offset - * - * Takes an array of register address/register value pairs and writes each - * value to the corresponding register. Register addresses are adjusted - * by the supplied offset. - */ -void t3_write_regs(struct adapter *adapter, const struct addr_val_pair *p, - int n, unsigned int offset) -{ - while (n--) { - t3_write_reg(adapter, p->reg_addr + offset, p->val); - p++; - } -} - -/** - * t3_set_reg_field - set a register field to a value - * @adapter: the adapter to program - * @addr: the register address - * @mask: specifies the portion of the register to modify - * @val: the new value for the register field - * - * Sets a register field specified by the supplied mask to the - * given value. - */ -void t3_set_reg_field(struct adapter *adapter, unsigned int addr, u32 mask, - u32 val) -{ - u32 v = t3_read_reg(adapter, addr) & ~mask; - - t3_write_reg(adapter, addr, v | val); - t3_read_reg(adapter, addr); /* flush */ -} - -/** - * t3_read_indirect - read indirectly addressed registers - * @adap: the adapter - * @addr_reg: register holding the indirect address - * @data_reg: register holding the value of the indirect register - * @vals: where the read register values are stored - * @start_idx: index of first indirect register to read - * @nregs: how many indirect registers to read - * - * Reads registers that are accessed indirectly through an address/data - * register pair. - */ -static void t3_read_indirect(struct adapter *adap, unsigned int addr_reg, - unsigned int data_reg, u32 *vals, - unsigned int nregs, unsigned int start_idx) -{ - while (nregs--) { - t3_write_reg(adap, addr_reg, start_idx); - *vals++ = t3_read_reg(adap, data_reg); - start_idx++; - } -} - -/** - * t3_mc7_bd_read - read from MC7 through backdoor accesses - * @mc7: identifies MC7 to read from - * @start: index of first 64-bit word to read - * @n: number of 64-bit words to read - * @buf: where to store the read result - * - * Read n 64-bit words from MC7 starting at word start, using backdoor - * accesses. - */ -int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n, - u64 *buf) -{ - static const int shift[] = { 0, 0, 16, 24 }; - static const int step[] = { 0, 32, 16, 8 }; - - unsigned int size64 = mc7->size / 8; /* # of 64-bit words */ - struct adapter *adap = mc7->adapter; - - if (start >= size64 || start + n > size64) - return -EINVAL; - - start *= (8 << mc7->width); - while (n--) { - int i; - u64 val64 = 0; - - for (i = (1 << mc7->width) - 1; i >= 0; --i) { - int attempts = 10; - u32 val; - - t3_write_reg(adap, mc7->offset + A_MC7_BD_ADDR, start); - t3_write_reg(adap, mc7->offset + A_MC7_BD_OP, 0); - val = t3_read_reg(adap, mc7->offset + A_MC7_BD_OP); - while ((val & F_BUSY) && attempts--) - val = t3_read_reg(adap, - mc7->offset + A_MC7_BD_OP); - if (val & F_BUSY) - return -EIO; - - val = t3_read_reg(adap, mc7->offset + A_MC7_BD_DATA1); - if (mc7->width == 0) { - val64 = t3_read_reg(adap, - mc7->offset + - A_MC7_BD_DATA0); - val64 |= (u64) val << 32; - } else { - if (mc7->width > 1) - val >>= shift[mc7->width]; - val64 |= (u64) val << (step[mc7->width] * i); - } - start += 8; - } - *buf++ = val64; - } - return 0; -} - -/* - * Initialize MI1. - */ -static void mi1_init(struct adapter *adap, const struct adapter_info *ai) -{ - u32 clkdiv = adap->params.vpd.cclk / (2 * adap->params.vpd.mdc) - 1; - u32 val = F_PREEN | V_CLKDIV(clkdiv); - - t3_write_reg(adap, A_MI1_CFG, val); -} - -#define MDIO_ATTEMPTS 20 - -/* - * MI1 read/write operations for clause 22 PHYs. - */ -static int t3_mi1_read(struct net_device *dev, int phy_addr, int mmd_addr, - u16 reg_addr) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - int ret; - u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr); - - mutex_lock(&adapter->mdio_lock); - t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), V_ST(1)); - 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, 10); - if (!ret) - ret = t3_read_reg(adapter, A_MI1_DATA); - mutex_unlock(&adapter->mdio_lock); - return ret; -} - -static int t3_mi1_write(struct net_device *dev, int phy_addr, int mmd_addr, - u16 reg_addr, u16 val) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - int ret; - u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr); - - mutex_lock(&adapter->mdio_lock); - t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), V_ST(1)); - 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, 10); - mutex_unlock(&adapter->mdio_lock); - return ret; -} - -static const struct mdio_ops mi1_mdio_ops = { - .read = t3_mi1_read, - .write = t3_mi1_write, - .mode_support = MDIO_SUPPORTS_C22 -}; - -/* - * Performs the address cycle for clause 45 PHYs. - * Must be called with the MDIO_LOCK held. - */ -static int mi1_wr_addr(struct adapter *adapter, int phy_addr, int mmd_addr, - int reg_addr) -{ - u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr); - - t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), 0); - 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)); - return t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, - MDIO_ATTEMPTS, 10); -} - -/* - * MI1 read/write operations for indirect-addressed PHYs. - */ -static int mi1_ext_read(struct net_device *dev, int phy_addr, int mmd_addr, - u16 reg_addr) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - int ret; - - mutex_lock(&adapter->mdio_lock); - ret = mi1_wr_addr(adapter, phy_addr, mmd_addr, reg_addr); - 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, 10); - if (!ret) - ret = t3_read_reg(adapter, A_MI1_DATA); - } - mutex_unlock(&adapter->mdio_lock); - return ret; -} - -static int mi1_ext_write(struct net_device *dev, int phy_addr, int mmd_addr, - u16 reg_addr, u16 val) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - int ret; - - mutex_lock(&adapter->mdio_lock); - ret = mi1_wr_addr(adapter, phy_addr, mmd_addr, reg_addr); - 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, 10); - } - mutex_unlock(&adapter->mdio_lock); - return ret; -} - -static const struct mdio_ops mi1_mdio_ext_ops = { - .read = mi1_ext_read, - .write = mi1_ext_write, - .mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22 -}; - -/** - * t3_mdio_change_bits - modify the value of a PHY register - * @phy: the PHY to operate on - * @mmd: the device address - * @reg: the register address - * @clear: what part of the register value to mask off - * @set: what part of the register value to set - * - * Changes the value of a PHY register by applying a mask to its current - * value and ORing the result with a new value. - */ -int t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear, - unsigned int set) -{ - int ret; - unsigned int val; - - ret = t3_mdio_read(phy, mmd, reg, &val); - if (!ret) { - val &= ~clear; - ret = t3_mdio_write(phy, mmd, reg, val | set); - } - return ret; -} - -/** - * t3_phy_reset - reset a PHY block - * @phy: the PHY to operate on - * @mmd: the device address of the PHY block to reset - * @wait: how long to wait for the reset to complete in 1ms increments - * - * Resets a PHY block and optionally waits for the reset to complete. - * @mmd should be 0 for 10/100/1000 PHYs and the device address to reset - * for 10G PHYs. - */ -int t3_phy_reset(struct cphy *phy, int mmd, int wait) -{ - int err; - unsigned int ctl; - - err = t3_mdio_change_bits(phy, mmd, MDIO_CTRL1, MDIO_CTRL1_LPOWER, - MDIO_CTRL1_RESET); - if (err || !wait) - return err; - - do { - err = t3_mdio_read(phy, mmd, MDIO_CTRL1, &ctl); - if (err) - return err; - ctl &= MDIO_CTRL1_RESET; - if (ctl) - msleep(1); - } while (ctl && --wait); - - return ctl ? -1 : 0; -} - -/** - * t3_phy_advertise - set the PHY advertisement registers for autoneg - * @phy: the PHY to operate on - * @advert: bitmap of capabilities the PHY should advertise - * - * Sets a 10/100/1000 PHY's advertisement registers to advertise the - * requested capabilities. - */ -int t3_phy_advertise(struct cphy *phy, unsigned int advert) -{ - int err; - unsigned int val = 0; - - err = t3_mdio_read(phy, MDIO_DEVAD_NONE, MII_CTRL1000, &val); - if (err) - return err; - - val &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); - if (advert & ADVERTISED_1000baseT_Half) - val |= ADVERTISE_1000HALF; - if (advert & ADVERTISED_1000baseT_Full) - val |= ADVERTISE_1000FULL; - - err = t3_mdio_write(phy, MDIO_DEVAD_NONE, MII_CTRL1000, val); - if (err) - return err; - - val = 1; - if (advert & ADVERTISED_10baseT_Half) - val |= ADVERTISE_10HALF; - if (advert & ADVERTISED_10baseT_Full) - val |= ADVERTISE_10FULL; - if (advert & ADVERTISED_100baseT_Half) - val |= ADVERTISE_100HALF; - if (advert & ADVERTISED_100baseT_Full) - val |= ADVERTISE_100FULL; - if (advert & ADVERTISED_Pause) - val |= ADVERTISE_PAUSE_CAP; - if (advert & ADVERTISED_Asym_Pause) - val |= ADVERTISE_PAUSE_ASYM; - return t3_mdio_write(phy, MDIO_DEVAD_NONE, MII_ADVERTISE, val); -} - -/** - * t3_phy_advertise_fiber - set fiber PHY advertisement register - * @phy: the PHY to operate on - * @advert: bitmap of capabilities the PHY should advertise - * - * Sets a fiber PHY's advertisement register to advertise the - * requested capabilities. - */ -int t3_phy_advertise_fiber(struct cphy *phy, unsigned int advert) -{ - unsigned int val = 0; - - if (advert & ADVERTISED_1000baseT_Half) - val |= ADVERTISE_1000XHALF; - if (advert & ADVERTISED_1000baseT_Full) - val |= ADVERTISE_1000XFULL; - if (advert & ADVERTISED_Pause) - val |= ADVERTISE_1000XPAUSE; - if (advert & ADVERTISED_Asym_Pause) - val |= ADVERTISE_1000XPSE_ASYM; - return t3_mdio_write(phy, MDIO_DEVAD_NONE, MII_ADVERTISE, val); -} - -/** - * t3_set_phy_speed_duplex - force PHY speed and duplex - * @phy: the PHY to operate on - * @speed: requested PHY speed - * @duplex: requested PHY duplex - * - * Force a 10/100/1000 PHY's speed and duplex. This also disables - * auto-negotiation except for GigE, where auto-negotiation is mandatory. - */ -int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex) -{ - int err; - unsigned int ctl; - - err = t3_mdio_read(phy, MDIO_DEVAD_NONE, MII_BMCR, &ctl); - if (err) - return err; - - if (speed >= 0) { - ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); - if (speed == SPEED_100) - ctl |= BMCR_SPEED100; - else if (speed == SPEED_1000) - ctl |= BMCR_SPEED1000; - } - if (duplex >= 0) { - ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE); - if (duplex == DUPLEX_FULL) - ctl |= BMCR_FULLDPLX; - } - if (ctl & BMCR_SPEED1000) /* auto-negotiation required for GigE */ - ctl |= BMCR_ANENABLE; - return t3_mdio_write(phy, MDIO_DEVAD_NONE, MII_BMCR, ctl); -} - -int t3_phy_lasi_intr_enable(struct cphy *phy) -{ - return t3_mdio_write(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, - MDIO_PMA_LASI_LSALARM); -} - -int t3_phy_lasi_intr_disable(struct cphy *phy) -{ - return t3_mdio_write(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, 0); -} - -int t3_phy_lasi_intr_clear(struct cphy *phy) -{ - u32 val; - - return t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT, &val); -} - -int t3_phy_lasi_intr_handler(struct cphy *phy) -{ - unsigned int status; - int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT, - &status); - - if (err) - return err; - return (status & MDIO_PMA_LASI_LSALARM) ? cphy_cause_link_change : 0; -} - -static const struct adapter_info t3_adap_info[] = { - {1, 1, 0, - F_GPIO2_OEN | F_GPIO4_OEN | - F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, { S_GPIO3, S_GPIO5 }, 0, - &mi1_mdio_ops, "Chelsio PE9000"}, - {1, 1, 0, - F_GPIO2_OEN | F_GPIO4_OEN | - F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, { S_GPIO3, S_GPIO5 }, 0, - &mi1_mdio_ops, "Chelsio T302"}, - {1, 0, 0, - F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN | - F_GPIO11_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"}, - {1, 1, 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, - { S_GPIO9, S_GPIO3 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, - &mi1_mdio_ext_ops, "Chelsio T320"}, - {}, - {}, - {1, 0, 0, - F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO6_OEN | F_GPIO7_OEN | - F_GPIO10_OEN | F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, - { S_GPIO9 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, - &mi1_mdio_ext_ops, "Chelsio T310" }, - {1, 0, 0, - F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | - F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL, - { S_GPIO9 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, - &mi1_mdio_ext_ops, "Chelsio N320E-G2" }, -}; - -/* - * Return the adapter_info structure with a given index. Out-of-range indices - * return NULL. - */ -const struct adapter_info *t3_get_adapter_info(unsigned int id) -{ - return id < ARRAY_SIZE(t3_adap_info) ? &t3_adap_info[id] : NULL; -} - -struct port_type_info { - int (*phy_prep)(struct cphy *phy, struct adapter *adapter, - int phy_addr, const struct mdio_ops *ops); -}; - -static const struct port_type_info port_types[] = { - { NULL }, - { t3_ael1002_phy_prep }, - { t3_vsc8211_phy_prep }, - { NULL}, - { t3_xaui_direct_phy_prep }, - { t3_ael2005_phy_prep }, - { t3_qt2045_phy_prep }, - { t3_ael1006_phy_prep }, - { NULL }, - { t3_aq100x_phy_prep }, - { t3_ael2020_phy_prep }, -}; - -#define VPD_ENTRY(name, len) \ - u8 name##_kword[2]; u8 name##_len; u8 name##_data[len] - -/* - * Partial EEPROM Vital Product Data structure. Includes only the ID and - * VPD-R sections. - */ -struct t3_vpd { - u8 id_tag; - u8 id_len[2]; - u8 id_data[16]; - u8 vpdr_tag; - u8 vpdr_len[2]; - VPD_ENTRY(pn, 16); /* part number */ - VPD_ENTRY(ec, 16); /* EC level */ - VPD_ENTRY(sn, SERNUM_LEN); /* serial number */ - VPD_ENTRY(na, 12); /* MAC address base */ - VPD_ENTRY(cclk, 6); /* core clock */ - VPD_ENTRY(mclk, 6); /* mem clock */ - VPD_ENTRY(uclk, 6); /* uP clk */ - VPD_ENTRY(mdc, 6); /* MDIO clk */ - VPD_ENTRY(mt, 2); /* mem timing */ - VPD_ENTRY(xaui0cfg, 6); /* XAUI0 config */ - VPD_ENTRY(xaui1cfg, 6); /* XAUI1 config */ - VPD_ENTRY(port0, 2); /* PHY0 complex */ - VPD_ENTRY(port1, 2); /* PHY1 complex */ - VPD_ENTRY(port2, 2); /* PHY2 complex */ - VPD_ENTRY(port3, 2); /* PHY3 complex */ - VPD_ENTRY(rv, 1); /* csum */ - u32 pad; /* for multiple-of-4 sizing and alignment */ -}; - -#define EEPROM_MAX_POLL 40 -#define EEPROM_STAT_ADDR 0x4000 -#define VPD_BASE 0xc00 - -/** - * t3_seeprom_read - read a VPD EEPROM location - * @adapter: adapter to read - * @addr: EEPROM address - * @data: where to store the read data - * - * Read a 32-bit word from a location in VPD EEPROM using the card's PCI - * VPD ROM capability. A zero is written to the flag bit when the - * address is written to the control register. The hardware device will - * set the flag to 1 when 4 bytes have been read into the data register. - */ -int t3_seeprom_read(struct adapter *adapter, u32 addr, __le32 *data) -{ - u16 val; - int attempts = EEPROM_MAX_POLL; - u32 v; - unsigned int base = adapter->params.pci.vpd_cap_addr; - - if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3)) - return -EINVAL; - - pci_write_config_word(adapter->pdev, base + PCI_VPD_ADDR, addr); - do { - udelay(10); - pci_read_config_word(adapter->pdev, base + PCI_VPD_ADDR, &val); - } while (!(val & PCI_VPD_ADDR_F) && --attempts); - - if (!(val & PCI_VPD_ADDR_F)) { - CH_ERR(adapter, "reading EEPROM address 0x%x failed\n", addr); - return -EIO; - } - pci_read_config_dword(adapter->pdev, base + PCI_VPD_DATA, &v); - *data = cpu_to_le32(v); - return 0; -} - -/** - * t3_seeprom_write - write a VPD EEPROM location - * @adapter: adapter to write - * @addr: EEPROM address - * @data: value to write - * - * Write a 32-bit word to a location in VPD EEPROM using the card's PCI - * VPD ROM capability. - */ -int t3_seeprom_write(struct adapter *adapter, u32 addr, __le32 data) -{ - u16 val; - int attempts = EEPROM_MAX_POLL; - unsigned int base = adapter->params.pci.vpd_cap_addr; - - if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3)) - return -EINVAL; - - pci_write_config_dword(adapter->pdev, base + PCI_VPD_DATA, - le32_to_cpu(data)); - pci_write_config_word(adapter->pdev,base + PCI_VPD_ADDR, - addr | PCI_VPD_ADDR_F); - do { - msleep(1); - pci_read_config_word(adapter->pdev, base + PCI_VPD_ADDR, &val); - } while ((val & PCI_VPD_ADDR_F) && --attempts); - - if (val & PCI_VPD_ADDR_F) { - CH_ERR(adapter, "write to EEPROM address 0x%x failed\n", addr); - return -EIO; - } - return 0; -} - -/** - * t3_seeprom_wp - enable/disable EEPROM write protection - * @adapter: the adapter - * @enable: 1 to enable write protection, 0 to disable it - * - * Enables or disables write protection on the serial EEPROM. - */ -int t3_seeprom_wp(struct adapter *adapter, int enable) -{ - return t3_seeprom_write(adapter, EEPROM_STAT_ADDR, enable ? 0xc : 0); -} - -/** - * get_vpd_params - read VPD parameters from VPD EEPROM - * @adapter: adapter to read - * @p: where to store the parameters - * - * Reads card parameters stored in VPD EEPROM. - */ -static int get_vpd_params(struct adapter *adapter, struct vpd_params *p) -{ - int i, addr, ret; - struct t3_vpd vpd; - - /* - * Card information is normally at VPD_BASE but some early cards had - * it at 0. - */ - ret = t3_seeprom_read(adapter, VPD_BASE, (__le32 *)&vpd); - if (ret) - return ret; - addr = vpd.id_tag == 0x82 ? VPD_BASE : 0; - - for (i = 0; i < sizeof(vpd); i += 4) { - ret = t3_seeprom_read(adapter, addr + i, - (__le32 *)((u8 *)&vpd + i)); - if (ret) - return ret; - } - - 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); - memcpy(p->sn, vpd.sn_data, SERNUM_LEN); - - /* Old eeproms didn't have port information */ - if (adapter->params.rev == 0 && !vpd.port0_data[0]) { - p->port_type[0] = uses_xaui(adapter) ? 1 : 2; - p->port_type[1] = uses_xaui(adapter) ? 6 : 2; - } else { - p->port_type[0] = hex_to_bin(vpd.port0_data[0]); - p->port_type[1] = hex_to_bin(vpd.port1_data[0]); - 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++) - p->eth_base[i] = hex_to_bin(vpd.na_data[2 * i]) * 16 + - hex_to_bin(vpd.na_data[2 * i + 1]); - return 0; -} - -/* serial flash and firmware constants */ -enum { - SF_ATTEMPTS = 5, /* max retries for SF1 operations */ - SF_SEC_SIZE = 64 * 1024, /* serial flash sector size */ - SF_SIZE = SF_SEC_SIZE * 8, /* serial flash size */ - - /* flash command opcodes */ - SF_PROG_PAGE = 2, /* program page */ - SF_WR_DISABLE = 4, /* disable writes */ - SF_RD_STATUS = 5, /* read status register */ - SF_WR_ENABLE = 6, /* enable writes */ - SF_RD_DATA_FAST = 0xb, /* read flash */ - SF_ERASE_SECTOR = 0xd8, /* erase sector */ - - FW_FLASH_BOOT_ADDR = 0x70000, /* start address of FW in flash */ - FW_VERS_ADDR = 0x7fffc, /* flash address holding FW version */ - FW_MIN_SIZE = 8 /* at least version and csum */ -}; - -/** - * sf1_read - read data from the serial flash - * @adapter: the adapter - * @byte_cnt: number of bytes to read - * @cont: whether another operation will be chained - * @valp: where to store the read data - * - * Reads up to 4 bytes of data from the serial flash. The location of - * the read needs to be specified prior to calling this by issuing the - * appropriate commands to the serial flash. - */ -static int sf1_read(struct adapter *adapter, unsigned int byte_cnt, int cont, - u32 *valp) -{ - int ret; - - if (!byte_cnt || byte_cnt > 4) - return -EINVAL; - if (t3_read_reg(adapter, A_SF_OP) & F_BUSY) - return -EBUSY; - t3_write_reg(adapter, A_SF_OP, V_CONT(cont) | V_BYTECNT(byte_cnt - 1)); - ret = t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10); - if (!ret) - *valp = t3_read_reg(adapter, A_SF_DATA); - return ret; -} - -/** - * sf1_write - write data to the serial flash - * @adapter: the adapter - * @byte_cnt: number of bytes to write - * @cont: whether another operation will be chained - * @val: value to write - * - * Writes up to 4 bytes of data to the serial flash. The location of - * the write needs to be specified prior to calling this by issuing the - * appropriate commands to the serial flash. - */ -static int sf1_write(struct adapter *adapter, unsigned int byte_cnt, int cont, - u32 val) -{ - if (!byte_cnt || byte_cnt > 4) - return -EINVAL; - if (t3_read_reg(adapter, A_SF_OP) & F_BUSY) - return -EBUSY; - t3_write_reg(adapter, A_SF_DATA, val); - t3_write_reg(adapter, A_SF_OP, - V_CONT(cont) | V_BYTECNT(byte_cnt - 1) | V_OP(1)); - return t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10); -} - -/** - * flash_wait_op - wait for a flash operation to complete - * @adapter: the adapter - * @attempts: max number of polls of the status register - * @delay: delay between polls in ms - * - * Wait for a flash operation to complete by polling the status register. - */ -static int flash_wait_op(struct adapter *adapter, int attempts, int delay) -{ - int ret; - u32 status; - - while (1) { - if ((ret = sf1_write(adapter, 1, 1, SF_RD_STATUS)) != 0 || - (ret = sf1_read(adapter, 1, 0, &status)) != 0) - return ret; - if (!(status & 1)) - return 0; - if (--attempts == 0) - return -EAGAIN; - if (delay) - msleep(delay); - } -} - -/** - * t3_read_flash - read words from serial flash - * @adapter: the adapter - * @addr: the start address for the read - * @nwords: how many 32-bit words to read - * @data: where to store the read data - * @byte_oriented: whether to store data as bytes or as words - * - * Read the specified number of 32-bit words from the serial flash. - * If @byte_oriented is set the read data is stored as a byte array - * (i.e., big-endian), otherwise as 32-bit words in the platform's - * natural endianess. - */ -static int t3_read_flash(struct adapter *adapter, unsigned int addr, - unsigned int nwords, u32 *data, int byte_oriented) -{ - int ret; - - if (addr + nwords * sizeof(u32) > SF_SIZE || (addr & 3)) - return -EINVAL; - - addr = swab32(addr) | SF_RD_DATA_FAST; - - if ((ret = sf1_write(adapter, 4, 1, addr)) != 0 || - (ret = sf1_read(adapter, 1, 1, data)) != 0) - return ret; - - for (; nwords; nwords--, data++) { - ret = sf1_read(adapter, 4, nwords > 1, data); - if (ret) - return ret; - if (byte_oriented) - *data = htonl(*data); - } - return 0; -} - -/** - * t3_write_flash - write up to a page of data to the serial flash - * @adapter: the adapter - * @addr: the start address to write - * @n: length of data to write - * @data: the data to write - * - * Writes up to a page of data (256 bytes) to the serial flash starting - * at the given address. - */ -static int t3_write_flash(struct adapter *adapter, unsigned int addr, - unsigned int n, const u8 *data) -{ - int ret; - u32 buf[64]; - unsigned int i, c, left, val, offset = addr & 0xff; - - if (addr + n > SF_SIZE || offset + n > 256) - return -EINVAL; - - val = swab32(addr) | SF_PROG_PAGE; - - if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 || - (ret = sf1_write(adapter, 4, 1, val)) != 0) - return ret; - - for (left = n; left; left -= c) { - c = min(left, 4U); - for (val = 0, i = 0; i < c; ++i) - val = (val << 8) + *data++; - - ret = sf1_write(adapter, c, c != left, val); - if (ret) - return ret; - } - if ((ret = flash_wait_op(adapter, 5, 1)) != 0) - return ret; - - /* Read the page to verify the write succeeded */ - ret = t3_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf, 1); - if (ret) - return ret; - - if (memcmp(data - n, (u8 *) buf + offset, n)) - return -EIO; - return 0; -} - -/** - * 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(struct adapter *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 flash. - */ -int t3_check_tpsram_version(struct adapter *adapter) -{ - int ret; - u32 vers; - unsigned int major, minor; - - if (adapter->params.rev == T3_REV_A) - return 0; - - - ret = t3_get_tp_version(adapter, &vers); - if (ret) - return ret; - - major = G_TP_VERSION_MAJOR(vers); - minor = G_TP_VERSION_MINOR(vers); - - if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR) - return 0; - else { - CH_ERR(adapter, "found wrong TP version (%u.%u), " - "driver compiled for version %d.%d\n", major, minor, - TP_VERSION_MAJOR, TP_VERSION_MINOR); - } - 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(struct adapter *adapter, const u8 *tp_sram, - unsigned int size) -{ - u32 csum; - unsigned int i; - const __be32 *p = (const __be32 *)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 -}; - -/** - * t3_get_fw_version - read the firmware version - * @adapter: the adapter - * @vers: where to place the version - * - * Reads the FW version from flash. - */ -int t3_get_fw_version(struct adapter *adapter, u32 *vers) -{ - return t3_read_flash(adapter, FW_VERS_ADDR, 1, vers, 0); -} - -/** - * t3_check_fw_version - check if the FW is compatible with this driver - * @adapter: the adapter - * - * Checks if an adapter's FW is compatible with the driver. Returns 0 - * if the versions are compatible, a negative error otherwise. - */ -int t3_check_fw_version(struct adapter *adapter) -{ - int ret; - u32 vers; - unsigned int type, major, minor; - - ret = t3_get_fw_version(adapter, &vers); - if (ret) - return ret; - - type = G_FW_VERSION_TYPE(vers); - major = G_FW_VERSION_MAJOR(vers); - minor = G_FW_VERSION_MINOR(vers); - - if (type == FW_VERSION_T3 && major == FW_VERSION_MAJOR && - minor == FW_VERSION_MINOR) - return 0; - else if (major != FW_VERSION_MAJOR || minor < FW_VERSION_MINOR) - CH_WARN(adapter, "found old FW minor version(%u.%u), " - "driver compiled for version %u.%u\n", major, minor, - FW_VERSION_MAJOR, FW_VERSION_MINOR); - else { - CH_WARN(adapter, "found newer FW version(%u.%u), " - "driver compiled for version %u.%u\n", major, minor, - FW_VERSION_MAJOR, FW_VERSION_MINOR); - return 0; - } - return -EINVAL; -} - -/** - * t3_flash_erase_sectors - erase a range of flash sectors - * @adapter: the adapter - * @start: the first sector to erase - * @end: the last sector to erase - * - * Erases the sectors in the given range. - */ -static int t3_flash_erase_sectors(struct adapter *adapter, int start, int end) -{ - while (start <= end) { - int ret; - - if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 || - (ret = sf1_write(adapter, 4, 0, - SF_ERASE_SECTOR | (start << 8))) != 0 || - (ret = flash_wait_op(adapter, 5, 500)) != 0) - return ret; - start++; - } - return 0; -} - -/* - * t3_load_fw - download firmware - * @adapter: the adapter - * @fw_data: the firmware image to write - * @size: image size - * - * Write the supplied firmware image to the card's serial flash. - * The FW image has the following sections: @size - 8 bytes of code and - * data, followed by 4 bytes of FW version, followed by the 32-bit - * 1's complement checksum of the whole image. - */ -int t3_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size) -{ - u32 csum; - unsigned int i; - const __be32 *p = (const __be32 *)fw_data; - int ret, addr, fw_sector = FW_FLASH_BOOT_ADDR >> 16; - - if ((size & 3) || size < FW_MIN_SIZE) - return -EINVAL; - if (size > FW_VERS_ADDR + 8 - FW_FLASH_BOOT_ADDR) - return -EFBIG; - - for (csum = 0, i = 0; i < size / sizeof(csum); i++) - csum += ntohl(p[i]); - if (csum != 0xffffffff) { - CH_ERR(adapter, "corrupted firmware image, checksum %u\n", - csum); - return -EINVAL; - } - - ret = t3_flash_erase_sectors(adapter, fw_sector, fw_sector); - if (ret) - goto out; - - size -= 8; /* trim off version and checksum */ - for (addr = FW_FLASH_BOOT_ADDR; size;) { - unsigned int chunk_size = min(size, 256U); - - ret = t3_write_flash(adapter, addr, chunk_size, fw_data); - if (ret) - goto out; - - addr += chunk_size; - fw_data += chunk_size; - size -= chunk_size; - } - - ret = t3_write_flash(adapter, FW_VERS_ADDR, 4, fw_data); -out: - if (ret) - CH_ERR(adapter, "firmware download failed, error %d\n", ret); - return ret; -} - -#define CIM_CTL_BASE 0x2000 - -/** - * t3_cim_ctl_blk_read - read a block from CIM control region - * - * @adap: the adapter - * @addr: the start address within the CIM control region - * @n: number of words to read - * @valp: where to store the result - * - * Reads a block of 4-byte words from the CIM control region. - */ -int t3_cim_ctl_blk_read(struct adapter *adap, unsigned int addr, - unsigned int n, unsigned int *valp) -{ - int ret = 0; - - if (t3_read_reg(adap, A_CIM_HOST_ACC_CTRL) & F_HOSTBUSY) - return -EBUSY; - - for ( ; !ret && n--; addr += 4) { - t3_write_reg(adap, A_CIM_HOST_ACC_CTRL, CIM_CTL_BASE + addr); - ret = t3_wait_op_done(adap, A_CIM_HOST_ACC_CTRL, F_HOSTBUSY, - 0, 5, 2); - if (!ret) - *valp++ = t3_read_reg(adap, A_CIM_HOST_ACC_DATA); - } - return ret; -} - -static void t3_gate_rx_traffic(struct cmac *mac, u32 *rx_cfg, - u32 *rx_hash_high, u32 *rx_hash_low) -{ - /* stop Rx unicast traffic */ - t3_mac_disable_exact_filters(mac); - - /* stop broadcast, multicast, promiscuous mode traffic */ - *rx_cfg = t3_read_reg(mac->adapter, A_XGM_RX_CFG); - t3_set_reg_field(mac->adapter, A_XGM_RX_CFG, - F_ENHASHMCAST | F_DISBCAST | F_COPYALLFRAMES, - F_DISBCAST); - - *rx_hash_high = t3_read_reg(mac->adapter, A_XGM_RX_HASH_HIGH); - t3_write_reg(mac->adapter, A_XGM_RX_HASH_HIGH, 0); - - *rx_hash_low = t3_read_reg(mac->adapter, A_XGM_RX_HASH_LOW); - t3_write_reg(mac->adapter, A_XGM_RX_HASH_LOW, 0); - - /* Leave time to drain max RX fifo */ - msleep(1); -} - -static void t3_open_rx_traffic(struct cmac *mac, u32 rx_cfg, - u32 rx_hash_high, u32 rx_hash_low) -{ - t3_mac_enable_exact_filters(mac); - t3_set_reg_field(mac->adapter, A_XGM_RX_CFG, - F_ENHASHMCAST | F_DISBCAST | F_COPYALLFRAMES, - rx_cfg); - t3_write_reg(mac->adapter, A_XGM_RX_HASH_HIGH, rx_hash_high); - t3_write_reg(mac->adapter, A_XGM_RX_HASH_LOW, rx_hash_low); -} - -/** - * t3_link_changed - handle interface link changes - * @adapter: the adapter - * @port_id: the port index that changed link state - * - * Called when a port's link settings change to propagate the new values - * to the associated PHY and MAC. After performing the common tasks it - * invokes an OS-specific handler. - */ -void t3_link_changed(struct adapter *adapter, int port_id) -{ - int link_ok, speed, duplex, fc; - 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); - - if (!lc->link_ok && link_ok) { - u32 rx_cfg, rx_hash_high, rx_hash_low; - u32 status; - - t3_xgm_intr_enable(adapter, port_id); - t3_gate_rx_traffic(mac, &rx_cfg, &rx_hash_high, &rx_hash_low); - t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, 0); - t3_mac_enable(mac, MAC_DIRECTION_RX); - - status = t3_read_reg(adapter, A_XGM_INT_STATUS + mac->offset); - if (status & F_LINKFAULTCHANGE) { - mac->stats.link_faults++; - pi->link_fault = 1; - } - t3_open_rx_traffic(mac, rx_cfg, rx_hash_high, rx_hash_low); - } - - if (lc->requested_fc & PAUSE_AUTONEG) - fc &= lc->requested_fc; - else - fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); - - if (link_ok == lc->link_ok && speed == lc->speed && - duplex == lc->duplex && fc == lc->fc) - return; /* nothing changed */ - - if (link_ok != lc->link_ok && adapter->params.rev > 0 && - uses_xaui(adapter)) { - if (link_ok) - t3b_pcs_reset(mac); - t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset, - link_ok ? F_TXACTENABLE | F_RXEN : 0); - } - lc->link_ok = link_ok; - lc->speed = speed < 0 ? SPEED_INVALID : speed; - lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex; - - if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE) { - /* Set MAC speed, duplex, and flow control to match PHY. */ - t3_mac_set_speed_duplex_fc(mac, speed, duplex, fc); - lc->fc = fc; - } - - t3_os_link_changed(adapter, port_id, link_ok && !pi->link_fault, - speed, duplex, fc); -} - -void t3_link_fault(struct adapter *adapter, int port_id) -{ - struct port_info *pi = adap2pinfo(adapter, port_id); - struct cmac *mac = &pi->mac; - struct cphy *phy = &pi->phy; - struct link_config *lc = &pi->link_config; - int link_ok, speed, duplex, fc, link_fault; - u32 rx_cfg, rx_hash_high, rx_hash_low; - - t3_gate_rx_traffic(mac, &rx_cfg, &rx_hash_high, &rx_hash_low); - - if (adapter->params.rev > 0 && uses_xaui(adapter)) - t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset, 0); - - t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, 0); - t3_mac_enable(mac, MAC_DIRECTION_RX); - - t3_open_rx_traffic(mac, rx_cfg, rx_hash_high, rx_hash_low); - - link_fault = t3_read_reg(adapter, - A_XGM_INT_STATUS + mac->offset); - link_fault &= F_LINKFAULTCHANGE; - - link_ok = lc->link_ok; - speed = lc->speed; - duplex = lc->duplex; - fc = lc->fc; - - phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc); - - if (link_fault) { - lc->link_ok = 0; - lc->speed = SPEED_INVALID; - lc->duplex = DUPLEX_INVALID; - - t3_os_link_fault(adapter, port_id, 0); - - /* Account link faults only when the phy reports a link up */ - if (link_ok) - mac->stats.link_faults++; - } else { - if (link_ok) - t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset, - F_TXACTENABLE | F_RXEN); - - pi->link_fault = 0; - lc->link_ok = (unsigned char)link_ok; - lc->speed = speed < 0 ? SPEED_INVALID : speed; - lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex; - t3_os_link_fault(adapter, port_id, link_ok); - } -} - -/** - * t3_link_start - apply link configuration to MAC/PHY - * @phy: the PHY to setup - * @mac: the MAC to setup - * @lc: the requested link configuration - * - * Set up a port's MAC and PHY according to a desired link configuration. - * - If the PHY can auto-negotiate first decide what to advertise, then - * enable/disable auto-negotiation as desired, and reset. - * - If the PHY does not auto-negotiate just reset it. - * - If auto-negotiation is off set the MAC to the proper speed/duplex/FC, - * otherwise do it later based on the outcome of auto-negotiation. - */ -int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc) -{ - unsigned int fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); - - lc->link_ok = 0; - if (lc->supported & SUPPORTED_Autoneg) { - lc->advertising &= ~(ADVERTISED_Asym_Pause | ADVERTISED_Pause); - if (fc) { - lc->advertising |= ADVERTISED_Asym_Pause; - if (fc & PAUSE_RX) - lc->advertising |= ADVERTISED_Pause; - } - phy->ops->advertise(phy, lc->advertising); - - if (lc->autoneg == AUTONEG_DISABLE) { - lc->speed = lc->requested_speed; - lc->duplex = lc->requested_duplex; - lc->fc = (unsigned char)fc; - t3_mac_set_speed_duplex_fc(mac, lc->speed, lc->duplex, - fc); - /* Also disables autoneg */ - phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex); - } else - phy->ops->autoneg_enable(phy); - } else { - t3_mac_set_speed_duplex_fc(mac, -1, -1, fc); - lc->fc = (unsigned char)fc; - phy->ops->reset(phy, 0); - } - return 0; -} - -/** - * t3_set_vlan_accel - control HW VLAN extraction - * @adapter: the adapter - * @ports: bitmap of adapter ports to operate on - * @on: enable (1) or disable (0) HW VLAN extraction - * - * Enables or disables HW extraction of VLAN tags for the given port. - */ -void t3_set_vlan_accel(struct adapter *adapter, unsigned int ports, int on) -{ - t3_set_reg_field(adapter, A_TP_OUT_CONFIG, - ports << S_VLANEXTRACTIONENABLE, - on ? (ports << S_VLANEXTRACTIONENABLE) : 0); -} - -struct intr_info { - unsigned int mask; /* bits to check in interrupt status */ - const char *msg; /* message to print or NULL */ - short stat_idx; /* stat counter to increment or -1 */ - unsigned short fatal; /* whether the condition reported is fatal */ -}; - -/** - * t3_handle_intr_status - table driven interrupt handler - * @adapter: the adapter that generated the interrupt - * @reg: the interrupt status register to process - * @mask: a mask to apply to the interrupt status - * @acts: table of interrupt actions - * @stats: statistics counters tracking interrupt occurrences - * - * A table driven interrupt handler that applies a set of masks to an - * interrupt status word and performs the corresponding actions if the - * interrupts described by the mask have occurred. The actions include - * optionally printing a warning or alert message, and optionally - * incrementing a stat counter. The table is terminated by an entry - * specifying mask 0. Returns the number of fatal interrupt conditions. - */ -static int t3_handle_intr_status(struct adapter *adapter, unsigned int reg, - unsigned int mask, - const struct intr_info *acts, - unsigned long *stats) -{ - int fatal = 0; - unsigned int status = t3_read_reg(adapter, reg) & mask; - - for (; acts->mask; ++acts) { - if (!(status & acts->mask)) - continue; - if (acts->fatal) { - fatal++; - CH_ALERT(adapter, "%s (0x%x)\n", - acts->msg, status & acts->mask); - status &= ~acts->mask; - } else if (acts->msg) - CH_WARN(adapter, "%s (0x%x)\n", - acts->msg, status & acts->mask); - if (acts->stat_idx >= 0) - stats[acts->stat_idx]++; - } - if (status) /* clear processed interrupts */ - t3_write_reg(adapter, reg, status); - return fatal; -} - -#define SGE_INTR_MASK (F_RSPQDISABLED | \ - F_UC_REQ_FRAMINGERROR | F_R_REQ_FRAMINGERROR | \ - F_CPPARITYERROR | F_OCPARITYERROR | F_RCPARITYERROR | \ - F_IRPARITYERROR | V_ITPARITYERROR(M_ITPARITYERROR) | \ - V_FLPARITYERROR(M_FLPARITYERROR) | F_LODRBPARITYERROR | \ - F_HIDRBPARITYERROR | F_LORCQPARITYERROR | \ - F_HIRCQPARITYERROR | F_LOPRIORITYDBFULL | \ - F_HIPRIORITYDBFULL | F_LOPRIORITYDBEMPTY | \ - F_HIPRIORITYDBEMPTY | F_HIPIODRBDROPERR | \ - F_LOPIODRBDROPERR) -#define MC5_INTR_MASK (F_PARITYERR | F_ACTRGNFULL | F_UNKNOWNCMD | \ - F_REQQPARERR | F_DISPQPARERR | F_DELACTEMPTY | \ - F_NFASRCHFAIL) -#define MC7_INTR_MASK (F_AE | F_UE | F_CE | V_PE(M_PE)) -#define XGM_INTR_MASK (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \ - V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR) | \ - F_TXFIFO_UNDERRUN) -#define PCIX_INTR_MASK (F_MSTDETPARERR | F_SIGTARABT | F_RCVTARABT | \ - F_RCVMSTABT | F_SIGSYSERR | F_DETPARERR | \ - F_SPLCMPDIS | F_UNXSPLCMP | F_RCVSPLCMPERR | \ - F_DETCORECCERR | F_DETUNCECCERR | F_PIOPARERR | \ - V_WFPARERR(M_WFPARERR) | V_RFPARERR(M_RFPARERR) | \ - V_CFPARERR(M_CFPARERR) /* | V_MSIXPARERR(M_MSIXPARERR) */) -#define PCIE_INTR_MASK (F_UNXSPLCPLERRR | F_UNXSPLCPLERRC | F_PCIE_PIOPARERR |\ - F_PCIE_WFPARERR | F_PCIE_RFPARERR | F_PCIE_CFPARERR | \ - /* V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR) | */ \ - F_RETRYBUFPARERR | F_RETRYLUTPARERR | F_RXPARERR | \ - F_TXPARERR | V_BISTERR(M_BISTERR)) -#define ULPRX_INTR_MASK (F_PARERRDATA | F_PARERRPCMD | F_ARBPF1PERR | \ - F_ARBPF0PERR | F_ARBFPERR | F_PCMDMUXPERR | \ - F_DATASELFRAMEERR1 | F_DATASELFRAMEERR0) -#define ULPTX_INTR_MASK 0xfc -#define CPLSW_INTR_MASK (F_CIM_OP_MAP_PERR | F_TP_FRAMING_ERROR | \ - F_SGE_FRAMING_ERROR | F_CIM_FRAMING_ERROR | \ - F_ZERO_SWITCH_ERROR) -#define CIM_INTR_MASK (F_BLKWRPLINT | F_BLKRDPLINT | F_BLKWRCTLINT | \ - F_BLKRDCTLINT | F_BLKWRFLASHINT | F_BLKRDFLASHINT | \ - F_SGLWRFLASHINT | F_WRBLKFLASHINT | F_BLKWRBOOTINT | \ - F_FLASHRANGEINT | F_SDRAMRANGEINT | F_RSVDSPACEINT | \ - F_DRAMPARERR | F_ICACHEPARERR | F_DCACHEPARERR | \ - F_OBQSGEPARERR | F_OBQULPHIPARERR | F_OBQULPLOPARERR | \ - F_IBQSGELOPARERR | F_IBQSGEHIPARERR | F_IBQULPPARERR | \ - F_IBQTPPARERR | F_ITAGPARERR | F_DTAGPARERR) -#define PMTX_INTR_MASK (F_ZERO_C_CMD_ERROR | ICSPI_FRM_ERR | OESPI_FRM_ERR | \ - V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR) | \ - V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR)) -#define PMRX_INTR_MASK (F_ZERO_E_CMD_ERROR | IESPI_FRM_ERR | OCSPI_FRM_ERR | \ - V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR) | \ - V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR)) -#define MPS_INTR_MASK (V_TX0TPPARERRENB(M_TX0TPPARERRENB) | \ - V_TX1TPPARERRENB(M_TX1TPPARERRENB) | \ - V_RXTPPARERRENB(M_RXTPPARERRENB) | \ - V_MCAPARERRENB(M_MCAPARERRENB)) -#define XGM_EXTRA_INTR_MASK (F_LINKFAULTCHANGE) -#define PL_INTR_MASK (F_T3DBG | F_XGMAC0_0 | F_XGMAC0_1 | F_MC5A | F_PM1_TX | \ - F_PM1_RX | F_ULP2_TX | F_ULP2_RX | F_TP1 | F_CIM | \ - F_MC7_CM | F_MC7_PMTX | F_MC7_PMRX | F_SGE3 | F_PCIM0 | \ - F_MPS0 | F_CPL_SWITCH) -/* - * Interrupt handler for the PCIX1 module. - */ -static void pci_intr_handler(struct adapter *adapter) -{ - static const struct intr_info pcix1_intr_info[] = { - {F_MSTDETPARERR, "PCI master detected parity error", -1, 1}, - {F_SIGTARABT, "PCI signaled target abort", -1, 1}, - {F_RCVTARABT, "PCI received target abort", -1, 1}, - {F_RCVMSTABT, "PCI received master abort", -1, 1}, - {F_SIGSYSERR, "PCI signaled system error", -1, 1}, - {F_DETPARERR, "PCI detected parity error", -1, 1}, - {F_SPLCMPDIS, "PCI split completion discarded", -1, 1}, - {F_UNXSPLCMP, "PCI unexpected split completion error", -1, 1}, - {F_RCVSPLCMPERR, "PCI received split completion error", -1, - 1}, - {F_DETCORECCERR, "PCI correctable ECC error", - STAT_PCI_CORR_ECC, 0}, - {F_DETUNCECCERR, "PCI uncorrectable ECC error", -1, 1}, - {F_PIOPARERR, "PCI PIO FIFO parity error", -1, 1}, - {V_WFPARERR(M_WFPARERR), "PCI write FIFO parity error", -1, - 1}, - {V_RFPARERR(M_RFPARERR), "PCI read FIFO parity error", -1, - 1}, - {V_CFPARERR(M_CFPARERR), "PCI command FIFO parity error", -1, - 1}, - {V_MSIXPARERR(M_MSIXPARERR), "PCI MSI-X table/PBA parity " - "error", -1, 1}, - {0} - }; - - if (t3_handle_intr_status(adapter, A_PCIX_INT_CAUSE, PCIX_INTR_MASK, - pcix1_intr_info, adapter->irq_stats)) - t3_fatal_err(adapter); -} - -/* - * Interrupt handler for the PCIE module. - */ -static void pcie_intr_handler(struct adapter *adapter) -{ - static const struct intr_info pcie_intr_info[] = { - {F_PEXERR, "PCI PEX error", -1, 1}, - {F_UNXSPLCPLERRR, - "PCI unexpected split completion DMA read error", -1, 1}, - {F_UNXSPLCPLERRC, - "PCI unexpected split completion DMA command error", -1, 1}, - {F_PCIE_PIOPARERR, "PCI PIO FIFO parity error", -1, 1}, - {F_PCIE_WFPARERR, "PCI write FIFO parity error", -1, 1}, - {F_PCIE_RFPARERR, "PCI read FIFO parity error", -1, 1}, - {F_PCIE_CFPARERR, "PCI command FIFO parity error", -1, 1}, - {V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR), - "PCI MSI-X table/PBA parity error", -1, 1}, - {F_RETRYBUFPARERR, "PCI retry buffer parity error", -1, 1}, - {F_RETRYLUTPARERR, "PCI retry LUT parity error", -1, 1}, - {F_RXPARERR, "PCI Rx parity error", -1, 1}, - {F_TXPARERR, "PCI Tx parity error", -1, 1}, - {V_BISTERR(M_BISTERR), "PCI BIST error", -1, 1}, - {0} - }; - - if (t3_read_reg(adapter, A_PCIE_INT_CAUSE) & F_PEXERR) - CH_ALERT(adapter, "PEX error code 0x%x\n", - t3_read_reg(adapter, A_PCIE_PEX_ERR)); - - if (t3_handle_intr_status(adapter, A_PCIE_INT_CAUSE, PCIE_INTR_MASK, - pcie_intr_info, adapter->irq_stats)) - t3_fatal_err(adapter); -} - -/* - * TP interrupt handler. - */ -static void tp_intr_handler(struct adapter *adapter) -{ - static const struct intr_info tp_intr_info[] = { - {0xffffff, "TP parity error", -1, 1}, - {0x1000000, "TP out of Rx pages", -1, 1}, - {0x2000000, "TP out of Tx pages", -1, 1}, - {0} - }; - - static const struct intr_info tp_intr_info_t3c[] = { - {0x1fffffff, "TP parity error", -1, 1}, - {F_FLMRXFLSTEMPTY, "TP out of Rx pages", -1, 1}, - {F_FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1}, - {0} - }; - - if (t3_handle_intr_status(adapter, A_TP_INT_CAUSE, 0xffffffff, - adapter->params.rev < T3_REV_C ? - tp_intr_info : tp_intr_info_t3c, NULL)) - t3_fatal_err(adapter); -} - -/* - * CIM interrupt handler. - */ -static void cim_intr_handler(struct adapter *adapter) -{ - static const struct intr_info cim_intr_info[] = { - {F_RSVDSPACEINT, "CIM reserved space write", -1, 1}, - {F_SDRAMRANGEINT, "CIM SDRAM address out of range", -1, 1}, - {F_FLASHRANGEINT, "CIM flash address out of range", -1, 1}, - {F_BLKWRBOOTINT, "CIM block write to boot space", -1, 1}, - {F_WRBLKFLASHINT, "CIM write to cached flash space", -1, 1}, - {F_SGLWRFLASHINT, "CIM single write to flash space", -1, 1}, - {F_BLKRDFLASHINT, "CIM block read from flash space", -1, 1}, - {F_BLKWRFLASHINT, "CIM block write to flash space", -1, 1}, - {F_BLKRDCTLINT, "CIM block read from CTL space", -1, 1}, - {F_BLKWRCTLINT, "CIM block write to CTL space", -1, 1}, - {F_BLKRDPLINT, "CIM block read from PL space", -1, 1}, - {F_BLKWRPLINT, "CIM block write to PL space", -1, 1}, - {F_DRAMPARERR, "CIM DRAM parity error", -1, 1}, - {F_ICACHEPARERR, "CIM icache parity error", -1, 1}, - {F_DCACHEPARERR, "CIM dcache parity error", -1, 1}, - {F_OBQSGEPARERR, "CIM OBQ SGE parity error", -1, 1}, - {F_OBQULPHIPARERR, "CIM OBQ ULPHI parity error", -1, 1}, - {F_OBQULPLOPARERR, "CIM OBQ ULPLO parity error", -1, 1}, - {F_IBQSGELOPARERR, "CIM IBQ SGELO parity error", -1, 1}, - {F_IBQSGEHIPARERR, "CIM IBQ SGEHI parity error", -1, 1}, - {F_IBQULPPARERR, "CIM IBQ ULP parity error", -1, 1}, - {F_IBQTPPARERR, "CIM IBQ TP parity error", -1, 1}, - {F_ITAGPARERR, "CIM itag parity error", -1, 1}, - {F_DTAGPARERR, "CIM dtag parity error", -1, 1}, - {0} - }; - - if (t3_handle_intr_status(adapter, A_CIM_HOST_INT_CAUSE, 0xffffffff, - cim_intr_info, NULL)) - t3_fatal_err(adapter); -} - -/* - * ULP RX interrupt handler. - */ -static void ulprx_intr_handler(struct adapter *adapter) -{ - static const struct intr_info ulprx_intr_info[] = { - {F_PARERRDATA, "ULP RX data parity error", -1, 1}, - {F_PARERRPCMD, "ULP RX command parity error", -1, 1}, - {F_ARBPF1PERR, "ULP RX ArbPF1 parity error", -1, 1}, - {F_ARBPF0PERR, "ULP RX ArbPF0 parity error", -1, 1}, - {F_ARBFPERR, "ULP RX ArbF parity error", -1, 1}, - {F_PCMDMUXPERR, "ULP RX PCMDMUX parity error", -1, 1}, - {F_DATASELFRAMEERR1, "ULP RX frame error", -1, 1}, - {F_DATASELFRAMEERR0, "ULP RX frame error", -1, 1}, - {0} - }; - - if (t3_handle_intr_status(adapter, A_ULPRX_INT_CAUSE, 0xffffffff, - ulprx_intr_info, NULL)) - t3_fatal_err(adapter); -} - -/* - * ULP TX interrupt handler. - */ -static void ulptx_intr_handler(struct adapter *adapter) -{ - static const struct intr_info ulptx_intr_info[] = { - {F_PBL_BOUND_ERR_CH0, "ULP TX channel 0 PBL out of bounds", - STAT_ULP_CH0_PBL_OOB, 0}, - {F_PBL_BOUND_ERR_CH1, "ULP TX channel 1 PBL out of bounds", - STAT_ULP_CH1_PBL_OOB, 0}, - {0xfc, "ULP TX parity error", -1, 1}, - {0} - }; - - if (t3_handle_intr_status(adapter, A_ULPTX_INT_CAUSE, 0xffffffff, - ulptx_intr_info, adapter->irq_stats)) - t3_fatal_err(adapter); -} - -#define ICSPI_FRM_ERR (F_ICSPI0_FIFO2X_RX_FRAMING_ERROR | \ - F_ICSPI1_FIFO2X_RX_FRAMING_ERROR | F_ICSPI0_RX_FRAMING_ERROR | \ - F_ICSPI1_RX_FRAMING_ERROR | F_ICSPI0_TX_FRAMING_ERROR | \ - F_ICSPI1_TX_FRAMING_ERROR) -#define OESPI_FRM_ERR (F_OESPI0_RX_FRAMING_ERROR | \ - F_OESPI1_RX_FRAMING_ERROR | F_OESPI0_TX_FRAMING_ERROR | \ - F_OESPI1_TX_FRAMING_ERROR | F_OESPI0_OFIFO2X_TX_FRAMING_ERROR | \ - F_OESPI1_OFIFO2X_TX_FRAMING_ERROR) - -/* - * PM TX interrupt handler. - */ -static void pmtx_intr_handler(struct adapter *adapter) -{ - static const struct intr_info pmtx_intr_info[] = { - {F_ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1}, - {ICSPI_FRM_ERR, "PMTX ispi framing error", -1, 1}, - {OESPI_FRM_ERR, "PMTX ospi framing error", -1, 1}, - {V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR), - "PMTX ispi parity error", -1, 1}, - {V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR), - "PMTX ospi parity error", -1, 1}, - {0} - }; - - if (t3_handle_intr_status(adapter, A_PM1_TX_INT_CAUSE, 0xffffffff, - pmtx_intr_info, NULL)) - t3_fatal_err(adapter); -} - -#define IESPI_FRM_ERR (F_IESPI0_FIFO2X_RX_FRAMING_ERROR | \ - F_IESPI1_FIFO2X_RX_FRAMING_ERROR | F_IESPI0_RX_FRAMING_ERROR | \ - F_IESPI1_RX_FRAMING_ERROR | F_IESPI0_TX_FRAMING_ERROR | \ - F_IESPI1_TX_FRAMING_ERROR) -#define OCSPI_FRM_ERR (F_OCSPI0_RX_FRAMING_ERROR | \ - F_OCSPI1_RX_FRAMING_ERROR | F_OCSPI0_TX_FRAMING_ERROR | \ - F_OCSPI1_TX_FRAMING_ERROR | F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR | \ - F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR) - -/* - * PM RX interrupt handler. - */ -static void pmrx_intr_handler(struct adapter *adapter) -{ - static const struct intr_info pmrx_intr_info[] = { - {F_ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1}, - {IESPI_FRM_ERR, "PMRX ispi framing error", -1, 1}, - {OCSPI_FRM_ERR, "PMRX ospi framing error", -1, 1}, - {V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR), - "PMRX ispi parity error", -1, 1}, - {V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR), - "PMRX ospi parity error", -1, 1}, - {0} - }; - - if (t3_handle_intr_status(adapter, A_PM1_RX_INT_CAUSE, 0xffffffff, - pmrx_intr_info, NULL)) - t3_fatal_err(adapter); -} - -/* - * CPL switch interrupt handler. - */ -static void cplsw_intr_handler(struct adapter *adapter) -{ - static const struct intr_info cplsw_intr_info[] = { - {F_CIM_OP_MAP_PERR, "CPL switch CIM parity error", -1, 1}, - {F_CIM_OVFL_ERROR, "CPL switch CIM overflow", -1, 1}, - {F_TP_FRAMING_ERROR, "CPL switch TP framing error", -1, 1}, - {F_SGE_FRAMING_ERROR, "CPL switch SGE framing error", -1, 1}, - {F_CIM_FRAMING_ERROR, "CPL switch CIM framing error", -1, 1}, - {F_ZERO_SWITCH_ERROR, "CPL switch no-switch error", -1, 1}, - {0} - }; - - if (t3_handle_intr_status(adapter, A_CPL_INTR_CAUSE, 0xffffffff, - cplsw_intr_info, NULL)) - t3_fatal_err(adapter); -} - -/* - * MPS interrupt handler. - */ -static void mps_intr_handler(struct adapter *adapter) -{ - static const struct intr_info mps_intr_info[] = { - {0x1ff, "MPS parity error", -1, 1}, - {0} - }; - - if (t3_handle_intr_status(adapter, A_MPS_INT_CAUSE, 0xffffffff, - mps_intr_info, NULL)) - t3_fatal_err(adapter); -} - -#define MC7_INTR_FATAL (F_UE | V_PE(M_PE) | F_AE) - -/* - * MC7 interrupt handler. - */ -static void mc7_intr_handler(struct mc7 *mc7) -{ - struct adapter *adapter = mc7->adapter; - u32 cause = t3_read_reg(adapter, mc7->offset + A_MC7_INT_CAUSE); - - if (cause & F_CE) { - mc7->stats.corr_err++; - CH_WARN(adapter, "%s MC7 correctable error at addr 0x%x, " - "data 0x%x 0x%x 0x%x\n", mc7->name, - t3_read_reg(adapter, mc7->offset + A_MC7_CE_ADDR), - t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA0), - t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA1), - t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA2)); - } - - if (cause & F_UE) { - mc7->stats.uncorr_err++; - CH_ALERT(adapter, "%s MC7 uncorrectable error at addr 0x%x, " - "data 0x%x 0x%x 0x%x\n", mc7->name, - t3_read_reg(adapter, mc7->offset + A_MC7_UE_ADDR), - t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA0), - t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA1), - t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA2)); - } - - if (G_PE(cause)) { - mc7->stats.parity_err++; - CH_ALERT(adapter, "%s MC7 parity error 0x%x\n", - mc7->name, G_PE(cause)); - } - - if (cause & F_AE) { - u32 addr = 0; - - if (adapter->params.rev > 0) - addr = t3_read_reg(adapter, - mc7->offset + A_MC7_ERR_ADDR); - mc7->stats.addr_err++; - CH_ALERT(adapter, "%s MC7 address error: 0x%x\n", - mc7->name, addr); - } - - if (cause & MC7_INTR_FATAL) - t3_fatal_err(adapter); - - t3_write_reg(adapter, mc7->offset + A_MC7_INT_CAUSE, cause); -} - -#define XGM_INTR_FATAL (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \ - V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR)) -/* - * XGMAC interrupt handler. - */ -static int mac_intr_handler(struct adapter *adap, unsigned int idx) -{ - struct cmac *mac = &adap2pinfo(adap, idx)->mac; - /* - * We mask out interrupt causes for which we're not taking interrupts. - * This allows us to use polling logic to monitor some of the other - * conditions when taking interrupts would impose too much load on the - * system. - */ - u32 cause = t3_read_reg(adap, A_XGM_INT_CAUSE + mac->offset) & - ~F_RXFIFO_OVERFLOW; - - if (cause & V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR)) { - mac->stats.tx_fifo_parity_err++; - CH_ALERT(adap, "port%d: MAC TX FIFO parity error\n", idx); - } - if (cause & V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR)) { - mac->stats.rx_fifo_parity_err++; - CH_ALERT(adap, "port%d: MAC RX FIFO parity error\n", idx); - } - if (cause & F_TXFIFO_UNDERRUN) - mac->stats.tx_fifo_urun++; - if (cause & F_RXFIFO_OVERFLOW) - mac->stats.rx_fifo_ovfl++; - if (cause & V_SERDES_LOS(M_SERDES_LOS)) - mac->stats.serdes_signal_loss++; - if (cause & F_XAUIPCSCTCERR) - mac->stats.xaui_pcs_ctc_err++; - if (cause & F_XAUIPCSALIGNCHANGE) - mac->stats.xaui_pcs_align_change++; - if (cause & F_XGM_INT) { - t3_set_reg_field(adap, - A_XGM_INT_ENABLE + mac->offset, - F_XGM_INT, 0); - mac->stats.link_faults++; - - t3_os_link_fault_handler(adap, idx); - } - - if (cause & XGM_INTR_FATAL) - t3_fatal_err(adap); - - t3_write_reg(adap, A_XGM_INT_CAUSE + mac->offset, cause); - return cause != 0; -} - -/* - * Interrupt handler for PHY events. - */ -int t3_phy_intr_handler(struct adapter *adapter) -{ - u32 i, cause = t3_read_reg(adapter, A_T3DBG_INT_CAUSE); - - for_each_port(adapter, i) { - struct port_info *p = adap2pinfo(adapter, i); - - if (!(p->phy.caps & SUPPORTED_IRQ)) - continue; - - if (cause & (1 << adapter_info(adapter)->gpio_intr[i])) { - int phy_cause = p->phy.ops->intr_handler(&p->phy); - - if (phy_cause & cphy_cause_link_change) - t3_link_changed(adapter, i); - if (phy_cause & cphy_cause_fifo_error) - p->phy.fifo_errors++; - if (phy_cause & cphy_cause_module_change) - t3_os_phymod_changed(adapter, i); - } - } - - t3_write_reg(adapter, A_T3DBG_INT_CAUSE, cause); - return 0; -} - -/* - * T3 slow path (non-data) interrupt handler. - */ -int t3_slow_intr_handler(struct adapter *adapter) -{ - u32 cause = t3_read_reg(adapter, A_PL_INT_CAUSE0); - - cause &= adapter->slow_intr_mask; - if (!cause) - return 0; - if (cause & F_PCIM0) { - if (is_pcie(adapter)) - pcie_intr_handler(adapter); - else - pci_intr_handler(adapter); - } - if (cause & F_SGE3) - t3_sge_err_intr_handler(adapter); - if (cause & F_MC7_PMRX) - mc7_intr_handler(&adapter->pmrx); - if (cause & F_MC7_PMTX) - mc7_intr_handler(&adapter->pmtx); - if (cause & F_MC7_CM) - mc7_intr_handler(&adapter->cm); - if (cause & F_CIM) - cim_intr_handler(adapter); - if (cause & F_TP1) - tp_intr_handler(adapter); - if (cause & F_ULP2_RX) - ulprx_intr_handler(adapter); - if (cause & F_ULP2_TX) - ulptx_intr_handler(adapter); - if (cause & F_PM1_RX) - pmrx_intr_handler(adapter); - if (cause & F_PM1_TX) - pmtx_intr_handler(adapter); - if (cause & F_CPL_SWITCH) - cplsw_intr_handler(adapter); - if (cause & F_MPS0) - mps_intr_handler(adapter); - if (cause & F_MC5A) - t3_mc5_intr_handler(&adapter->mc5); - if (cause & F_XGMAC0_0) - mac_intr_handler(adapter, 0); - if (cause & F_XGMAC0_1) - mac_intr_handler(adapter, 1); - if (cause & F_T3DBG) - t3_os_ext_intr_handler(adapter); - - /* Clear the interrupts just processed. */ - t3_write_reg(adapter, A_PL_INT_CAUSE0, cause); - t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */ - return 1; -} - -static unsigned int calc_gpio_intr(struct adapter *adap) -{ - unsigned int i, gpi_intr = 0; - - for_each_port(adap, i) - if ((adap2pinfo(adap, i)->phy.caps & SUPPORTED_IRQ) && - adapter_info(adap)->gpio_intr[i]) - gpi_intr |= 1 << adapter_info(adap)->gpio_intr[i]; - return gpi_intr; -} - -/** - * t3_intr_enable - enable interrupts - * @adapter: the adapter whose interrupts should be enabled - * - * Enable interrupts by setting the interrupt enable registers of the - * various HW modules and then enabling the top-level interrupt - * concentrator. - */ -void t3_intr_enable(struct adapter *adapter) -{ - static const struct addr_val_pair intr_en_avp[] = { - {A_SG_INT_ENABLE, SGE_INTR_MASK}, - {A_MC7_INT_ENABLE, MC7_INTR_MASK}, - {A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR, - MC7_INTR_MASK}, - {A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR, - MC7_INTR_MASK}, - {A_MC5_DB_INT_ENABLE, MC5_INTR_MASK}, - {A_ULPRX_INT_ENABLE, ULPRX_INTR_MASK}, - {A_PM1_TX_INT_ENABLE, PMTX_INTR_MASK}, - {A_PM1_RX_INT_ENABLE, PMRX_INTR_MASK}, - {A_CIM_HOST_INT_ENABLE, CIM_INTR_MASK}, - {A_MPS_INT_ENABLE, MPS_INTR_MASK}, - }; - - adapter->slow_intr_mask = PL_INTR_MASK; - - t3_write_regs(adapter, intr_en_avp, ARRAY_SIZE(intr_en_avp), 0); - t3_write_reg(adapter, A_TP_INT_ENABLE, - adapter->params.rev >= T3_REV_C ? 0x2bfffff : 0x3bfffff); - - if (adapter->params.rev > 0) { - t3_write_reg(adapter, A_CPL_INTR_ENABLE, - CPLSW_INTR_MASK | F_CIM_OVFL_ERROR); - t3_write_reg(adapter, A_ULPTX_INT_ENABLE, - ULPTX_INTR_MASK | F_PBL_BOUND_ERR_CH0 | - F_PBL_BOUND_ERR_CH1); - } else { - t3_write_reg(adapter, A_CPL_INTR_ENABLE, CPLSW_INTR_MASK); - t3_write_reg(adapter, A_ULPTX_INT_ENABLE, ULPTX_INTR_MASK); - } - - t3_write_reg(adapter, A_T3DBG_INT_ENABLE, calc_gpio_intr(adapter)); - - if (is_pcie(adapter)) - t3_write_reg(adapter, A_PCIE_INT_ENABLE, PCIE_INTR_MASK); - else - t3_write_reg(adapter, A_PCIX_INT_ENABLE, PCIX_INTR_MASK); - t3_write_reg(adapter, A_PL_INT_ENABLE0, adapter->slow_intr_mask); - t3_read_reg(adapter, A_PL_INT_ENABLE0); /* flush */ -} - -/** - * t3_intr_disable - disable a card's interrupts - * @adapter: the adapter whose interrupts should be disabled - * - * Disable interrupts. We only disable the top-level interrupt - * concentrator and the SGE data interrupts. - */ -void t3_intr_disable(struct adapter *adapter) -{ - t3_write_reg(adapter, A_PL_INT_ENABLE0, 0); - t3_read_reg(adapter, A_PL_INT_ENABLE0); /* flush */ - adapter->slow_intr_mask = 0; -} - -/** - * t3_intr_clear - clear all interrupts - * @adapter: the adapter whose interrupts should be cleared - * - * Clears all interrupts. - */ -void t3_intr_clear(struct adapter *adapter) -{ - static const unsigned int cause_reg_addr[] = { - A_SG_INT_CAUSE, - A_SG_RSPQ_FL_STATUS, - A_PCIX_INT_CAUSE, - A_MC7_INT_CAUSE, - A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR, - A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR, - A_CIM_HOST_INT_CAUSE, - A_TP_INT_CAUSE, - A_MC5_DB_INT_CAUSE, - A_ULPRX_INT_CAUSE, - A_ULPTX_INT_CAUSE, - A_CPL_INTR_CAUSE, - A_PM1_TX_INT_CAUSE, - A_PM1_RX_INT_CAUSE, - A_MPS_INT_CAUSE, - A_T3DBG_INT_CAUSE, - }; - unsigned int i; - - /* Clear PHY and MAC interrupts for each port. */ - for_each_port(adapter, i) - t3_port_intr_clear(adapter, i); - - for (i = 0; i < ARRAY_SIZE(cause_reg_addr); ++i) - t3_write_reg(adapter, cause_reg_addr[i], 0xffffffff); - - if (is_pcie(adapter)) - t3_write_reg(adapter, A_PCIE_PEX_ERR, 0xffffffff); - t3_write_reg(adapter, A_PL_INT_CAUSE0, 0xffffffff); - t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */ -} - -void t3_xgm_intr_enable(struct adapter *adapter, int idx) -{ - struct port_info *pi = adap2pinfo(adapter, idx); - - t3_write_reg(adapter, A_XGM_XGM_INT_ENABLE + pi->mac.offset, - XGM_EXTRA_INTR_MASK); -} - -void t3_xgm_intr_disable(struct adapter *adapter, int idx) -{ - struct port_info *pi = adap2pinfo(adapter, idx); - - t3_write_reg(adapter, A_XGM_XGM_INT_DISABLE + pi->mac.offset, - 0x7ff); -} - -/** - * t3_port_intr_enable - enable port-specific interrupts - * @adapter: associated adapter - * @idx: index of port whose interrupts should be enabled - * - * Enable port-specific (i.e., MAC and PHY) interrupts for the given - * adapter port. - */ -void t3_port_intr_enable(struct adapter *adapter, int idx) -{ - struct cphy *phy = &adap2pinfo(adapter, idx)->phy; - - t3_write_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx), XGM_INTR_MASK); - t3_read_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx)); /* flush */ - phy->ops->intr_enable(phy); -} - -/** - * t3_port_intr_disable - disable port-specific interrupts - * @adapter: associated adapter - * @idx: index of port whose interrupts should be disabled - * - * Disable port-specific (i.e., MAC and PHY) interrupts for the given - * adapter port. - */ -void t3_port_intr_disable(struct adapter *adapter, int idx) -{ - struct cphy *phy = &adap2pinfo(adapter, idx)->phy; - - t3_write_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx), 0); - t3_read_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx)); /* flush */ - phy->ops->intr_disable(phy); -} - -/** - * t3_port_intr_clear - clear port-specific interrupts - * @adapter: associated adapter - * @idx: index of port whose interrupts to clear - * - * Clear port-specific (i.e., MAC and PHY) interrupts for the given - * adapter port. - */ -static void t3_port_intr_clear(struct adapter *adapter, int idx) -{ - struct cphy *phy = &adap2pinfo(adapter, idx)->phy; - - t3_write_reg(adapter, XGM_REG(A_XGM_INT_CAUSE, idx), 0xffffffff); - t3_read_reg(adapter, XGM_REG(A_XGM_INT_CAUSE, idx)); /* flush */ - phy->ops->intr_clear(phy); -} - -#define SG_CONTEXT_CMD_ATTEMPTS 100 - -/** - * t3_sge_write_context - write an SGE context - * @adapter: the adapter - * @id: the context id - * @type: the context type - * - * Program an SGE context with the values already loaded in the - * CONTEXT_DATA? registers. - */ -static int t3_sge_write_context(struct adapter *adapter, unsigned int id, - unsigned int type) -{ - if (type == F_RESPONSEQ) { - /* - * Can't write the Response Queue Context bits for - * Interrupt Armed or the Reserve bits after the chip - * has been initialized out of reset. Writing to these - * bits can confuse the hardware. - */ - t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0xffffffff); - t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0xffffffff); - t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0x17ffffff); - t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0xffffffff); - } else { - t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0xffffffff); - t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0xffffffff); - t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0xffffffff); - t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0xffffffff); - } - t3_write_reg(adapter, A_SG_CONTEXT_CMD, - V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id)); - return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, - 0, SG_CONTEXT_CMD_ATTEMPTS, 1); -} - -/** - * clear_sge_ctxt - completely clear an SGE context - * @adapter: the adapter - * @id: the context id - * @type: the context type - * - * Completely clear an SGE context. Used predominantly at post-reset - * initialization. Note in particular that we don't skip writing to any - * "sensitive bits" in the contexts the way that t3_sge_write_context() - * does ... - */ -static int clear_sge_ctxt(struct adapter *adap, unsigned int id, - unsigned int type) -{ - t3_write_reg(adap, A_SG_CONTEXT_DATA0, 0); - t3_write_reg(adap, A_SG_CONTEXT_DATA1, 0); - t3_write_reg(adap, A_SG_CONTEXT_DATA2, 0); - t3_write_reg(adap, A_SG_CONTEXT_DATA3, 0); - t3_write_reg(adap, A_SG_CONTEXT_MASK0, 0xffffffff); - t3_write_reg(adap, A_SG_CONTEXT_MASK1, 0xffffffff); - t3_write_reg(adap, A_SG_CONTEXT_MASK2, 0xffffffff); - t3_write_reg(adap, A_SG_CONTEXT_MASK3, 0xffffffff); - t3_write_reg(adap, A_SG_CONTEXT_CMD, - V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id)); - return t3_wait_op_done(adap, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, - 0, SG_CONTEXT_CMD_ATTEMPTS, 1); -} - -/** - * t3_sge_init_ecntxt - initialize an SGE egress context - * @adapter: the adapter to configure - * @id: the context id - * @gts_enable: whether to enable GTS for the context - * @type: the egress context type - * @respq: associated response queue - * @base_addr: base address of queue - * @size: number of queue entries - * @token: uP token - * @gen: initial generation value for the context - * @cidx: consumer pointer - * - * Initialize an SGE egress context and make it ready for use. If the - * platform allows concurrent context operations, the caller is - * responsible for appropriate locking. - */ -int t3_sge_init_ecntxt(struct adapter *adapter, unsigned int id, int gts_enable, - enum sge_context_type type, int respq, u64 base_addr, - unsigned int size, unsigned int token, int gen, - unsigned int cidx) -{ - unsigned int credits = type == SGE_CNTXT_OFLD ? 0 : FW_WR_NUM; - - if (base_addr & 0xfff) /* must be 4K aligned */ - return -EINVAL; - if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) - return -EBUSY; - - base_addr >>= 12; - t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_EC_INDEX(cidx) | - V_EC_CREDITS(credits) | V_EC_GTS(gts_enable)); - t3_write_reg(adapter, A_SG_CONTEXT_DATA1, V_EC_SIZE(size) | - V_EC_BASE_LO(base_addr & 0xffff)); - base_addr >>= 16; - t3_write_reg(adapter, A_SG_CONTEXT_DATA2, base_addr); - base_addr >>= 32; - t3_write_reg(adapter, A_SG_CONTEXT_DATA3, - V_EC_BASE_HI(base_addr & 0xf) | V_EC_RESPQ(respq) | - V_EC_TYPE(type) | V_EC_GEN(gen) | V_EC_UP_TOKEN(token) | - F_EC_VALID); - return t3_sge_write_context(adapter, id, F_EGRESS); -} - -/** - * t3_sge_init_flcntxt - initialize an SGE free-buffer list context - * @adapter: the adapter to configure - * @id: the context id - * @gts_enable: whether to enable GTS for the context - * @base_addr: base address of queue - * @size: number of queue entries - * @bsize: size of each buffer for this queue - * @cong_thres: threshold to signal congestion to upstream producers - * @gen: initial generation value for the context - * @cidx: consumer pointer - * - * Initialize an SGE free list context and make it ready for use. The - * caller is responsible for ensuring only one context operation occurs - * at a time. - */ -int t3_sge_init_flcntxt(struct adapter *adapter, unsigned int id, - int gts_enable, u64 base_addr, unsigned int size, - unsigned int bsize, unsigned int cong_thres, int gen, - unsigned int cidx) -{ - if (base_addr & 0xfff) /* must be 4K aligned */ - return -EINVAL; - if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) - return -EBUSY; - - base_addr >>= 12; - t3_write_reg(adapter, A_SG_CONTEXT_DATA0, base_addr); - base_addr >>= 32; - t3_write_reg(adapter, A_SG_CONTEXT_DATA1, - V_FL_BASE_HI((u32) base_addr) | - V_FL_INDEX_LO(cidx & M_FL_INDEX_LO)); - t3_write_reg(adapter, A_SG_CONTEXT_DATA2, V_FL_SIZE(size) | - V_FL_GEN(gen) | V_FL_INDEX_HI(cidx >> 12) | - V_FL_ENTRY_SIZE_LO(bsize & M_FL_ENTRY_SIZE_LO)); - t3_write_reg(adapter, A_SG_CONTEXT_DATA3, - V_FL_ENTRY_SIZE_HI(bsize >> (32 - S_FL_ENTRY_SIZE_LO)) | - V_FL_CONG_THRES(cong_thres) | V_FL_GTS(gts_enable)); - return t3_sge_write_context(adapter, id, F_FREELIST); -} - -/** - * t3_sge_init_rspcntxt - initialize an SGE response queue context - * @adapter: the adapter to configure - * @id: the context id - * @irq_vec_idx: MSI-X interrupt vector index, 0 if no MSI-X, -1 if no IRQ - * @base_addr: base address of queue - * @size: number of queue entries - * @fl_thres: threshold for selecting the normal or jumbo free list - * @gen: initial generation value for the context - * @cidx: consumer pointer - * - * Initialize an SGE response queue context and make it ready for use. - * The caller is responsible for ensuring only one context operation - * occurs at a time. - */ -int t3_sge_init_rspcntxt(struct adapter *adapter, unsigned int id, - int irq_vec_idx, u64 base_addr, unsigned int size, - unsigned int fl_thres, int gen, unsigned int cidx) -{ - unsigned int intr = 0; - - if (base_addr & 0xfff) /* must be 4K aligned */ - return -EINVAL; - if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) - return -EBUSY; - - base_addr >>= 12; - t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size) | - V_CQ_INDEX(cidx)); - t3_write_reg(adapter, A_SG_CONTEXT_DATA1, base_addr); - base_addr >>= 32; - if (irq_vec_idx >= 0) - intr = V_RQ_MSI_VEC(irq_vec_idx) | F_RQ_INTR_EN; - t3_write_reg(adapter, A_SG_CONTEXT_DATA2, - V_CQ_BASE_HI((u32) base_addr) | intr | V_RQ_GEN(gen)); - t3_write_reg(adapter, A_SG_CONTEXT_DATA3, fl_thres); - return t3_sge_write_context(adapter, id, F_RESPONSEQ); -} - -/** - * t3_sge_init_cqcntxt - initialize an SGE completion queue context - * @adapter: the adapter to configure - * @id: the context id - * @base_addr: base address of queue - * @size: number of queue entries - * @rspq: response queue for async notifications - * @ovfl_mode: CQ overflow mode - * @credits: completion queue credits - * @credit_thres: the credit threshold - * - * Initialize an SGE completion queue context and make it ready for use. - * The caller is responsible for ensuring only one context operation - * occurs at a time. - */ -int t3_sge_init_cqcntxt(struct adapter *adapter, unsigned int id, u64 base_addr, - unsigned int size, int rspq, int ovfl_mode, - unsigned int credits, unsigned int credit_thres) -{ - if (base_addr & 0xfff) /* must be 4K aligned */ - return -EINVAL; - if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) - return -EBUSY; - - base_addr >>= 12; - t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size)); - t3_write_reg(adapter, A_SG_CONTEXT_DATA1, base_addr); - base_addr >>= 32; - t3_write_reg(adapter, A_SG_CONTEXT_DATA2, - V_CQ_BASE_HI((u32) base_addr) | V_CQ_RSPQ(rspq) | - V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode) | - V_CQ_ERR(ovfl_mode)); - t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_CQ_CREDITS(credits) | - V_CQ_CREDIT_THRES(credit_thres)); - return t3_sge_write_context(adapter, id, F_CQ); -} - -/** - * t3_sge_enable_ecntxt - enable/disable an SGE egress context - * @adapter: the adapter - * @id: the egress context id - * @enable: enable (1) or disable (0) the context - * - * Enable or disable an SGE egress context. The caller is responsible for - * ensuring only one context operation occurs at a time. - */ -int t3_sge_enable_ecntxt(struct adapter *adapter, unsigned int id, int enable) -{ - if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) - return -EBUSY; - - t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0); - t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); - t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0); - t3_write_reg(adapter, A_SG_CONTEXT_MASK3, F_EC_VALID); - t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_EC_VALID(enable)); - t3_write_reg(adapter, A_SG_CONTEXT_CMD, - V_CONTEXT_CMD_OPCODE(1) | F_EGRESS | V_CONTEXT(id)); - return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, - 0, SG_CONTEXT_CMD_ATTEMPTS, 1); -} - -/** - * t3_sge_disable_fl - disable an SGE free-buffer list - * @adapter: the adapter - * @id: the free list context id - * - * Disable an SGE free-buffer list. The caller is responsible for - * ensuring only one context operation occurs at a time. - */ -int t3_sge_disable_fl(struct adapter *adapter, unsigned int id) -{ - if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) - return -EBUSY; - - t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0); - t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); - t3_write_reg(adapter, A_SG_CONTEXT_MASK2, V_FL_SIZE(M_FL_SIZE)); - t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0); - t3_write_reg(adapter, A_SG_CONTEXT_DATA2, 0); - t3_write_reg(adapter, A_SG_CONTEXT_CMD, - V_CONTEXT_CMD_OPCODE(1) | F_FREELIST | V_CONTEXT(id)); - return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, - 0, SG_CONTEXT_CMD_ATTEMPTS, 1); -} - -/** - * t3_sge_disable_rspcntxt - disable an SGE response queue - * @adapter: the adapter - * @id: the response queue context id - * - * Disable an SGE response queue. The caller is responsible for - * ensuring only one context operation occurs at a time. - */ -int t3_sge_disable_rspcntxt(struct adapter *adapter, unsigned int id) -{ - if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) - return -EBUSY; - - t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE)); - t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); - t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0); - t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0); - t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0); - t3_write_reg(adapter, A_SG_CONTEXT_CMD, - V_CONTEXT_CMD_OPCODE(1) | F_RESPONSEQ | V_CONTEXT(id)); - return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, - 0, SG_CONTEXT_CMD_ATTEMPTS, 1); -} - -/** - * t3_sge_disable_cqcntxt - disable an SGE completion queue - * @adapter: the adapter - * @id: the completion queue context id - * - * Disable an SGE completion queue. The caller is responsible for - * ensuring only one context operation occurs at a time. - */ -int t3_sge_disable_cqcntxt(struct adapter *adapter, unsigned int id) -{ - if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) - return -EBUSY; - - t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE)); - t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); - t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0); - t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0); - t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0); - t3_write_reg(adapter, A_SG_CONTEXT_CMD, - V_CONTEXT_CMD_OPCODE(1) | F_CQ | V_CONTEXT(id)); - return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, - 0, SG_CONTEXT_CMD_ATTEMPTS, 1); -} - -/** - * t3_sge_cqcntxt_op - perform an operation on a completion queue context - * @adapter: the adapter - * @id: the context id - * @op: the operation to perform - * - * Perform the selected operation on an SGE completion queue context. - * The caller is responsible for ensuring only one context operation - * occurs at a time. - */ -int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op, - unsigned int credits) -{ - u32 val; - - if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) - return -EBUSY; - - t3_write_reg(adapter, A_SG_CONTEXT_DATA0, credits << 16); - t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(op) | - V_CONTEXT(id) | F_CQ); - if (t3_wait_op_done_val(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, - 0, SG_CONTEXT_CMD_ATTEMPTS, 1, &val)) - return -EIO; - - if (op >= 2 && op < 7) { - if (adapter->params.rev > 0) - return G_CQ_INDEX(val); - - t3_write_reg(adapter, A_SG_CONTEXT_CMD, - V_CONTEXT_CMD_OPCODE(0) | F_CQ | V_CONTEXT(id)); - if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, - F_CONTEXT_CMD_BUSY, 0, - SG_CONTEXT_CMD_ATTEMPTS, 1)) - return -EIO; - return G_CQ_INDEX(t3_read_reg(adapter, A_SG_CONTEXT_DATA0)); - } - return 0; -} - -/** - * t3_config_rss - configure Rx packet steering - * @adapter: the adapter - * @rss_config: RSS settings (written to TP_RSS_CONFIG) - * @cpus: values for the CPU lookup table (0xff terminated) - * @rspq: values for the response queue lookup table (0xffff terminated) - * - * Programs the receive packet steering logic. @cpus and @rspq provide - * the values for the CPU and response queue lookup tables. If they - * provide fewer values than the size of the tables the supplied values - * are used repeatedly until the tables are fully populated. - */ -void t3_config_rss(struct adapter *adapter, unsigned int rss_config, - const u8 * cpus, const u16 *rspq) -{ - int i, j, cpu_idx = 0, q_idx = 0; - - if (cpus) - for (i = 0; i < RSS_TABLE_SIZE; ++i) { - u32 val = i << 16; - - for (j = 0; j < 2; ++j) { - val |= (cpus[cpu_idx++] & 0x3f) << (8 * j); - if (cpus[cpu_idx] == 0xff) - cpu_idx = 0; - } - t3_write_reg(adapter, A_TP_RSS_LKP_TABLE, val); - } - - if (rspq) - for (i = 0; i < RSS_TABLE_SIZE; ++i) { - t3_write_reg(adapter, A_TP_RSS_MAP_TABLE, - (i << 16) | rspq[q_idx++]); - if (rspq[q_idx] == 0xffff) - q_idx = 0; - } - - t3_write_reg(adapter, A_TP_RSS_CONFIG, rss_config); -} - -/** - * t3_tp_set_offload_mode - put TP in NIC/offload mode - * @adap: the adapter - * @enable: 1 to select offload mode, 0 for regular NIC - * - * Switches TP to NIC/offload mode. - */ -void t3_tp_set_offload_mode(struct adapter *adap, int enable) -{ - if (is_offload(adap) || !enable) - t3_set_reg_field(adap, A_TP_IN_CONFIG, F_NICMODE, - V_NICMODE(!enable)); -} - -/** - * pm_num_pages - calculate the number of pages of the payload memory - * @mem_size: the size of the payload memory - * @pg_size: the size of each payload memory page - * - * Calculate the number of pages, each of the given size, that fit in a - * memory of the specified size, respecting the HW requirement that the - * number of pages must be a multiple of 24. - */ -static inline unsigned int pm_num_pages(unsigned int mem_size, - unsigned int pg_size) -{ - unsigned int n = mem_size / pg_size; - - return n - n % 24; -} - -#define mem_region(adap, start, size, reg) \ - t3_write_reg((adap), A_ ## reg, (start)); \ - start += size - -/** - * partition_mem - partition memory and configure TP memory settings - * @adap: the adapter - * @p: the TP parameters - * - * Partitions context and payload memory and configures TP's memory - * registers. - */ -static void partition_mem(struct adapter *adap, const struct tp_params *p) -{ - unsigned int m, pstructs, tids = t3_mc5_size(&adap->mc5); - unsigned int timers = 0, timers_shift = 22; - - if (adap->params.rev > 0) { - if (tids <= 16 * 1024) { - timers = 1; - timers_shift = 16; - } else if (tids <= 64 * 1024) { - timers = 2; - timers_shift = 18; - } else if (tids <= 256 * 1024) { - timers = 3; - timers_shift = 20; - } - } - - t3_write_reg(adap, A_TP_PMM_SIZE, - p->chan_rx_size | (p->chan_tx_size >> 16)); - - t3_write_reg(adap, A_TP_PMM_TX_BASE, 0); - t3_write_reg(adap, A_TP_PMM_TX_PAGE_SIZE, p->tx_pg_size); - t3_write_reg(adap, A_TP_PMM_TX_MAX_PAGE, p->tx_num_pgs); - t3_set_reg_field(adap, A_TP_PARA_REG3, V_TXDATAACKIDX(M_TXDATAACKIDX), - V_TXDATAACKIDX(fls(p->tx_pg_size) - 12)); - - t3_write_reg(adap, A_TP_PMM_RX_BASE, 0); - t3_write_reg(adap, A_TP_PMM_RX_PAGE_SIZE, p->rx_pg_size); - t3_write_reg(adap, A_TP_PMM_RX_MAX_PAGE, p->rx_num_pgs); - - pstructs = p->rx_num_pgs + p->tx_num_pgs; - /* Add a bit of headroom and make multiple of 24 */ - pstructs += 48; - pstructs -= pstructs % 24; - t3_write_reg(adap, A_TP_CMM_MM_MAX_PSTRUCT, pstructs); - - m = tids * TCB_SIZE; - mem_region(adap, m, (64 << 10) * 64, SG_EGR_CNTX_BADDR); - mem_region(adap, m, (64 << 10) * 64, SG_CQ_CONTEXT_BADDR); - t3_write_reg(adap, A_TP_CMM_TIMER_BASE, V_CMTIMERMAXNUM(timers) | m); - m += ((p->ntimer_qs - 1) << timers_shift) + (1 << 22); - mem_region(adap, m, pstructs * 64, TP_CMM_MM_BASE); - mem_region(adap, m, 64 * (pstructs / 24), TP_CMM_MM_PS_FLST_BASE); - mem_region(adap, m, 64 * (p->rx_num_pgs / 24), TP_CMM_MM_RX_FLST_BASE); - mem_region(adap, m, 64 * (p->tx_num_pgs / 24), TP_CMM_MM_TX_FLST_BASE); - - m = (m + 4095) & ~0xfff; - t3_write_reg(adap, A_CIM_SDRAM_BASE_ADDR, m); - t3_write_reg(adap, A_CIM_SDRAM_ADDR_SIZE, p->cm_size - m); - - tids = (p->cm_size - m - (3 << 20)) / 3072 - 32; - m = t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers - - adap->params.mc5.nfilters - adap->params.mc5.nroutes; - if (tids < m) - adap->params.mc5.nservers += m - tids; -} - -static inline void tp_wr_indirect(struct adapter *adap, unsigned int addr, - u32 val) -{ - t3_write_reg(adap, A_TP_PIO_ADDR, addr); - t3_write_reg(adap, A_TP_PIO_DATA, val); -} - -static void tp_config(struct adapter *adap, const struct tp_params *p) -{ - t3_write_reg(adap, A_TP_GLOBAL_CONFIG, F_TXPACINGENABLE | F_PATHMTU | - F_IPCHECKSUMOFFLOAD | F_UDPCHECKSUMOFFLOAD | - F_TCPCHECKSUMOFFLOAD | V_IPTTL(64)); - t3_write_reg(adap, A_TP_TCP_OPTIONS, V_MTUDEFAULT(576) | - F_MTUENABLE | V_WINDOWSCALEMODE(1) | - V_TIMESTAMPSMODE(1) | V_SACKMODE(1) | V_SACKRX(1)); - t3_write_reg(adap, A_TP_DACK_CONFIG, V_AUTOSTATE3(1) | - V_AUTOSTATE2(1) | V_AUTOSTATE1(0) | - V_BYTETHRESHOLD(26880) | V_MSSTHRESHOLD(2) | - F_AUTOCAREFUL | F_AUTOENABLE | V_DACK_MODE(1)); - t3_set_reg_field(adap, A_TP_IN_CONFIG, F_RXFBARBPRIO | F_TXFBARBPRIO, - 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, 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); - t3_set_reg_field(adap, A_TP_PC_CONFIG2, F_CHDRAFULL, - F_ENABLEIPV6RSS | F_ENABLENONOFDTNLSYN | - F_ENABLEARPMISS | F_DISBLEDAPARBIT0); - 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); - t3_set_reg_field(adap, A_TP_PARA_REG3, F_TXPACEAUTO, - F_TXPACEAUTO); - 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); - } else - t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEFIXED); - - if (adap->params.rev == T3_REV_C) - t3_set_reg_field(adap, A_TP_PC_CONFIG, - V_TABLELATENCYDELTA(M_TABLELATENCYDELTA), - V_TABLELATENCYDELTA(4)); - - 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, 0xf2200000); -} - -/* Desired TP timer resolution in usec */ -#define TP_TMR_RES 50 - -/* TCP timer values in ms */ -#define TP_DACK_TIMER 50 -#define TP_RTO_MIN 250 - -/** - * tp_set_timers - set TP timing parameters - * @adap: the adapter to set - * @core_clk: the core clock frequency in Hz - * - * Set TP's timing parameters, such as the various timer resolutions and - * the TCP timer values. - */ -static void tp_set_timers(struct adapter *adap, unsigned int core_clk) -{ - unsigned int tre = fls(core_clk / (1000000 / TP_TMR_RES)) - 1; - unsigned int dack_re = fls(core_clk / 5000) - 1; /* 200us */ - unsigned int tstamp_re = fls(core_clk / 1000); /* 1ms, at least */ - unsigned int tps = core_clk >> tre; - - t3_write_reg(adap, A_TP_TIMER_RESOLUTION, V_TIMERRESOLUTION(tre) | - V_DELAYEDACKRESOLUTION(dack_re) | - V_TIMESTAMPRESOLUTION(tstamp_re)); - t3_write_reg(adap, A_TP_DACK_TIMER, - (core_clk >> dack_re) / (1000 / TP_DACK_TIMER)); - t3_write_reg(adap, A_TP_TCP_BACKOFF_REG0, 0x3020100); - t3_write_reg(adap, A_TP_TCP_BACKOFF_REG1, 0x7060504); - t3_write_reg(adap, A_TP_TCP_BACKOFF_REG2, 0xb0a0908); - t3_write_reg(adap, A_TP_TCP_BACKOFF_REG3, 0xf0e0d0c); - t3_write_reg(adap, A_TP_SHIFT_CNT, V_SYNSHIFTMAX(6) | - V_RXTSHIFTMAXR1(4) | V_RXTSHIFTMAXR2(15) | - V_PERSHIFTBACKOFFMAX(8) | V_PERSHIFTMAX(8) | - V_KEEPALIVEMAX(9)); - -#define SECONDS * tps - - t3_write_reg(adap, A_TP_MSL, adap->params.rev > 0 ? 0 : 2 SECONDS); - t3_write_reg(adap, A_TP_RXT_MIN, tps / (1000 / TP_RTO_MIN)); - t3_write_reg(adap, A_TP_RXT_MAX, 64 SECONDS); - t3_write_reg(adap, A_TP_PERS_MIN, 5 SECONDS); - t3_write_reg(adap, A_TP_PERS_MAX, 64 SECONDS); - t3_write_reg(adap, A_TP_KEEP_IDLE, 7200 SECONDS); - t3_write_reg(adap, A_TP_KEEP_INTVL, 75 SECONDS); - t3_write_reg(adap, A_TP_INIT_SRTT, 3 SECONDS); - t3_write_reg(adap, A_TP_FINWAIT2_TIMER, 600 SECONDS); - -#undef SECONDS -} - -/** - * t3_tp_set_coalescing_size - set receive coalescing size - * @adap: the adapter - * @size: the receive coalescing size - * @psh: whether a set PSH bit should deliver coalesced data - * - * Set the receive coalescing size and PSH bit handling. - */ -static int t3_tp_set_coalescing_size(struct adapter *adap, - unsigned int size, int psh) -{ - u32 val; - - if (size > MAX_RX_COALESCING_LEN) - return -EINVAL; - - val = t3_read_reg(adap, A_TP_PARA_REG3); - val &= ~(F_RXCOALESCEENABLE | F_RXCOALESCEPSHEN); - - if (size) { - 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)); - } - t3_write_reg(adap, A_TP_PARA_REG3, val); - return 0; -} - -/** - * t3_tp_set_max_rxsize - set the max receive size - * @adap: the adapter - * @size: the max receive size - * - * Set TP's max receive size. This is the limit that applies when - * receive coalescing is disabled. - */ -static void t3_tp_set_max_rxsize(struct adapter *adap, unsigned int size) -{ - t3_write_reg(adap, A_TP_PARA_REG7, - V_PMMAXXFERLEN0(size) | V_PMMAXXFERLEN1(size)); -} - -static void init_mtus(unsigned short mtus[]) -{ - /* - * See draft-mathis-plpmtud-00.txt for the values. The min is 88 so - * it can accommodate max size TCP/IP headers when SACK and timestamps - * are enabled and still have at least 8 bytes of payload. - */ - mtus[0] = 88; - mtus[1] = 88; - mtus[2] = 256; - mtus[3] = 512; - mtus[4] = 576; - mtus[5] = 1024; - mtus[6] = 1280; - mtus[7] = 1492; - mtus[8] = 1500; - mtus[9] = 2002; - mtus[10] = 2048; - mtus[11] = 4096; - mtus[12] = 4352; - mtus[13] = 8192; - mtus[14] = 9000; - mtus[15] = 9600; -} - -/* - * Initial congestion control parameters. - */ -static void init_cong_ctrl(unsigned short *a, unsigned short *b) -{ - a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1; - a[9] = 2; - a[10] = 3; - a[11] = 4; - a[12] = 5; - a[13] = 6; - a[14] = 7; - a[15] = 8; - a[16] = 9; - a[17] = 10; - a[18] = 14; - a[19] = 17; - a[20] = 21; - a[21] = 25; - a[22] = 30; - a[23] = 35; - a[24] = 45; - a[25] = 60; - a[26] = 80; - a[27] = 100; - a[28] = 200; - a[29] = 300; - a[30] = 400; - a[31] = 500; - - b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0; - b[9] = b[10] = 1; - b[11] = b[12] = 2; - b[13] = b[14] = b[15] = b[16] = 3; - b[17] = b[18] = b[19] = b[20] = b[21] = 4; - b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5; - b[28] = b[29] = 6; - b[30] = b[31] = 7; -} - -/* The minimum additive increment value for the congestion control table */ -#define CC_MIN_INCR 2U - -/** - * t3_load_mtus - write the MTU and congestion control HW tables - * @adap: the adapter - * @mtus: the unrestricted values for the MTU table - * @alphs: the values for the congestion control alpha parameter - * @beta: the values for the congestion control beta parameter - * @mtu_cap: the maximum permitted effective MTU - * - * Write the MTU table with the supplied MTUs capping each at &mtu_cap. - * Update the high-speed congestion control table with the supplied alpha, - * beta, and MTUs. - */ -void t3_load_mtus(struct adapter *adap, unsigned short mtus[NMTUS], - unsigned short alpha[NCCTRL_WIN], - unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap) -{ - static const unsigned int avg_pkts[NCCTRL_WIN] = { - 2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640, - 896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480, - 28672, 40960, 57344, 81920, 114688, 163840, 229376 - }; - - unsigned int i, w; - - for (i = 0; i < NMTUS; ++i) { - unsigned int mtu = min(mtus[i], mtu_cap); - unsigned int log2 = fls(mtu); - - if (!(mtu & ((1 << log2) >> 2))) /* round */ - log2--; - t3_write_reg(adap, A_TP_MTU_TABLE, - (i << 24) | (log2 << 16) | mtu); - - for (w = 0; w < NCCTRL_WIN; ++w) { - unsigned int inc; - - inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w], - CC_MIN_INCR); - - t3_write_reg(adap, A_TP_CCTRL_TABLE, (i << 21) | - (w << 16) | (beta[w] << 13) | inc); - } - } -} - -/** - * t3_tp_get_mib_stats - read TP's MIB counters - * @adap: the adapter - * @tps: holds the returned counter values - * - * Returns the values of TP's MIB counters. - */ -void t3_tp_get_mib_stats(struct adapter *adap, struct tp_mib_stats *tps) -{ - t3_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_RDATA, (u32 *) tps, - sizeof(*tps) / sizeof(u32), 0); -} - -#define ulp_region(adap, name, start, len) \ - t3_write_reg((adap), A_ULPRX_ ## name ## _LLIMIT, (start)); \ - t3_write_reg((adap), A_ULPRX_ ## name ## _ULIMIT, \ - (start) + (len) - 1); \ - start += len - -#define ulptx_region(adap, name, start, len) \ - t3_write_reg((adap), A_ULPTX_ ## name ## _LLIMIT, (start)); \ - t3_write_reg((adap), A_ULPTX_ ## name ## _ULIMIT, \ - (start) + (len) - 1) - -static void ulp_config(struct adapter *adap, const struct tp_params *p) -{ - unsigned int m = p->chan_rx_size; - - ulp_region(adap, ISCSI, m, p->chan_rx_size / 8); - ulp_region(adap, TDDP, m, p->chan_rx_size / 8); - ulptx_region(adap, TPT, m, p->chan_rx_size / 4); - ulp_region(adap, STAG, m, p->chan_rx_size / 4); - ulp_region(adap, RQ, m, p->chan_rx_size / 4); - ulptx_region(adap, PBL, m, p->chan_rx_size / 4); - 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(struct adapter *adap, const u8 *data) -{ - int i; - const __be32 *buf = (const __be32 *)data; - - for (i = 0; i < PROTO_SRAM_LINES; i++) { - t3_write_reg(adap, A_TP_EMBED_OP_FIELD5, be32_to_cpu(*buf++)); - t3_write_reg(adap, A_TP_EMBED_OP_FIELD4, be32_to_cpu(*buf++)); - t3_write_reg(adap, A_TP_EMBED_OP_FIELD3, be32_to_cpu(*buf++)); - t3_write_reg(adap, A_TP_EMBED_OP_FIELD2, be32_to_cpu(*buf++)); - t3_write_reg(adap, A_TP_EMBED_OP_FIELD1, be32_to_cpu(*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; - } - t3_write_reg(adap, A_TP_EMBED_OP_FIELD0, 0); - - return 0; -} - -void t3_config_trace_filter(struct adapter *adapter, - const struct trace_params *tp, int filter_index, - int invert, int enable) -{ - u32 addr, key[4], mask[4]; - - key[0] = tp->sport | (tp->sip << 16); - key[1] = (tp->sip >> 16) | (tp->dport << 16); - key[2] = tp->dip; - key[3] = tp->proto | (tp->vlan << 8) | (tp->intf << 20); - - mask[0] = tp->sport_mask | (tp->sip_mask << 16); - mask[1] = (tp->sip_mask >> 16) | (tp->dport_mask << 16); - mask[2] = tp->dip_mask; - mask[3] = tp->proto_mask | (tp->vlan_mask << 8) | (tp->intf_mask << 20); - - if (invert) - key[3] |= (1 << 29); - if (enable) - key[3] |= (1 << 28); - - addr = filter_index ? A_TP_RX_TRC_KEY0 : A_TP_TX_TRC_KEY0; - tp_wr_indirect(adapter, addr++, key[0]); - tp_wr_indirect(adapter, addr++, mask[0]); - tp_wr_indirect(adapter, addr++, key[1]); - tp_wr_indirect(adapter, addr++, mask[1]); - tp_wr_indirect(adapter, addr++, key[2]); - tp_wr_indirect(adapter, addr++, mask[2]); - tp_wr_indirect(adapter, addr++, key[3]); - tp_wr_indirect(adapter, addr, mask[3]); - t3_read_reg(adapter, A_TP_PIO_DATA); -} - -/** - * t3_config_sched - configure a HW traffic scheduler - * @adap: the adapter - * @kbps: target rate in Kbps - * @sched: the scheduler index - * - * Configure a HW scheduler for the target rate - */ -int t3_config_sched(struct adapter *adap, unsigned int kbps, int sched) -{ - unsigned int v, tps, cpt, bpt, delta, mindelta = ~0; - unsigned int clk = adap->params.vpd.cclk * 1000; - unsigned int selected_cpt = 0, selected_bpt = 0; - - if (kbps > 0) { - kbps *= 125; /* -> bytes */ - for (cpt = 1; cpt <= 255; cpt++) { - tps = clk / cpt; - bpt = (kbps + tps / 2) / tps; - if (bpt > 0 && bpt <= 255) { - v = bpt * tps; - delta = v >= kbps ? v - kbps : kbps - v; - if (delta <= mindelta) { - mindelta = delta; - selected_cpt = cpt; - selected_bpt = bpt; - } - } else if (selected_cpt) - break; - } - if (!selected_cpt) - return -EINVAL; - } - t3_write_reg(adap, A_TP_TM_PIO_ADDR, - A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2); - v = t3_read_reg(adap, A_TP_TM_PIO_DATA); - if (sched & 1) - v = (v & 0xffff) | (selected_cpt << 16) | (selected_bpt << 24); - else - v = (v & 0xffff0000) | selected_cpt | (selected_bpt << 8); - t3_write_reg(adap, A_TP_TM_PIO_DATA, v); - return 0; -} - -static int tp_init(struct adapter *adap, const struct tp_params *p) -{ - int busy = 0; - - tp_config(adap, p); - t3_set_vlan_accel(adap, 3, 0); - - if (is_offload(adap)) { - tp_set_timers(adap, adap->params.vpd.cclk * 1000); - t3_write_reg(adap, A_TP_RESET, F_FLSTINITENABLE); - busy = t3_wait_op_done(adap, A_TP_RESET, F_FLSTINITENABLE, - 0, 1000, 5); - if (busy) - CH_ERR(adap, "TP initialization timed out\n"); - } - - if (!busy) - t3_write_reg(adap, A_TP_RESET, F_TPRESET); - return busy; -} - -/* - * Perform the bits of HW initialization that are dependent on the Tx - * channels being used. - */ -static void chan_init_hw(struct adapter *adap, unsigned int chan_map) -{ - int i; - - 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_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, - V_D1_WEIGHT(16) | V_D0_WEIGHT(16)); - t3_write_reg(adap, A_MPS_CFG, F_TPTXPORT0EN | F_TPTXPORT1EN | - F_TPRXPORTEN | F_PORT0ACTIVE | F_PORT1ACTIVE | - F_ENFORCEPKT); - t3_write_reg(adap, A_PM1_TX_CFG, 0x80008000); - t3_set_reg_field(adap, A_TP_PC_CONFIG, 0, F_TXTOSQUEUEMAPMODE); - t3_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP, - V_TX_MOD_QUEUE_REQ_MAP(0xaa)); - for (i = 0; i < 16; i++) - t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, - (i << 16) | 0x1010); - } -} - -static int calibrate_xgm(struct adapter *adapter) -{ - if (uses_xaui(adapter)) { - unsigned int v, i; - - for (i = 0; i < 5; ++i) { - t3_write_reg(adapter, A_XGM_XAUI_IMP, 0); - t3_read_reg(adapter, A_XGM_XAUI_IMP); - 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, - V_XAUIIMP(G_CALIMP(v) >> 2)); - return 0; - } - } - CH_ERR(adapter, "MAC calibration failed\n"); - return -1; - } else { - t3_write_reg(adapter, A_XGM_RGMII_IMP, - V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3)); - t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE, - F_XGM_IMPSETUPDATE); - } - return 0; -} - -static void calibrate_xgm_t3b(struct adapter *adapter) -{ - if (!uses_xaui(adapter)) { - t3_write_reg(adapter, A_XGM_RGMII_IMP, F_CALRESET | - F_CALUPDATE | V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3)); - t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALRESET, 0); - t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0, - F_XGM_IMPSETUPDATE); - t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE, - 0); - t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALUPDATE, 0); - t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0, F_CALUPDATE); - } -} - -struct mc7_timing_params { - unsigned char ActToPreDly; - unsigned char ActToRdWrDly; - unsigned char PreCyc; - unsigned char RefCyc[5]; - unsigned char BkCyc; - unsigned char WrToRdDly; - unsigned char RdToWrDly; -}; - -/* - * Write a value to a register and check that the write completed. These - * writes normally complete in a cycle or two, so one read should suffice. - * The very first read exists to flush the posted write to the device. - */ -static int wrreg_wait(struct adapter *adapter, unsigned int addr, u32 val) -{ - t3_write_reg(adapter, addr, val); - t3_read_reg(adapter, addr); /* flush */ - if (!(t3_read_reg(adapter, addr) & F_BUSY)) - return 0; - CH_ERR(adapter, "write to MC7 register 0x%x timed out\n", addr); - return -EIO; -} - -static int mc7_init(struct mc7 *mc7, unsigned int mc7_clock, int mem_type) -{ - static const unsigned int mc7_mode[] = { - 0x632, 0x642, 0x652, 0x432, 0x442 - }; - static const struct mc7_timing_params mc7_timings[] = { - {12, 3, 4, {20, 28, 34, 52, 0}, 15, 6, 4}, - {12, 4, 5, {20, 28, 34, 52, 0}, 16, 7, 4}, - {12, 5, 6, {20, 28, 34, 52, 0}, 17, 8, 4}, - {9, 3, 4, {15, 21, 26, 39, 0}, 12, 6, 4}, - {9, 4, 5, {15, 21, 26, 39, 0}, 13, 7, 4} - }; - - u32 val; - unsigned int width, density, slow, attempts; - struct adapter *adapter = mc7->adapter; - const struct mc7_timing_params *p = &mc7_timings[mem_type]; - - if (!mc7->size) - return 0; - - val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); - slow = val & F_SLOW; - width = G_WIDTH(val); - density = G_DEN(val); - - t3_write_reg(adapter, mc7->offset + A_MC7_CFG, val | F_IFEN); - val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); /* flush */ - msleep(1); - - if (!slow) { - t3_write_reg(adapter, mc7->offset + A_MC7_CAL, F_SGL_CAL_EN); - t3_read_reg(adapter, mc7->offset + A_MC7_CAL); - 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", - mc7->name); - goto out_fail; - } - } - - t3_write_reg(adapter, mc7->offset + A_MC7_PARM, - V_ACTTOPREDLY(p->ActToPreDly) | - V_ACTTORDWRDLY(p->ActToRdWrDly) | V_PRECYC(p->PreCyc) | - V_REFCYC(p->RefCyc[density]) | V_BKCYC(p->BkCyc) | - V_WRTORDDLY(p->WrToRdDly) | V_RDTOWRDLY(p->RdToWrDly)); - - t3_write_reg(adapter, mc7->offset + A_MC7_CFG, - val | F_CLKEN | F_TERM150); - t3_read_reg(adapter, mc7->offset + A_MC7_CFG); /* flush */ - - if (!slow) - t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLENB, - F_DLLENB); - udelay(1); - - val = slow ? 3 : 6; - if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) || - wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE2, 0) || - wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE3, 0) || - wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val)) - goto out_fail; - - if (!slow) { - t3_write_reg(adapter, mc7->offset + A_MC7_MODE, 0x100); - t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLRST, 0); - udelay(5); - } - - if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) || - wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) || - wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) || - wrreg_wait(adapter, mc7->offset + A_MC7_MODE, - mc7_mode[mem_type]) || - wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val | 0x380) || - wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val)) - goto out_fail; - - /* clock value is in KHz */ - mc7_clock = mc7_clock * 7812 + mc7_clock / 2; /* ns */ - mc7_clock /= 1000000; /* KHz->MHz, ns->us */ - - t3_write_reg(adapter, mc7->offset + A_MC7_REF, - F_PERREFEN | V_PREREFDIV(mc7_clock)); - t3_read_reg(adapter, mc7->offset + A_MC7_REF); /* flush */ - - t3_write_reg(adapter, mc7->offset + A_MC7_ECC, F_ECCGENEN | F_ECCCHKEN); - t3_write_reg(adapter, mc7->offset + A_MC7_BIST_DATA, 0); - t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_BEG, 0); - t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_END, - (mc7->size << width) - 1); - t3_write_reg(adapter, mc7->offset + A_MC7_BIST_OP, V_OP(1)); - t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP); /* flush */ - - attempts = 50; - do { - msleep(250); - val = t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP); - } while ((val & F_BUSY) && --attempts); - if (val & F_BUSY) { - CH_ERR(adapter, "%s MC7 BIST timed out\n", mc7->name); - goto out_fail; - } - - /* Enable normal memory accesses. */ - t3_set_reg_field(adapter, mc7->offset + A_MC7_CFG, 0, F_RDY); - return 0; - -out_fail: - return -1; -} - -static void config_pcie(struct adapter *adap) -{ - static const u16 ack_lat[4][6] = { - {237, 416, 559, 1071, 2095, 4143}, - {128, 217, 289, 545, 1057, 2081}, - {73, 118, 154, 282, 538, 1050}, - {67, 107, 86, 150, 278, 534} - }; - static const u16 rpl_tmr[4][6] = { - {711, 1248, 1677, 3213, 6285, 12429}, - {384, 651, 867, 1635, 3171, 6243}, - {219, 354, 462, 846, 1614, 3150}, - {201, 321, 258, 450, 834, 1602} - }; - - u16 val, devid; - unsigned int log2_width, pldsize; - unsigned int fst_trn_rx, fst_trn_tx, acklat, rpllmt; - - pci_read_config_word(adap->pdev, - adap->pdev->pcie_cap + PCI_EXP_DEVCTL, - &val); - pldsize = (val & PCI_EXP_DEVCTL_PAYLOAD) >> 5; - - pci_read_config_word(adap->pdev, 0x2, &devid); - if (devid == 0x37) { - pci_write_config_word(adap->pdev, - adap->pdev->pcie_cap + PCI_EXP_DEVCTL, - val & ~PCI_EXP_DEVCTL_READRQ & - ~PCI_EXP_DEVCTL_PAYLOAD); - pldsize = 0; - } - - pci_read_config_word(adap->pdev, adap->pdev->pcie_cap + PCI_EXP_LNKCTL, - &val); - - fst_trn_tx = G_NUMFSTTRNSEQ(t3_read_reg(adap, A_PCIE_PEX_CTRL0)); - fst_trn_rx = adap->params.rev == 0 ? fst_trn_tx : - G_NUMFSTTRNSEQRX(t3_read_reg(adap, A_PCIE_MODE)); - log2_width = fls(adap->params.pci.width) - 1; - acklat = ack_lat[log2_width][pldsize]; - if (val & 1) /* check LOsEnable */ - acklat += fst_trn_tx * 4; - rpllmt = rpl_tmr[log2_width][pldsize] + fst_trn_rx * 4; - - if (adap->params.rev == 0) - t3_set_reg_field(adap, A_PCIE_PEX_CTRL1, - V_T3A_ACKLAT(M_T3A_ACKLAT), - V_T3A_ACKLAT(acklat)); - else - t3_set_reg_field(adap, A_PCIE_PEX_CTRL1, V_ACKLAT(M_ACKLAT), - V_ACKLAT(acklat)); - - t3_set_reg_field(adap, A_PCIE_PEX_CTRL0, V_REPLAYLMT(M_REPLAYLMT), - V_REPLAYLMT(rpllmt)); - - t3_write_reg(adap, A_PCIE_PEX_ERR, 0xffffffff); - t3_set_reg_field(adap, A_PCIE_CFG, 0, - F_ENABLELINKDWNDRST | F_ENABLELINKDOWNRST | - F_PCIE_DMASTOPEN | F_PCIE_CLIDECEN); -} - -/* - * Initialize and configure T3 HW modules. This performs the - * initialization steps that need to be done once after a card is reset. - * MAC and PHY initialization is handled separarely whenever a port is enabled. - * - * fw_params are passed to FW and their value is platform dependent. Only the - * top 8 bits are available for use, the rest must be 0. - */ -int t3_init_hw(struct adapter *adapter, u32 fw_params) -{ - int err = -EIO, attempts, i; - const struct vpd_params *vpd = &adapter->params.vpd; - - if (adapter->params.rev > 0) - calibrate_xgm_t3b(adapter); - else if (calibrate_xgm(adapter)) - goto out_err; - - if (vpd->mclk) { - partition_mem(adapter, &adapter->params.tp); - - if (mc7_init(&adapter->pmrx, vpd->mclk, vpd->mem_timing) || - mc7_init(&adapter->pmtx, vpd->mclk, vpd->mem_timing) || - mc7_init(&adapter->cm, vpd->mclk, vpd->mem_timing) || - t3_mc5_init(&adapter->mc5, adapter->params.mc5.nservers, - adapter->params.mc5.nfilters, - adapter->params.mc5.nroutes)) - goto out_err; - - for (i = 0; i < 32; i++) - if (clear_sge_ctxt(adapter, i, F_CQ)) - goto out_err; - } - - if (tp_init(adapter, &adapter->params.tp)) - goto out_err; - - t3_tp_set_coalescing_size(adapter, - min(adapter->params.sge.max_pkt_size, - MAX_RX_COALESCING_LEN), 1); - t3_tp_set_max_rxsize(adapter, - min(adapter->params.sge.max_pkt_size, 16384U)); - ulp_config(adapter, &adapter->params.tp); - - if (is_pcie(adapter)) - config_pcie(adapter); - else - t3_set_reg_field(adapter, A_PCIX_CFG, 0, - F_DMASTOPEN | F_CLIDECEN); - - if (adapter->params.rev == T3_REV_C) - t3_set_reg_field(adapter, A_ULPTX_CONFIG, 0, - F_CFG_CQE_SOP_MASK); - - t3_write_reg(adapter, A_PM1_RX_CFG, 0xffffffff); - t3_write_reg(adapter, A_PM1_RX_MODE, 0); - t3_write_reg(adapter, A_PM1_TX_MODE, 0); - chan_init_hw(adapter, adapter->params.chan_map); - t3_sge_init(adapter, &adapter->params.sge); - t3_set_reg_field(adapter, A_PL_RST, 0, F_FATALPERREN); - - t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW, calc_gpio_intr(adapter)); - - t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, vpd->uclk | fw_params); - t3_write_reg(adapter, A_CIM_BOOT_CFG, - V_BOOTADDR(FW_FLASH_BOOT_ADDR >> 2)); - t3_read_reg(adapter, A_CIM_BOOT_CFG); /* flush */ - - attempts = 100; - do { /* wait for uP to initialize */ - msleep(20); - } while (t3_read_reg(adapter, A_CIM_HOST_ACC_DATA) && --attempts); - if (!attempts) { - CH_ERR(adapter, "uP initialization timed out\n"); - goto out_err; - } - - err = 0; -out_err: - return err; -} - -/** - * get_pci_mode - determine a card's PCI mode - * @adapter: the adapter - * @p: where to store the PCI settings - * - * Determines a card's PCI mode and associated parameters, such as speed - * and width. - */ -static void get_pci_mode(struct adapter *adapter, struct pci_params *p) -{ - static unsigned short speed_map[] = { 33, 66, 100, 133 }; - u32 pci_mode, pcie_cap; - - pcie_cap = pci_pcie_cap(adapter->pdev); - if (pcie_cap) { - u16 val; - - p->variant = PCI_VARIANT_PCIE; - pci_read_config_word(adapter->pdev, pcie_cap + PCI_EXP_LNKSTA, - &val); - p->width = (val >> 4) & 0x3f; - return; - } - - pci_mode = t3_read_reg(adapter, A_PCIX_MODE); - p->speed = speed_map[G_PCLKRANGE(pci_mode)]; - p->width = (pci_mode & F_64BIT) ? 64 : 32; - pci_mode = G_PCIXINITPAT(pci_mode); - if (pci_mode == 0) - p->variant = PCI_VARIANT_PCI; - else if (pci_mode < 4) - p->variant = PCI_VARIANT_PCIX_MODE1_PARITY; - else if (pci_mode < 8) - p->variant = PCI_VARIANT_PCIX_MODE1_ECC; - else - p->variant = PCI_VARIANT_PCIX_266_MODE2; -} - -/** - * init_link_config - initialize a link's SW state - * @lc: structure holding the link state - * @ai: information about the current card - * - * Initializes the SW state maintained for each link, including the link's - * capabilities and default speed/duplex/flow-control/autonegotiation - * settings. - */ -static void init_link_config(struct link_config *lc, unsigned int caps) -{ - lc->supported = caps; - lc->requested_speed = lc->speed = SPEED_INVALID; - lc->requested_duplex = lc->duplex = DUPLEX_INVALID; - lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX; - if (lc->supported & SUPPORTED_Autoneg) { - lc->advertising = lc->supported; - lc->autoneg = AUTONEG_ENABLE; - lc->requested_fc |= PAUSE_AUTONEG; - } else { - lc->advertising = 0; - lc->autoneg = AUTONEG_DISABLE; - } -} - -/** - * mc7_calc_size - calculate MC7 memory size - * @cfg: the MC7 configuration - * - * Calculates the size of an MC7 memory in bytes from the value of its - * configuration register. - */ -static unsigned int mc7_calc_size(u32 cfg) -{ - unsigned int width = G_WIDTH(cfg); - unsigned int banks = !!(cfg & F_BKS) + 1; - unsigned int org = !!(cfg & F_ORG) + 1; - unsigned int density = G_DEN(cfg); - unsigned int MBs = ((256 << density) * banks) / (org << width); - - return MBs << 20; -} - -static void mc7_prep(struct adapter *adapter, struct mc7 *mc7, - unsigned int base_addr, const char *name) -{ - u32 cfg; - - mc7->adapter = adapter; - mc7->name = name; - mc7->offset = base_addr - MC7_PMRX_BASE_ADDR; - cfg = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); - mc7->size = G_DEN(cfg) == M_DEN ? 0 : mc7_calc_size(cfg); - mc7->width = G_WIDTH(cfg); -} - -static void mac_prep(struct cmac *mac, struct adapter *adapter, int index) -{ - u16 devid; - - mac->adapter = adapter; - pci_read_config_word(adapter->pdev, 0x2, &devid); - - if (devid == 0x37 && !adapter->params.vpd.xauicfg[1]) - index = 0; - 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, - is_10G(adapter) ? 0x2901c04 : 0x2301c04); - t3_set_reg_field(adapter, A_XGM_PORT_CFG + mac->offset, - F_ENRGMII, 0); - } -} - -static void early_hw_init(struct adapter *adapter, - const struct adapter_info *ai) -{ - u32 val = V_PORTSPEED(is_10G(adapter) ? 3 : 2); - - mi1_init(adapter, ai); - t3_write_reg(adapter, A_I2C_CFG, /* set for 80KHz */ - V_I2C_CLKDIV(adapter->params.vpd.cclk / 80 - 1)); - t3_write_reg(adapter, A_T3DBG_GPIO_EN, - ai->gpio_out | F_GPIO0_OEN | F_GPIO0_OUT_VAL); - t3_write_reg(adapter, A_MC5_DB_SERVER_INDEX, 0); - t3_write_reg(adapter, A_SG_OCO_BASE, V_BASE1(0xfff)); - - if (adapter->params.rev == 0 || !uses_xaui(adapter)) - val |= F_ENRGMII; - - /* Enable MAC clocks so we can access the registers */ - t3_write_reg(adapter, A_XGM_PORT_CFG, val); - t3_read_reg(adapter, A_XGM_PORT_CFG); - - val |= F_CLKDIVRESET_; - t3_write_reg(adapter, A_XGM_PORT_CFG, val); - t3_read_reg(adapter, A_XGM_PORT_CFG); - t3_write_reg(adapter, XGM_REG(A_XGM_PORT_CFG, 1), val); - t3_read_reg(adapter, A_XGM_PORT_CFG); -} - -/* - * Reset the adapter. - * Older PCIe cards lose their config space during reset, PCI-X - * ones don't. - */ -int t3_reset_adapter(struct adapter *adapter) -{ - int i, save_and_restore_pcie = - adapter->params.rev < T3_REV_B2 && is_pcie(adapter); - uint16_t devid = 0; - - if (save_and_restore_pcie) - pci_save_state(adapter->pdev); - t3_write_reg(adapter, A_PL_RST, F_CRSTWRM | F_CRSTWRMMODE); - - /* - * Delay. Give Some time to device to reset fully. - * XXX The delay time should be modified. - */ - for (i = 0; i < 10; i++) { - msleep(50); - pci_read_config_word(adapter->pdev, 0x00, &devid); - if (devid == 0x1425) - break; - } - - if (devid != 0x1425) - return -1; - - if (save_and_restore_pcie) - pci_restore_state(adapter->pdev); - return 0; -} - -static int init_parity(struct adapter *adap) -{ - int i, err, addr; - - if (t3_read_reg(adap, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) - return -EBUSY; - - for (err = i = 0; !err && i < 16; i++) - err = clear_sge_ctxt(adap, i, F_EGRESS); - for (i = 0xfff0; !err && i <= 0xffff; i++) - err = clear_sge_ctxt(adap, i, F_EGRESS); - for (i = 0; !err && i < SGE_QSETS; i++) - err = clear_sge_ctxt(adap, i, F_RESPONSEQ); - if (err) - return err; - - t3_write_reg(adap, A_CIM_IBQ_DBG_DATA, 0); - for (i = 0; i < 4; i++) - for (addr = 0; addr <= M_IBQDBGADDR; addr++) { - t3_write_reg(adap, A_CIM_IBQ_DBG_CFG, F_IBQDBGEN | - F_IBQDBGWR | V_IBQDBGQID(i) | - V_IBQDBGADDR(addr)); - err = t3_wait_op_done(adap, A_CIM_IBQ_DBG_CFG, - F_IBQDBGBUSY, 0, 2, 1); - if (err) - return err; - } - return 0; -} - -/* - * Initialize adapter SW state for the various HW modules, set initial values - * for some adapter tunables, take PHYs out of reset, and initialize the MDIO - * interface. - */ -int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai, - int reset) -{ - int ret; - unsigned int i, j = -1; - - get_pci_mode(adapter, &adapter->params.pci); - - adapter->params.info = ai; - 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); - /* - * We used to only run the "adapter check task" once a second if - * we had PHYs which didn't support interrupts (we would check - * their link status once a second). Now we check other conditions - * in that routine which could potentially impose a very high - * interrupt load on the system. As such, we now always scan the - * adapter state once a second ... - */ - adapter->params.linkpoll_period = 10; - adapter->params.stats_update_period = is_10G(adapter) ? - MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10); - adapter->params.pci.vpd_cap_addr = - pci_find_capability(adapter->pdev, PCI_CAP_ID_VPD); - ret = get_vpd_params(adapter, &adapter->params.vpd); - if (ret < 0) - return ret; - - if (reset && t3_reset_adapter(adapter)) - return -1; - - t3_sge_prep(adapter, &adapter->params.sge); - - if (adapter->params.vpd.mclk) { - struct tp_params *p = &adapter->params.tp; - - mc7_prep(adapter, &adapter->pmrx, MC7_PMRX_BASE_ADDR, "PMRX"); - mc7_prep(adapter, &adapter->pmtx, MC7_PMTX_BASE_ADDR, "PMTX"); - mc7_prep(adapter, &adapter->cm, MC7_CM_BASE_ADDR, "CM"); - - 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); - p->chan_rx_size = p->pmrx_size / 2; /* only 1 Rx channel */ - p->chan_tx_size = p->pmtx_size / p->nchan; - p->rx_pg_size = 64 * 1024; - p->tx_pg_size = is_10G(adapter) ? 64 * 1024 : 16 * 1024; - p->rx_num_pgs = pm_num_pages(p->chan_rx_size, p->rx_pg_size); - 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; - } - - adapter->params.offload = t3_mc7_size(&adapter->pmrx) && - t3_mc7_size(&adapter->pmtx) && - t3_mc7_size(&adapter->cm); - - if (is_offload(adapter)) { - adapter->params.mc5.nservers = DEFAULT_NSERVERS; - adapter->params.mc5.nfilters = adapter->params.rev > 0 ? - DEFAULT_NFILTERS : 0; - adapter->params.mc5.nroutes = 0; - t3_mc5_prep(adapter, &adapter->mc5, MC5_MODE_144_BIT); - - init_mtus(adapter->params.mtus); - init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd); - } - - early_hw_init(adapter, ai); - ret = init_parity(adapter); - if (ret) - return ret; - - for_each_port(adapter, i) { - u8 hw_addr[6]; - const struct port_type_info *pti; - struct port_info *p = adap2pinfo(adapter, i); - - while (!adapter->params.vpd.port_type[++j]) - ; - - pti = &port_types[adapter->params.vpd.port_type[j]]; - if (!pti->phy_prep) { - CH_ALERT(adapter, "Invalid port type index %d\n", - adapter->params.vpd.port_type[j]); - return -EINVAL; - } - - p->phy.mdio.dev = adapter->port[i]; - ret = pti->phy_prep(&p->phy, adapter, ai->phy_base_addr + j, - ai->mdio_ops); - if (ret) - return ret; - mac_prep(&p->mac, adapter, j); - - /* - * The VPD EEPROM stores the base Ethernet address for the - * card. A port's address is derived from the base by adding - * the port's index to the base's low octet. - */ - memcpy(hw_addr, adapter->params.vpd.eth_base, 5); - hw_addr[5] = adapter->params.vpd.eth_base[5] + i; - - memcpy(adapter->port[i]->dev_addr, hw_addr, - ETH_ALEN); - memcpy(adapter->port[i]->perm_addr, hw_addr, - ETH_ALEN); - init_link_config(&p->link_config, p->phy.caps); - p->phy.ops->power_down(&p->phy, 1); - - /* - * If the PHY doesn't support interrupts for link status - * changes, schedule a scan of the adapter links at least - * once a second. - */ - if (!(p->phy.caps & SUPPORTED_IRQ) && - adapter->params.linkpoll_period > 10) - adapter->params.linkpoll_period = 10; - } - - return 0; -} - -void t3_led_ready(struct adapter *adapter) -{ - t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, - F_GPIO0_OUT_VAL); -} - -int t3_replay_prep_adapter(struct adapter *adapter) -{ - const struct adapter_info *ai = adapter->params.info; - unsigned int i, j = -1; - int ret; - - early_hw_init(adapter, ai); - ret = init_parity(adapter); - if (ret) - return ret; - - for_each_port(adapter, i) { - const struct port_type_info *pti; - struct port_info *p = adap2pinfo(adapter, i); - - while (!adapter->params.vpd.port_type[++j]) - ; - - pti = &port_types[adapter->params.vpd.port_type[j]]; - ret = pti->phy_prep(&p->phy, adapter, p->phy.mdio.prtad, NULL); - if (ret) - return ret; - p->phy.ops->power_down(&p->phy, 1); - } - -return 0; -} - diff --git a/drivers/net/cxgb3/t3cdev.h b/drivers/net/cxgb3/t3cdev.h deleted file mode 100644 index 705713b56636..000000000000 --- a/drivers/net/cxgb3/t3cdev.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2006-2008 Chelsio Communications. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _T3CDEV_H_ -#define _T3CDEV_H_ - -#include -#include -#include -#include -#include -#include - -#define T3CNAMSIZ 16 - -struct cxgb3_client; - -enum t3ctype { - T3A = 0, - T3B, - T3C, -}; - -struct t3cdev { - char name[T3CNAMSIZ]; /* T3C device name */ - enum t3ctype type; - struct list_head ofld_dev_list; /* for list linking */ - struct net_device *lldev; /* LL dev associated with T3C messages */ - struct proc_dir_entry *proc_dir; /* root of proc dir for this T3C */ - int (*send)(struct t3cdev *dev, struct sk_buff *skb); - int (*recv)(struct t3cdev *dev, struct sk_buff **skb, int n); - int (*ctl)(struct t3cdev *dev, unsigned int req, void *data); - void (*neigh_update)(struct t3cdev *dev, struct neighbour *neigh); - void *priv; /* driver private data */ - void *l2opt; /* optional layer 2 data */ - void *l3opt; /* optional layer 3 data */ - void *l4opt; /* optional layer 4 data */ - void *ulp; /* ulp stuff */ - void *ulp_iscsi; /* ulp iscsi */ -}; - -#endif /* _T3CDEV_H_ */ diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h deleted file mode 100644 index 8bda06e366c8..000000000000 --- a/drivers/net/cxgb3/version.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -/* $Date: 2006/10/31 18:57:51 $ $RCSfile: version.h,v $ $Revision: 1.3 $ */ -#ifndef __CHELSIO_VERSION_H -#define __CHELSIO_VERSION_H -#define DRV_DESC "Chelsio T3 Network Driver" -#define DRV_NAME "cxgb3" -/* Driver version */ -#define DRV_VERSION "1.1.4-ko" - -/* Firmware version */ -#define FW_VERSION_MAJOR 7 -#define FW_VERSION_MINOR 10 -#define FW_VERSION_MICRO 0 -#endif /* __CHELSIO_VERSION_H */ diff --git a/drivers/net/cxgb3/vsc8211.c b/drivers/net/cxgb3/vsc8211.c deleted file mode 100644 index 4f9a1c2724f4..000000000000 --- a/drivers/net/cxgb3/vsc8211.c +++ /dev/null @@ -1,416 +0,0 @@ -/* - * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#include "common.h" - -/* VSC8211 PHY specific registers. */ -enum { - VSC8211_SIGDET_CTRL = 19, - VSC8211_EXT_CTRL = 23, - VSC8211_INTR_ENABLE = 25, - VSC8211_INTR_STATUS = 26, - VSC8211_LED_CTRL = 27, - VSC8211_AUX_CTRL_STAT = 28, - VSC8211_EXT_PAGE_AXS = 31, -}; - -enum { - VSC_INTR_RX_ERR = 1 << 0, - VSC_INTR_MS_ERR = 1 << 1, /* master/slave resolution error */ - VSC_INTR_CABLE = 1 << 2, /* cable impairment */ - VSC_INTR_FALSE_CARR = 1 << 3, /* false carrier */ - VSC_INTR_MEDIA_CHG = 1 << 4, /* AMS media change */ - VSC_INTR_RX_FIFO = 1 << 5, /* Rx FIFO over/underflow */ - VSC_INTR_TX_FIFO = 1 << 6, /* Tx FIFO over/underflow */ - VSC_INTR_DESCRAMBL = 1 << 7, /* descrambler lock-lost */ - VSC_INTR_SYMBOL_ERR = 1 << 8, /* symbol error */ - VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */ - VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */ - VSC_INTR_DPLX_CHG = 1 << 12, /* duplex change */ - VSC_INTR_LINK_CHG = 1 << 13, /* link change */ - VSC_INTR_SPD_CHG = 1 << 14, /* speed change */ - VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */ -}; - -enum { - VSC_CTRL_CLAUSE37_VIEW = 1 << 4, /* Switch to Clause 37 view */ - VSC_CTRL_MEDIA_MODE_HI = 0xf000 /* High part of media mode select */ -}; - -#define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \ - VSC_INTR_DPLX_CHG | VSC_INTR_SPD_CHG | \ - VSC_INTR_NEG_DONE) -#define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \ - VSC_INTR_ENABLE) - -/* PHY specific auxiliary control & status register fields */ -#define S_ACSR_ACTIPHY_TMR 0 -#define M_ACSR_ACTIPHY_TMR 0x3 -#define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR) - -#define S_ACSR_SPEED 3 -#define M_ACSR_SPEED 0x3 -#define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED) - -#define S_ACSR_DUPLEX 5 -#define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX) - -#define S_ACSR_ACTIPHY 6 -#define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY) - -/* - * Reset the PHY. This PHY completes reset immediately so we never wait. - */ -static int vsc8211_reset(struct cphy *cphy, int wait) -{ - return t3_phy_reset(cphy, MDIO_DEVAD_NONE, 0); -} - -static int vsc8211_intr_enable(struct cphy *cphy) -{ - return t3_mdio_write(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_ENABLE, - INTR_MASK); -} - -static int vsc8211_intr_disable(struct cphy *cphy) -{ - return t3_mdio_write(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_ENABLE, 0); -} - -static int vsc8211_intr_clear(struct cphy *cphy) -{ - u32 val; - - /* Clear PHY interrupts by reading the register. */ - return t3_mdio_read(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_STATUS, &val); -} - -static int vsc8211_autoneg_enable(struct cphy *cphy) -{ - return t3_mdio_change_bits(cphy, MDIO_DEVAD_NONE, MII_BMCR, - BMCR_PDOWN | BMCR_ISOLATE, - BMCR_ANENABLE | BMCR_ANRESTART); -} - -static int vsc8211_autoneg_restart(struct cphy *cphy) -{ - return t3_mdio_change_bits(cphy, MDIO_DEVAD_NONE, MII_BMCR, - BMCR_PDOWN | BMCR_ISOLATE, - BMCR_ANRESTART); -} - -static int vsc8211_get_link_status(struct cphy *cphy, int *link_ok, - int *speed, int *duplex, int *fc) -{ - unsigned int bmcr, status, lpa, adv; - int err, sp = -1, dplx = -1, pause = 0; - - err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMCR, &bmcr); - if (!err) - err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR, &status); - if (err) - return err; - - if (link_ok) { - /* - * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it - * once more to get the current link state. - */ - if (!(status & BMSR_LSTATUS)) - err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR, - &status); - if (err) - return err; - *link_ok = (status & BMSR_LSTATUS) != 0; - } - if (!(bmcr & BMCR_ANENABLE)) { - dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; - if (bmcr & BMCR_SPEED1000) - sp = SPEED_1000; - else if (bmcr & BMCR_SPEED100) - sp = SPEED_100; - else - sp = SPEED_10; - } else if (status & BMSR_ANEGCOMPLETE) { - err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, VSC8211_AUX_CTRL_STAT, - &status); - if (err) - return err; - - dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF; - sp = G_ACSR_SPEED(status); - if (sp == 0) - sp = SPEED_10; - else if (sp == 1) - sp = SPEED_100; - else - sp = SPEED_1000; - - if (fc && dplx == DUPLEX_FULL) { - err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_LPA, - &lpa); - if (!err) - err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, - MII_ADVERTISE, &adv); - if (err) - return err; - - if (lpa & adv & ADVERTISE_PAUSE_CAP) - pause = PAUSE_RX | PAUSE_TX; - else if ((lpa & ADVERTISE_PAUSE_CAP) && - (lpa & ADVERTISE_PAUSE_ASYM) && - (adv & ADVERTISE_PAUSE_ASYM)) - pause = PAUSE_TX; - else if ((lpa & ADVERTISE_PAUSE_ASYM) && - (adv & ADVERTISE_PAUSE_CAP)) - pause = PAUSE_RX; - } - } - if (speed) - *speed = sp; - if (duplex) - *duplex = dplx; - if (fc) - *fc = pause; - return 0; -} - -static int vsc8211_get_link_status_fiber(struct cphy *cphy, int *link_ok, - int *speed, int *duplex, int *fc) -{ - unsigned int bmcr, status, lpa, adv; - int err, sp = -1, dplx = -1, pause = 0; - - err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMCR, &bmcr); - if (!err) - err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR, &status); - if (err) - return err; - - if (link_ok) { - /* - * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it - * once more to get the current link state. - */ - if (!(status & BMSR_LSTATUS)) - err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR, - &status); - if (err) - return err; - *link_ok = (status & BMSR_LSTATUS) != 0; - } - if (!(bmcr & BMCR_ANENABLE)) { - dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; - if (bmcr & BMCR_SPEED1000) - sp = SPEED_1000; - else if (bmcr & BMCR_SPEED100) - sp = SPEED_100; - else - sp = SPEED_10; - } else if (status & BMSR_ANEGCOMPLETE) { - err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_LPA, &lpa); - if (!err) - err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_ADVERTISE, - &adv); - if (err) - return err; - - if (adv & lpa & ADVERTISE_1000XFULL) { - dplx = DUPLEX_FULL; - sp = SPEED_1000; - } else if (adv & lpa & ADVERTISE_1000XHALF) { - dplx = DUPLEX_HALF; - sp = SPEED_1000; - } - - if (fc && dplx == DUPLEX_FULL) { - if (lpa & adv & ADVERTISE_1000XPAUSE) - pause = PAUSE_RX | PAUSE_TX; - else if ((lpa & ADVERTISE_1000XPAUSE) && - (adv & lpa & ADVERTISE_1000XPSE_ASYM)) - pause = PAUSE_TX; - else if ((lpa & ADVERTISE_1000XPSE_ASYM) && - (adv & ADVERTISE_1000XPAUSE)) - pause = PAUSE_RX; - } - } - if (speed) - *speed = sp; - if (duplex) - *duplex = dplx; - if (fc) - *fc = pause; - return 0; -} - -#ifdef UNUSED -/* - * Enable/disable auto MDI/MDI-X in forced link speed mode. - */ -static int vsc8211_set_automdi(struct cphy *phy, int enable) -{ - int err; - - err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 0x52b5); - if (err) - return err; - - err = t3_mdio_write(phy, MDIO_DEVAD_NONE, 18, 0x12); - if (err) - return err; - - err = t3_mdio_write(phy, MDIO_DEVAD_NONE, 17, enable ? 0x2803 : 0x3003); - if (err) - return err; - - err = t3_mdio_write(phy, MDIO_DEVAD_NONE, 16, 0x87fa); - if (err) - return err; - - err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 0); - if (err) - return err; - - return 0; -} - -int vsc8211_set_speed_duplex(struct cphy *phy, int speed, int duplex) -{ - int err; - - err = t3_set_phy_speed_duplex(phy, speed, duplex); - if (!err) - err = vsc8211_set_automdi(phy, 1); - return err; -} -#endif /* UNUSED */ - -static int vsc8211_power_down(struct cphy *cphy, int enable) -{ - return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN, - enable ? BMCR_PDOWN : 0); -} - -static int vsc8211_intr_handler(struct cphy *cphy) -{ - unsigned int cause; - int err, cphy_cause = 0; - - err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_STATUS, &cause); - if (err) - return err; - - cause &= INTR_MASK; - if (cause & CFG_CHG_INTR_MASK) - cphy_cause |= cphy_cause_link_change; - if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO)) - cphy_cause |= cphy_cause_fifo_error; - return cphy_cause; -} - -static struct cphy_ops vsc8211_ops = { - .reset = vsc8211_reset, - .intr_enable = vsc8211_intr_enable, - .intr_disable = vsc8211_intr_disable, - .intr_clear = vsc8211_intr_clear, - .intr_handler = vsc8211_intr_handler, - .autoneg_enable = vsc8211_autoneg_enable, - .autoneg_restart = vsc8211_autoneg_restart, - .advertise = t3_phy_advertise, - .set_speed_duplex = t3_set_phy_speed_duplex, - .get_link_status = vsc8211_get_link_status, - .power_down = vsc8211_power_down, -}; - -static struct cphy_ops vsc8211_fiber_ops = { - .reset = vsc8211_reset, - .intr_enable = vsc8211_intr_enable, - .intr_disable = vsc8211_intr_disable, - .intr_clear = vsc8211_intr_clear, - .intr_handler = vsc8211_intr_handler, - .autoneg_enable = vsc8211_autoneg_enable, - .autoneg_restart = vsc8211_autoneg_restart, - .advertise = t3_phy_advertise_fiber, - .set_speed_duplex = t3_set_phy_speed_duplex, - .get_link_status = vsc8211_get_link_status_fiber, - .power_down = vsc8211_power_down, -}; - -int t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter, - int phy_addr, const struct mdio_ops *mdio_ops) -{ - int err; - unsigned int val; - - cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops, - SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full | - SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII | - SUPPORTED_TP | SUPPORTED_IRQ, "10/100/1000BASE-T"); - msleep(20); /* PHY needs ~10ms to start responding to MDIO */ - - err = t3_mdio_read(phy, MDIO_DEVAD_NONE, VSC8211_EXT_CTRL, &val); - if (err) - return err; - if (val & VSC_CTRL_MEDIA_MODE_HI) { - /* copper interface, just need to configure the LEDs */ - return t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_LED_CTRL, - 0x100); - } - - phy->caps = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | - SUPPORTED_MII | SUPPORTED_FIBRE | SUPPORTED_IRQ; - phy->desc = "1000BASE-X"; - phy->ops = &vsc8211_fiber_ops; - - err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 1); - if (err) - return err; - - err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_SIGDET_CTRL, 1); - if (err) - return err; - - err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 0); - if (err) - return err; - - err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_CTRL, - val | VSC_CTRL_CLAUSE37_VIEW); - if (err) - return err; - - err = vsc8211_reset(phy, 0); - if (err) - return err; - - udelay(5); /* delay after reset before next SMI */ - return 0; -} diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c deleted file mode 100644 index 3af19a550372..000000000000 --- a/drivers/net/cxgb3/xgmac.c +++ /dev/null @@ -1,657 +0,0 @@ -/* - * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#include "common.h" -#include "regs.h" - -/* - * # of exact address filters. The first one is used for the station address, - * the rest are available for multicast addresses. - */ -#define EXACT_ADDR_FILTERS 8 - -static inline int macidx(const struct cmac *mac) -{ - return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR); -} - -static void xaui_serdes_reset(struct cmac *mac) -{ - static const unsigned int clear[] = { - F_PWRDN0 | F_PWRDN1, F_RESETPLL01, F_RESET0 | F_RESET1, - F_PWRDN2 | F_PWRDN3, F_RESETPLL23, F_RESET2 | F_RESET3 - }; - - int i; - struct adapter *adap = mac->adapter; - u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset; - - t3_write_reg(adap, ctrl, adap->params.vpd.xauicfg[macidx(mac)] | - F_RESET3 | F_RESET2 | F_RESET1 | F_RESET0 | - F_PWRDN3 | F_PWRDN2 | F_PWRDN1 | F_PWRDN0 | - F_RESETPLL23 | F_RESETPLL01); - t3_read_reg(adap, ctrl); - udelay(15); - - for (i = 0; i < ARRAY_SIZE(clear); i++) { - t3_set_reg_field(adap, ctrl, clear[i], 0); - udelay(15); - } -} - -void t3b_pcs_reset(struct cmac *mac) -{ - t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, - F_PCS_RESET_, 0); - udelay(20); - t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0, - F_PCS_RESET_); -} - -int t3_mac_reset(struct cmac *mac) -{ - static const struct addr_val_pair mac_reset_avp[] = { - {A_XGM_TX_CTRL, 0}, - {A_XGM_RX_CTRL, 0}, - {A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES | - F_RMFCS | F_ENJUMBO | F_ENHASHMCAST}, - {A_XGM_RX_HASH_LOW, 0}, - {A_XGM_RX_HASH_HIGH, 0}, - {A_XGM_RX_EXACT_MATCH_LOW_1, 0}, - {A_XGM_RX_EXACT_MATCH_LOW_2, 0}, - {A_XGM_RX_EXACT_MATCH_LOW_3, 0}, - {A_XGM_RX_EXACT_MATCH_LOW_4, 0}, - {A_XGM_RX_EXACT_MATCH_LOW_5, 0}, - {A_XGM_RX_EXACT_MATCH_LOW_6, 0}, - {A_XGM_RX_EXACT_MATCH_LOW_7, 0}, - {A_XGM_RX_EXACT_MATCH_LOW_8, 0}, - {A_XGM_STAT_CTRL, F_CLRSTATS} - }; - u32 val; - struct adapter *adap = mac->adapter; - unsigned int oft = mac->offset; - - t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_); - t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ - - t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft); - t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft, - F_RXSTRFRWRD | F_DISERRFRAMES, - uses_xaui(adap) ? 0 : F_RXSTRFRWRD); - t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0, F_UNDERUNFIX); - - if (uses_xaui(adap)) { - if (adap->params.rev == 0) { - t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0, - F_RXENABLE | F_TXENABLE); - if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft, - F_CMULOCK, 1, 5, 2)) { - CH_ERR(adap, - "MAC %d XAUI SERDES CMU lock failed\n", - macidx(mac)); - return -1; - } - t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0, - F_SERDESRESET_); - } else - xaui_serdes_reset(mac); - } - - t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + oft, - V_RXMAXFRAMERSIZE(M_RXMAXFRAMERSIZE), - V_RXMAXFRAMERSIZE(MAX_FRAME_SIZE) | F_RXENFRAMER); - val = F_MAC_RESET_ | F_XGMAC_STOP_EN; - - if (is_10G(adap)) - val |= F_PCS_RESET_; - else if (uses_xaui(adap)) - val |= F_PCS_RESET_ | F_XG2G_RESET_; - else - val |= F_RGMII_RESET_ | F_XG2G_RESET_; - t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val); - t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ - if ((val & F_PCS_RESET_) && adap->params.rev) { - msleep(1); - t3b_pcs_reset(mac); - } - - memset(&mac->stats, 0, sizeof(mac->stats)); - return 0; -} - -static int t3b2_mac_reset(struct cmac *mac) -{ - struct adapter *adap = mac->adapter; - unsigned int oft = mac->offset, store; - int idx = macidx(mac); - u32 val; - - if (!macidx(mac)) - t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0); - else - t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0); - - /* Stop NIC traffic to reduce the number of TXTOGGLES */ - t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 0); - /* Ensure TX drains */ - t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 0); - - t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_); - t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ - - /* Store A_TP_TX_DROP_CFG_CH0 */ - t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); - store = t3_read_reg(adap, A_TP_TX_DROP_CFG_CH0 + idx); - - msleep(10); - - /* Change DROP_CFG to 0xc0000011 */ - t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); - t3_write_reg(adap, A_TP_PIO_DATA, 0xc0000011); - - /* Check for xgm Rx fifo empty */ - /* Increased loop count to 1000 from 5 cover 1G and 100Mbps case */ - if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft, - 0x80000000, 1, 1000, 2)) { - CH_ERR(adap, "MAC %d Rx fifo drain failed\n", - macidx(mac)); - return -1; - } - - t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0); - t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ - - val = F_MAC_RESET_; - if (is_10G(adap)) - val |= F_PCS_RESET_; - else if (uses_xaui(adap)) - val |= F_PCS_RESET_ | F_XG2G_RESET_; - else - val |= F_RGMII_RESET_ | F_XG2G_RESET_; - t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val); - t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ - if ((val & F_PCS_RESET_) && adap->params.rev) { - msleep(1); - t3b_pcs_reset(mac); - } - t3_write_reg(adap, A_XGM_RX_CFG + oft, - F_DISPAUSEFRAMES | F_EN1536BFRAMES | - F_RMFCS | F_ENJUMBO | F_ENHASHMCAST); - - /* Restore the DROP_CFG */ - t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); - t3_write_reg(adap, A_TP_PIO_DATA, store); - - if (!idx) - t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT0ACTIVE); - else - t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT1ACTIVE); - - /* re-enable nic traffic */ - t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 1); - - /* Set: re-enable NIC traffic */ - t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 1); - - return 0; -} - -/* - * Set the exact match register 'idx' to recognize the given Ethernet address. - */ -static void set_addr_filter(struct cmac *mac, int idx, const u8 * addr) -{ - u32 addr_lo, addr_hi; - unsigned int oft = mac->offset + idx * 8; - - addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; - addr_hi = (addr[5] << 8) | addr[4]; - - t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo); - t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi); -} - -/* Set one of the station's unicast MAC addresses. */ -int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6]) -{ - if (idx >= mac->nucast) - return -EINVAL; - set_addr_filter(mac, idx, addr); - return 0; -} - -/* - * Specify the number of exact address filters that should be reserved for - * unicast addresses. Caller should reload the unicast and multicast addresses - * after calling this. - */ -int t3_mac_set_num_ucast(struct cmac *mac, int n) -{ - if (n > EXACT_ADDR_FILTERS) - return -EINVAL; - mac->nucast = n; - return 0; -} - -void t3_mac_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 */ -} - -void t3_mac_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) -{ - int hash = 0, octet, bit, i = 0, c; - - for (octet = 0; octet < 6; ++octet) - for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) { - hash ^= (c & 1) << i; - if (++i == 6) - i = 0; - } - return hash; -} - -int t3_mac_set_rx_mode(struct cmac *mac, struct net_device *dev) -{ - u32 val, hash_lo, hash_hi; - struct adapter *adap = mac->adapter; - unsigned int oft = mac->offset; - - val = t3_read_reg(adap, A_XGM_RX_CFG + oft) & ~F_COPYALLFRAMES; - if (dev->flags & IFF_PROMISC) - val |= F_COPYALLFRAMES; - t3_write_reg(adap, A_XGM_RX_CFG + oft, val); - - if (dev->flags & IFF_ALLMULTI) - hash_lo = hash_hi = 0xffffffff; - else { - struct netdev_hw_addr *ha; - int exact_addr_idx = mac->nucast; - - hash_lo = hash_hi = 0; - netdev_for_each_mc_addr(ha, dev) - if (exact_addr_idx < EXACT_ADDR_FILTERS) - set_addr_filter(mac, exact_addr_idx++, - ha->addr); - else { - int hash = hash_hw_addr(ha->addr); - - if (hash < 32) - hash_lo |= (1 << hash); - else - hash_hi |= (1 << (hash - 32)); - } - } - - t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo); - t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi); - return 0; -} - -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, divisor; - int ipg; - unsigned int thres, v, reg; - struct adapter *adap = mac->adapter; - - /* - * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't. The HW max - * packet size register includes header, but not FCS. - */ - mtu += 14; - if (mtu > 1536) - mtu += 4; - - if (mtu > MAX_FRAME_SIZE - 4) - return -EINVAL; - t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu); - - if (adap->params.rev >= T3_REV_B2 && - (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) { - t3_mac_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); - - reg = adap->params.rev == T3_REV_B2 ? - A_XGM_RX_MAX_PKT_SIZE_ERR_CNT : A_XGM_RXFIFO_CFG; - - /* drain RX FIFO */ - if (t3_wait_op_done(adap, reg + mac->offset, - F_RXFIFO_EMPTY, 1, 20, 5)) { - t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v); - t3_mac_enable_exact_filters(mac); - return -EIO; - } - t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, - V_RXMAXPKTSIZE(M_RXMAXPKTSIZE), - V_RXMAXPKTSIZE(mtu)); - t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v); - t3_mac_enable_exact_filters(mac); - } else - t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, - V_RXMAXPKTSIZE(M_RXMAXPKTSIZE), - V_RXMAXPKTSIZE(mtu)); - - /* - * Adjust the PAUSE frame watermarks. We always set the LWM, and the - * HWM only if flow-control is enabled. - */ - 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); - v |= V_RXFIFOPAUSELWM(lwm / 8); - 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 */ - thres = (adap->params.vpd.cclk * 1000) / 15625; - thres = (thres * mtu) / 1000; - if (is_10G(adap)) - thres /= 10; - thres = mtu > thres ? (mtu - thres + 7) / 8 : 0; - thres = max(thres, 8U); /* need at least 8 */ - ipg = (adap->params.rev == T3_REV_C) ? 0 : 1; - t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset, - V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG), - V_TXFIFOTHRESH(thres) | V_TXIPG(ipg)); - - if (adap->params.rev > 0) { - divisor = (adap->params.rev == T3_REV_C) ? 64 : 8; - t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset, - (hwm - lwm) * 4 / divisor); - } - t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset, - MAC_RXFIFO_SIZE * 4 * 8 / 512); - return 0; -} - -int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc) -{ - u32 val; - struct adapter *adap = mac->adapter; - unsigned int oft = mac->offset; - - if (duplex >= 0 && duplex != DUPLEX_FULL) - return -EINVAL; - if (speed >= 0) { - if (speed == SPEED_10) - val = V_PORTSPEED(0); - else if (speed == SPEED_100) - val = V_PORTSPEED(1); - else if (speed == SPEED_1000) - val = V_PORTSPEED(2); - else if (speed == SPEED_10000) - val = V_PORTSPEED(3); - else - return -EINVAL; - - t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, - V_PORTSPEED(M_PORTSPEED), val); - } - - val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft); - val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); - if (fc & PAUSE_TX) { - u32 rx_max_pkt_size = - G_RXMAXPKTSIZE(t3_read_reg(adap, - A_XGM_RX_MAX_PKT_SIZE + oft)); - val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8); - } - 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); - return 0; -} - -int t3_mac_enable(struct cmac *mac, int which) -{ - int idx = macidx(mac); - struct adapter *adap = mac->adapter; - unsigned int oft = mac->offset; - struct mac_stats *s = &mac->stats; - - if (which & MAC_DIRECTION_TX) { - t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); - t3_write_reg(adap, A_TP_PIO_DATA, - adap->params.rev == T3_REV_C ? - 0xc4ffff01 : 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, - adap->params.rev == T3_REV_C ? 0 : 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, - A_TP_PIO_DATA))); - mac->tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, - A_XGM_TX_SPI4_SOP_EOP_CNT + - oft))); - mac->rx_mcnt = s->rx_frames; - mac->rx_pause = s->rx_pause; - mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, - A_XGM_RX_SPI4_SOP_EOP_CNT + - oft))); - mac->rx_ocnt = s->rx_fifo_ovfl; - mac->txen = F_TXEN; - mac->toggle_cnt = 0; - } - if (which & MAC_DIRECTION_RX) - t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN); - return 0; -} - -int t3_mac_disable(struct cmac *mac, int which) -{ - struct adapter *adap = mac->adapter; - - if (which & MAC_DIRECTION_TX) { - t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0); - mac->txen = 0; - } - if (which & MAC_DIRECTION_RX) { - int val = F_MAC_RESET_; - - t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, - F_PCS_RESET_, 0); - msleep(100); - t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0); - if (is_10G(adap)) - val |= F_PCS_RESET_; - else if (uses_xaui(adap)) - val |= F_PCS_RESET_ | F_XG2G_RESET_; - else - val |= F_RGMII_RESET_ | F_XG2G_RESET_; - t3_write_reg(mac->adapter, A_XGM_RESET_CTRL + mac->offset, val); - } - return 0; -} - -int t3b2_mac_watchdog_task(struct cmac *mac) -{ - struct adapter *adap = mac->adapter; - struct mac_stats *s = &mac->stats; - unsigned int tx_tcnt, tx_xcnt; - u64 tx_mcnt = s->tx_frames; - int status; - - 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 */ - if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) { - tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, - A_XGM_TX_SPI4_SOP_EOP_CNT + - mac->offset))); - if (tx_xcnt == 0) { - t3_write_reg(adap, A_TP_PIO_ADDR, - A_TP_TX_DROP_CNT_CH0 + macidx(mac)); - tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap, - A_TP_PIO_DATA))); - } else { - goto out; - } - } else { - mac->toggle_cnt = 0; - goto out; - } - - if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) { - if (mac->toggle_cnt > 4) { - status = 2; - goto out; - } else { - status = 1; - goto out; - } - } else { - mac->toggle_cnt = 0; - goto out; - } - -out: - mac->tx_tcnt = tx_tcnt; - mac->tx_xcnt = tx_xcnt; - mac->tx_mcnt = s->tx_frames; - mac->rx_pause = s->rx_pause; - if (status == 1) { - t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0); - t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */ - t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, mac->txen); - t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */ - mac->toggle_cnt++; - } else if (status == 2) { - t3b2_mac_reset(mac); - mac->toggle_cnt = 0; - } - return status; -} - -/* - * This function is called periodically to accumulate the current values of the - * RMON counters into the port statistics. Since the packet counters are only - * 32 bits they can overflow in ~286 secs at 10G, so the function should be - * called more frequently than that. The byte counters are 45-bit wide, they - * would overflow in ~7.8 hours. - */ -const struct mac_stats *t3_mac_update_stats(struct cmac *mac) -{ -#define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset) -#define RMON_UPDATE(mac, name, reg) \ - (mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg) -#define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \ - (mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \ - ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32) - - u32 v, lo; - - 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); - RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES); - RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES); - RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES); - RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES); - RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES); - RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES); - - RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES); - - v = RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT); - if (mac->adapter->params.rev == T3_REV_B2) - v &= 0x7fffffff; - mac->stats.rx_too_long += v; - - RMON_UPDATE(mac, rx_frames_64, RX_64B_FRAMES); - RMON_UPDATE(mac, rx_frames_65_127, RX_65_127B_FRAMES); - RMON_UPDATE(mac, rx_frames_128_255, RX_128_255B_FRAMES); - RMON_UPDATE(mac, rx_frames_256_511, RX_256_511B_FRAMES); - RMON_UPDATE(mac, rx_frames_512_1023, RX_512_1023B_FRAMES); - RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES); - RMON_UPDATE(mac, rx_frames_1519_max, RX_1519_MAXB_FRAMES); - - RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH); - RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH); - RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST); - RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST); - RMON_UPDATE(mac, tx_pause, TX_PAUSE); - /* This counts error frames in general (bad FCS, underrun, etc). */ - RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES); - - RMON_UPDATE(mac, tx_frames_64, TX_64B_FRAMES); - RMON_UPDATE(mac, tx_frames_65_127, TX_65_127B_FRAMES); - RMON_UPDATE(mac, tx_frames_128_255, TX_128_255B_FRAMES); - RMON_UPDATE(mac, tx_frames_256_511, TX_256_511B_FRAMES); - RMON_UPDATE(mac, tx_frames_512_1023, TX_512_1023B_FRAMES); - RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES); - RMON_UPDATE(mac, tx_frames_1519_max, TX_1519_MAXB_FRAMES); - - /* The next stat isn't clear-on-read. */ - t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50); - v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA); - lo = (u32) mac->stats.rx_cong_drops; - mac->stats.rx_cong_drops += (u64) (v - lo); - - return &mac->stats; -} diff --git a/drivers/net/cxgb4/Makefile b/drivers/net/cxgb4/Makefile deleted file mode 100644 index 498667487f52..000000000000 --- a/drivers/net/cxgb4/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# Chelsio T4 driver -# - -obj-$(CONFIG_CHELSIO_T4) += cxgb4.o - -cxgb4-objs := cxgb4_main.o l2t.o t4_hw.o sge.o diff --git a/drivers/net/cxgb4/cxgb4.h b/drivers/net/cxgb4/cxgb4.h deleted file mode 100644 index 223a7f72343b..000000000000 --- a/drivers/net/cxgb4/cxgb4.h +++ /dev/null @@ -1,722 +0,0 @@ -/* - * This file is part of the Chelsio T4 Ethernet driver for Linux. - * - * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef __CXGB4_H__ -#define __CXGB4_H__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "cxgb4_uld.h" -#include "t4_hw.h" - -#define FW_VERSION_MAJOR 1 -#define FW_VERSION_MINOR 1 -#define FW_VERSION_MICRO 0 - -enum { - MAX_NPORTS = 4, /* max # of ports */ - SERNUM_LEN = 24, /* Serial # length */ - EC_LEN = 16, /* E/C length */ - ID_LEN = 16, /* ID length */ -}; - -enum { - MEM_EDC0, - MEM_EDC1, - MEM_MC -}; - -enum dev_master { - MASTER_CANT, - MASTER_MAY, - MASTER_MUST -}; - -enum dev_state { - DEV_STATE_UNINIT, - DEV_STATE_INIT, - DEV_STATE_ERR -}; - -enum { - PAUSE_RX = 1 << 0, - PAUSE_TX = 1 << 1, - PAUSE_AUTONEG = 1 << 2 -}; - -struct port_stats { - u64 tx_octets; /* total # of octets in good frames */ - u64 tx_frames; /* all good frames */ - u64 tx_bcast_frames; /* all broadcast frames */ - u64 tx_mcast_frames; /* all multicast frames */ - u64 tx_ucast_frames; /* all unicast frames */ - u64 tx_error_frames; /* all error frames */ - - u64 tx_frames_64; /* # of Tx frames in a particular range */ - u64 tx_frames_65_127; - u64 tx_frames_128_255; - u64 tx_frames_256_511; - u64 tx_frames_512_1023; - u64 tx_frames_1024_1518; - u64 tx_frames_1519_max; - - u64 tx_drop; /* # of dropped Tx frames */ - u64 tx_pause; /* # of transmitted pause frames */ - u64 tx_ppp0; /* # of transmitted PPP prio 0 frames */ - u64 tx_ppp1; /* # of transmitted PPP prio 1 frames */ - u64 tx_ppp2; /* # of transmitted PPP prio 2 frames */ - u64 tx_ppp3; /* # of transmitted PPP prio 3 frames */ - u64 tx_ppp4; /* # of transmitted PPP prio 4 frames */ - u64 tx_ppp5; /* # of transmitted PPP prio 5 frames */ - u64 tx_ppp6; /* # of transmitted PPP prio 6 frames */ - u64 tx_ppp7; /* # of transmitted PPP prio 7 frames */ - - u64 rx_octets; /* total # of octets in good frames */ - u64 rx_frames; /* all good frames */ - u64 rx_bcast_frames; /* all broadcast frames */ - u64 rx_mcast_frames; /* all multicast frames */ - u64 rx_ucast_frames; /* all unicast frames */ - u64 rx_too_long; /* # of frames exceeding MTU */ - u64 rx_jabber; /* # of jabber frames */ - u64 rx_fcs_err; /* # of received frames with bad FCS */ - u64 rx_len_err; /* # of received frames with length error */ - u64 rx_symbol_err; /* symbol errors */ - u64 rx_runt; /* # of short frames */ - - u64 rx_frames_64; /* # of Rx frames in a particular range */ - u64 rx_frames_65_127; - u64 rx_frames_128_255; - u64 rx_frames_256_511; - u64 rx_frames_512_1023; - u64 rx_frames_1024_1518; - u64 rx_frames_1519_max; - - u64 rx_pause; /* # of received pause frames */ - u64 rx_ppp0; /* # of received PPP prio 0 frames */ - u64 rx_ppp1; /* # of received PPP prio 1 frames */ - u64 rx_ppp2; /* # of received PPP prio 2 frames */ - u64 rx_ppp3; /* # of received PPP prio 3 frames */ - u64 rx_ppp4; /* # of received PPP prio 4 frames */ - u64 rx_ppp5; /* # of received PPP prio 5 frames */ - u64 rx_ppp6; /* # of received PPP prio 6 frames */ - u64 rx_ppp7; /* # of received PPP prio 7 frames */ - - u64 rx_ovflow0; /* drops due to buffer-group 0 overflows */ - u64 rx_ovflow1; /* drops due to buffer-group 1 overflows */ - u64 rx_ovflow2; /* drops due to buffer-group 2 overflows */ - u64 rx_ovflow3; /* drops due to buffer-group 3 overflows */ - u64 rx_trunc0; /* buffer-group 0 truncated packets */ - u64 rx_trunc1; /* buffer-group 1 truncated packets */ - u64 rx_trunc2; /* buffer-group 2 truncated packets */ - u64 rx_trunc3; /* buffer-group 3 truncated packets */ -}; - -struct lb_port_stats { - u64 octets; - u64 frames; - u64 bcast_frames; - u64 mcast_frames; - u64 ucast_frames; - u64 error_frames; - - u64 frames_64; - u64 frames_65_127; - u64 frames_128_255; - u64 frames_256_511; - u64 frames_512_1023; - u64 frames_1024_1518; - u64 frames_1519_max; - - u64 drop; - - u64 ovflow0; - u64 ovflow1; - u64 ovflow2; - u64 ovflow3; - u64 trunc0; - u64 trunc1; - u64 trunc2; - u64 trunc3; -}; - -struct tp_tcp_stats { - u32 tcpOutRsts; - u64 tcpInSegs; - u64 tcpOutSegs; - u64 tcpRetransSegs; -}; - -struct tp_err_stats { - u32 macInErrs[4]; - u32 hdrInErrs[4]; - u32 tcpInErrs[4]; - u32 tnlCongDrops[4]; - u32 ofldChanDrops[4]; - u32 tnlTxDrops[4]; - u32 ofldVlanDrops[4]; - u32 tcp6InErrs[4]; - u32 ofldNoNeigh; - u32 ofldCongDefer; -}; - -struct tp_params { - unsigned int ntxchan; /* # of Tx channels */ - unsigned int tre; /* log2 of core clocks per TP tick */ -}; - -struct vpd_params { - unsigned int cclk; - u8 ec[EC_LEN + 1]; - u8 sn[SERNUM_LEN + 1]; - u8 id[ID_LEN + 1]; -}; - -struct pci_params { - unsigned char speed; - unsigned char width; -}; - -struct adapter_params { - struct tp_params tp; - struct vpd_params vpd; - struct pci_params pci; - - unsigned int sf_size; /* serial flash size in bytes */ - unsigned int sf_nsec; /* # of flash sectors */ - unsigned int sf_fw_start; /* start of FW image in flash */ - - unsigned int fw_vers; - unsigned int tp_vers; - u8 api_vers[7]; - - unsigned short mtus[NMTUS]; - unsigned short a_wnd[NCCTRL_WIN]; - unsigned short b_wnd[NCCTRL_WIN]; - - unsigned char nports; /* # of ethernet ports */ - unsigned char portvec; - unsigned char rev; /* chip revision */ - unsigned char offload; - - unsigned int ofldq_wr_cred; -}; - -struct trace_params { - u32 data[TRACE_LEN / 4]; - u32 mask[TRACE_LEN / 4]; - unsigned short snap_len; - unsigned short min_len; - unsigned char skip_ofst; - unsigned char skip_len; - unsigned char invert; - unsigned char port; -}; - -struct link_config { - unsigned short supported; /* link capabilities */ - unsigned short advertising; /* advertised capabilities */ - unsigned short requested_speed; /* speed user has requested */ - unsigned short speed; /* actual link speed */ - unsigned char requested_fc; /* flow control user has requested */ - unsigned char fc; /* actual link flow control */ - unsigned char autoneg; /* autonegotiating? */ - unsigned char link_ok; /* link up? */ -}; - -#define FW_LEN16(fw_struct) FW_CMD_LEN16(sizeof(fw_struct) / 16) - -enum { - MAX_ETH_QSETS = 32, /* # of Ethernet Tx/Rx queue sets */ - MAX_OFLD_QSETS = 16, /* # of offload Tx/Rx queue sets */ - MAX_CTRL_QUEUES = NCHAN, /* # of control Tx queues */ - MAX_RDMA_QUEUES = NCHAN, /* # of streaming RDMA Rx queues */ -}; - -enum { - MAX_EGRQ = 128, /* max # of egress queues, including FLs */ - MAX_INGQ = 64 /* max # of interrupt-capable ingress queues */ -}; - -struct adapter; -struct sge_rspq; - -struct port_info { - struct adapter *adapter; - u16 viid; - s16 xact_addr_filt; /* index of exact MAC address filter */ - u16 rss_size; /* size of VI's RSS table slice */ - s8 mdio_addr; - u8 port_type; - u8 mod_type; - u8 port_id; - u8 tx_chan; - u8 lport; /* associated offload logical port */ - u8 nqsets; /* # of qsets */ - u8 first_qset; /* index of first qset */ - u8 rss_mode; - struct link_config link_cfg; - u16 *rss; -}; - -struct dentry; -struct work_struct; - -enum { /* adapter flags */ - FULL_INIT_DONE = (1 << 0), - USING_MSI = (1 << 1), - USING_MSIX = (1 << 2), - FW_OK = (1 << 4), -}; - -struct rx_sw_desc; - -struct sge_fl { /* SGE free-buffer queue state */ - unsigned int avail; /* # of available Rx buffers */ - unsigned int pend_cred; /* new buffers since last FL DB ring */ - unsigned int cidx; /* consumer index */ - unsigned int pidx; /* producer index */ - unsigned long alloc_failed; /* # of times buffer allocation failed */ - unsigned long large_alloc_failed; - unsigned long starving; - /* RO fields */ - unsigned int cntxt_id; /* SGE context id for the free list */ - unsigned int size; /* capacity of free list */ - struct rx_sw_desc *sdesc; /* address of SW Rx descriptor ring */ - __be64 *desc; /* address of HW Rx descriptor ring */ - dma_addr_t addr; /* bus address of HW ring start */ -}; - -/* A packet gather list */ -struct pkt_gl { - skb_frag_t frags[MAX_SKB_FRAGS]; - void *va; /* virtual address of first byte */ - unsigned int nfrags; /* # of fragments */ - unsigned int tot_len; /* total length of fragments */ -}; - -typedef int (*rspq_handler_t)(struct sge_rspq *q, const __be64 *rsp, - const struct pkt_gl *gl); - -struct sge_rspq { /* state for an SGE response queue */ - struct napi_struct napi; - const __be64 *cur_desc; /* current descriptor in queue */ - unsigned int cidx; /* consumer index */ - u8 gen; /* current generation bit */ - u8 intr_params; /* interrupt holdoff parameters */ - u8 next_intr_params; /* holdoff params for next interrupt */ - u8 pktcnt_idx; /* interrupt packet threshold */ - u8 uld; /* ULD handling this queue */ - u8 idx; /* queue index within its group */ - int offset; /* offset into current Rx buffer */ - u16 cntxt_id; /* SGE context id for the response q */ - u16 abs_id; /* absolute SGE id for the response q */ - __be64 *desc; /* address of HW response ring */ - dma_addr_t phys_addr; /* physical address of the ring */ - unsigned int iqe_len; /* entry size */ - unsigned int size; /* capacity of response queue */ - struct adapter *adap; - struct net_device *netdev; /* associated net device */ - rspq_handler_t handler; -}; - -struct sge_eth_stats { /* Ethernet queue statistics */ - unsigned long pkts; /* # of ethernet packets */ - unsigned long lro_pkts; /* # of LRO super packets */ - unsigned long lro_merged; /* # of wire packets merged by LRO */ - unsigned long rx_cso; /* # of Rx checksum offloads */ - unsigned long vlan_ex; /* # of Rx VLAN extractions */ - unsigned long rx_drops; /* # of packets dropped due to no mem */ -}; - -struct sge_eth_rxq { /* SW Ethernet Rx queue */ - struct sge_rspq rspq; - struct sge_fl fl; - struct sge_eth_stats stats; -} ____cacheline_aligned_in_smp; - -struct sge_ofld_stats { /* offload queue statistics */ - unsigned long pkts; /* # of packets */ - unsigned long imm; /* # of immediate-data packets */ - unsigned long an; /* # of asynchronous notifications */ - unsigned long nomem; /* # of responses deferred due to no mem */ -}; - -struct sge_ofld_rxq { /* SW offload Rx queue */ - struct sge_rspq rspq; - struct sge_fl fl; - struct sge_ofld_stats stats; -} ____cacheline_aligned_in_smp; - -struct tx_desc { - __be64 flit[8]; -}; - -struct tx_sw_desc; - -struct sge_txq { - unsigned int in_use; /* # of in-use Tx descriptors */ - unsigned int size; /* # of descriptors */ - unsigned int cidx; /* SW consumer index */ - unsigned int pidx; /* producer index */ - unsigned long stops; /* # of times q has been stopped */ - unsigned long restarts; /* # of queue restarts */ - unsigned int cntxt_id; /* SGE context id for the Tx q */ - struct tx_desc *desc; /* address of HW Tx descriptor ring */ - struct tx_sw_desc *sdesc; /* address of SW Tx descriptor ring */ - struct sge_qstat *stat; /* queue status entry */ - dma_addr_t phys_addr; /* physical address of the ring */ -}; - -struct sge_eth_txq { /* state for an SGE Ethernet Tx queue */ - struct sge_txq q; - struct netdev_queue *txq; /* associated netdev TX queue */ - unsigned long tso; /* # of TSO requests */ - unsigned long tx_cso; /* # of Tx checksum offloads */ - unsigned long vlan_ins; /* # of Tx VLAN insertions */ - unsigned long mapping_err; /* # of I/O MMU packet mapping errors */ -} ____cacheline_aligned_in_smp; - -struct sge_ofld_txq { /* state for an SGE offload Tx queue */ - struct sge_txq q; - struct adapter *adap; - struct sk_buff_head sendq; /* list of backpressured packets */ - struct tasklet_struct qresume_tsk; /* restarts the queue */ - u8 full; /* the Tx ring is full */ - unsigned long mapping_err; /* # of I/O MMU packet mapping errors */ -} ____cacheline_aligned_in_smp; - -struct sge_ctrl_txq { /* state for an SGE control Tx queue */ - struct sge_txq q; - struct adapter *adap; - struct sk_buff_head sendq; /* list of backpressured packets */ - struct tasklet_struct qresume_tsk; /* restarts the queue */ - u8 full; /* the Tx ring is full */ -} ____cacheline_aligned_in_smp; - -struct sge { - struct sge_eth_txq ethtxq[MAX_ETH_QSETS]; - struct sge_ofld_txq ofldtxq[MAX_OFLD_QSETS]; - struct sge_ctrl_txq ctrlq[MAX_CTRL_QUEUES]; - - struct sge_eth_rxq ethrxq[MAX_ETH_QSETS]; - struct sge_ofld_rxq ofldrxq[MAX_OFLD_QSETS]; - struct sge_ofld_rxq rdmarxq[MAX_RDMA_QUEUES]; - struct sge_rspq fw_evtq ____cacheline_aligned_in_smp; - - struct sge_rspq intrq ____cacheline_aligned_in_smp; - spinlock_t intrq_lock; - - u16 max_ethqsets; /* # of available Ethernet queue sets */ - u16 ethqsets; /* # of active Ethernet queue sets */ - u16 ethtxq_rover; /* Tx queue to clean up next */ - u16 ofldqsets; /* # of active offload queue sets */ - u16 rdmaqs; /* # of available RDMA Rx queues */ - u16 ofld_rxq[MAX_OFLD_QSETS]; - u16 rdma_rxq[NCHAN]; - u16 timer_val[SGE_NTIMERS]; - u8 counter_val[SGE_NCOUNTERS]; - unsigned int starve_thres; - u8 idma_state[2]; - unsigned int egr_start; - unsigned int ingr_start; - void *egr_map[MAX_EGRQ]; /* qid->queue egress queue map */ - struct sge_rspq *ingr_map[MAX_INGQ]; /* qid->queue ingress queue map */ - DECLARE_BITMAP(starving_fl, MAX_EGRQ); - DECLARE_BITMAP(txq_maperr, MAX_EGRQ); - struct timer_list rx_timer; /* refills starving FLs */ - struct timer_list tx_timer; /* checks Tx queues */ -}; - -#define for_each_ethrxq(sge, i) for (i = 0; i < (sge)->ethqsets; i++) -#define for_each_ofldrxq(sge, i) for (i = 0; i < (sge)->ofldqsets; i++) -#define for_each_rdmarxq(sge, i) for (i = 0; i < (sge)->rdmaqs; i++) - -struct l2t_data; - -struct adapter { - void __iomem *regs; - struct pci_dev *pdev; - struct device *pdev_dev; - unsigned int fn; - unsigned int flags; - - int msg_enable; - - struct adapter_params params; - struct cxgb4_virt_res vres; - unsigned int swintr; - - unsigned int wol; - - struct { - unsigned short vec; - char desc[IFNAMSIZ + 10]; - } msix_info[MAX_INGQ + 1]; - - struct sge sge; - - struct net_device *port[MAX_NPORTS]; - u8 chan_map[NCHAN]; /* channel -> port map */ - - struct l2t_data *l2t; - void *uld_handle[CXGB4_ULD_MAX]; - struct list_head list_node; - - struct tid_info tids; - void **tid_release_head; - spinlock_t tid_release_lock; - struct work_struct tid_release_task; - bool tid_release_task_busy; - - struct dentry *debugfs_root; - - spinlock_t stats_lock; -}; - -static inline u32 t4_read_reg(struct adapter *adap, u32 reg_addr) -{ - return readl(adap->regs + reg_addr); -} - -static inline void t4_write_reg(struct adapter *adap, u32 reg_addr, u32 val) -{ - writel(val, adap->regs + reg_addr); -} - -#ifndef readq -static inline u64 readq(const volatile void __iomem *addr) -{ - return readl(addr) + ((u64)readl(addr + 4) << 32); -} - -static inline void writeq(u64 val, volatile void __iomem *addr) -{ - writel(val, addr); - writel(val >> 32, addr + 4); -} -#endif - -static inline u64 t4_read_reg64(struct adapter *adap, u32 reg_addr) -{ - return readq(adap->regs + reg_addr); -} - -static inline void t4_write_reg64(struct adapter *adap, u32 reg_addr, u64 val) -{ - writeq(val, adap->regs + reg_addr); -} - -/** - * netdev2pinfo - return the port_info structure associated with a net_device - * @dev: the netdev - * - * Return the struct port_info associated with a net_device - */ -static inline struct port_info *netdev2pinfo(const struct net_device *dev) -{ - return netdev_priv(dev); -} - -/** - * adap2pinfo - return the port_info of a port - * @adap: the adapter - * @idx: the port index - * - * Return the port_info structure for the port of the given index. - */ -static inline struct port_info *adap2pinfo(struct adapter *adap, int idx) -{ - return netdev_priv(adap->port[idx]); -} - -/** - * netdev2adap - return the adapter structure associated with a net_device - * @dev: the netdev - * - * Return the struct adapter associated with a net_device - */ -static inline struct adapter *netdev2adap(const struct net_device *dev) -{ - return netdev2pinfo(dev)->adapter; -} - -void t4_os_portmod_changed(const struct adapter *adap, int port_id); -void t4_os_link_changed(struct adapter *adap, int port_id, int link_stat); - -void *t4_alloc_mem(size_t size); - -void t4_free_sge_resources(struct adapter *adap); -irq_handler_t t4_intr_handler(struct adapter *adap); -netdev_tx_t t4_eth_xmit(struct sk_buff *skb, struct net_device *dev); -int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, - const struct pkt_gl *gl); -int t4_mgmt_tx(struct adapter *adap, struct sk_buff *skb); -int t4_ofld_send(struct adapter *adap, struct sk_buff *skb); -int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq, - struct net_device *dev, int intr_idx, - struct sge_fl *fl, rspq_handler_t hnd); -int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq, - struct net_device *dev, struct netdev_queue *netdevq, - unsigned int iqid); -int t4_sge_alloc_ctrl_txq(struct adapter *adap, struct sge_ctrl_txq *txq, - struct net_device *dev, unsigned int iqid, - unsigned int cmplqid); -int t4_sge_alloc_ofld_txq(struct adapter *adap, struct sge_ofld_txq *txq, - struct net_device *dev, unsigned int iqid); -irqreturn_t t4_sge_intr_msix(int irq, void *cookie); -void t4_sge_init(struct adapter *adap); -void t4_sge_start(struct adapter *adap); -void t4_sge_stop(struct adapter *adap); - -#define for_each_port(adapter, iter) \ - for (iter = 0; iter < (adapter)->params.nports; ++iter) - -static inline unsigned int core_ticks_per_usec(const struct adapter *adap) -{ - return adap->params.vpd.cclk / 1000; -} - -static inline unsigned int us_to_core_ticks(const struct adapter *adap, - unsigned int us) -{ - return (us * adap->params.vpd.cclk) / 1000; -} - -void t4_set_reg_field(struct adapter *adap, unsigned int addr, u32 mask, - u32 val); - -int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size, - void *rpl, bool sleep_ok); - -static inline int t4_wr_mbox(struct adapter *adap, int mbox, const void *cmd, - int size, void *rpl) -{ - return t4_wr_mbox_meat(adap, mbox, cmd, size, rpl, true); -} - -static inline int t4_wr_mbox_ns(struct adapter *adap, int mbox, const void *cmd, - int size, void *rpl) -{ - return t4_wr_mbox_meat(adap, mbox, cmd, size, rpl, false); -} - -void t4_intr_enable(struct adapter *adapter); -void t4_intr_disable(struct adapter *adapter); -int t4_slow_intr_handler(struct adapter *adapter); - -int t4_wait_dev_ready(struct adapter *adap); -int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port, - struct link_config *lc); -int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port); -int t4_seeprom_wp(struct adapter *adapter, bool enable); -int t4_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size); -int t4_check_fw_version(struct adapter *adapter); -int t4_prep_adapter(struct adapter *adapter); -int t4_port_init(struct adapter *adap, int mbox, int pf, int vf); -void t4_fatal_err(struct adapter *adapter); -int t4_config_rss_range(struct adapter *adapter, int mbox, unsigned int viid, - int start, int n, const u16 *rspq, unsigned int nrspq); -int t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode, - unsigned int flags); -int t4_mc_read(struct adapter *adap, u32 addr, __be32 *data, u64 *parity); -int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, - u64 *parity); - -void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p); -void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log); -void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4, - struct tp_tcp_stats *v6); -void t4_load_mtus(struct adapter *adap, const unsigned short *mtus, - const unsigned short *alpha, const unsigned short *beta); - -void t4_wol_magic_enable(struct adapter *adap, unsigned int port, - const u8 *addr); -int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map, - u64 mask0, u64 mask1, unsigned int crc, bool enable); - -int t4_fw_hello(struct adapter *adap, unsigned int mbox, unsigned int evt_mbox, - enum dev_master master, enum dev_state *state); -int t4_fw_bye(struct adapter *adap, unsigned int mbox); -int t4_early_init(struct adapter *adap, unsigned int mbox); -int t4_fw_reset(struct adapter *adap, unsigned int mbox, int reset); -int t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf, - unsigned int vf, unsigned int nparams, const u32 *params, - u32 *val); -int t4_set_params(struct adapter *adap, unsigned int mbox, unsigned int pf, - unsigned int vf, unsigned int nparams, const u32 *params, - const u32 *val); -int t4_cfg_pfvf(struct adapter *adap, unsigned int mbox, unsigned int pf, - unsigned int vf, unsigned int txq, unsigned int txq_eth_ctrl, - unsigned int rxqi, unsigned int rxq, unsigned int tc, - unsigned int vi, unsigned int cmask, unsigned int pmask, - unsigned int nexact, unsigned int rcaps, unsigned int wxcaps); -int t4_alloc_vi(struct adapter *adap, unsigned int mbox, unsigned int port, - unsigned int pf, unsigned int vf, unsigned int nmac, u8 *mac, - unsigned int *rss_size); -int t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid, - int mtu, int promisc, int all_multi, int bcast, int vlanex, - bool sleep_ok); -int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox, - unsigned int viid, bool free, unsigned int naddr, - const u8 **addr, u16 *idx, u64 *hash, bool sleep_ok); -int t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid, - int idx, const u8 *addr, bool persist, bool add_smt); -int t4_set_addr_hash(struct adapter *adap, unsigned int mbox, unsigned int viid, - bool ucast, u64 vec, bool sleep_ok); -int t4_enable_vi(struct adapter *adap, unsigned int mbox, unsigned int viid, - bool rx_en, bool tx_en); -int t4_identify_port(struct adapter *adap, unsigned int mbox, unsigned int viid, - unsigned int nblinks); -int t4_mdio_rd(struct adapter *adap, unsigned int mbox, unsigned int phy_addr, - unsigned int mmd, unsigned int reg, u16 *valp); -int t4_mdio_wr(struct adapter *adap, unsigned int mbox, unsigned int phy_addr, - unsigned int mmd, unsigned int reg, u16 val); -int t4_iq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, - unsigned int vf, unsigned int iqtype, unsigned int iqid, - unsigned int fl0id, unsigned int fl1id); -int t4_eth_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, - unsigned int vf, unsigned int eqid); -int t4_ctrl_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, - unsigned int vf, unsigned int eqid); -int t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, - unsigned int vf, unsigned int eqid); -int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl); -#endif /* __CXGB4_H__ */ diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c deleted file mode 100644 index c9957b7f17b5..000000000000 --- a/drivers/net/cxgb4/cxgb4_main.c +++ /dev/null @@ -1,3806 +0,0 @@ -/* - * This file is part of the Chelsio T4 Ethernet driver for Linux. - * - * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cxgb4.h" -#include "t4_regs.h" -#include "t4_msg.h" -#include "t4fw_api.h" -#include "l2t.h" - -#define DRV_VERSION "1.3.0-ko" -#define DRV_DESC "Chelsio T4 Network Driver" - -/* - * Max interrupt hold-off timer value in us. Queues fall back to this value - * under extreme memory pressure so it's largish to give the system time to - * recover. - */ -#define MAX_SGE_TIMERVAL 200U - -#ifdef CONFIG_PCI_IOV -/* - * Virtual Function provisioning constants. We need two extra Ingress Queues - * with Interrupt capability to serve as the VF's Firmware Event Queue and - * Forwarded Interrupt Queue (when using MSI mode) -- neither will have Free - * Lists associated with them). For each Ethernet/Control Egress Queue and - * for each Free List, we need an Egress Context. - */ -enum { - VFRES_NPORTS = 1, /* # of "ports" per VF */ - VFRES_NQSETS = 2, /* # of "Queue Sets" per VF */ - - VFRES_NVI = VFRES_NPORTS, /* # of Virtual Interfaces */ - VFRES_NETHCTRL = VFRES_NQSETS, /* # of EQs used for ETH or CTRL Qs */ - VFRES_NIQFLINT = VFRES_NQSETS+2,/* # of ingress Qs/w Free List(s)/intr */ - VFRES_NIQ = 0, /* # of non-fl/int ingress queues */ - VFRES_NEQ = VFRES_NQSETS*2, /* # of egress queues */ - VFRES_TC = 0, /* PCI-E traffic class */ - VFRES_NEXACTF = 16, /* # of exact MPS filters */ - - VFRES_R_CAPS = FW_CMD_CAP_DMAQ|FW_CMD_CAP_VF|FW_CMD_CAP_PORT, - VFRES_WX_CAPS = FW_CMD_CAP_DMAQ|FW_CMD_CAP_VF, -}; - -/* - * Provide a Port Access Rights Mask for the specified PF/VF. This is very - * static and likely not to be useful in the long run. We really need to - * implement some form of persistent configuration which the firmware - * controls. - */ -static unsigned int pfvfres_pmask(struct adapter *adapter, - unsigned int pf, unsigned int vf) -{ - unsigned int portn, portvec; - - /* - * Give PF's access to all of the ports. - */ - if (vf == 0) - return FW_PFVF_CMD_PMASK_MASK; - - /* - * For VFs, we'll assign them access to the ports based purely on the - * PF. We assign active ports in order, wrapping around if there are - * fewer active ports than PFs: e.g. active port[pf % nports]. - * Unfortunately the adapter's port_info structs haven't been - * initialized yet so we have to compute this. - */ - if (adapter->params.nports == 0) - return 0; - - portn = pf % adapter->params.nports; - portvec = adapter->params.portvec; - for (;;) { - /* - * Isolate the lowest set bit in the port vector. If we're at - * the port number that we want, return that as the pmask. - * otherwise mask that bit out of the port vector and - * decrement our port number ... - */ - unsigned int pmask = portvec ^ (portvec & (portvec-1)); - if (portn == 0) - return pmask; - portn--; - portvec &= ~pmask; - } - /*NOTREACHED*/ -} -#endif - -enum { - MEMWIN0_APERTURE = 65536, - MEMWIN0_BASE = 0x30000, - MEMWIN1_APERTURE = 32768, - MEMWIN1_BASE = 0x28000, - MEMWIN2_APERTURE = 2048, - MEMWIN2_BASE = 0x1b800, -}; - -enum { - MAX_TXQ_ENTRIES = 16384, - MAX_CTRL_TXQ_ENTRIES = 1024, - MAX_RSPQ_ENTRIES = 16384, - MAX_RX_BUFFERS = 16384, - MIN_TXQ_ENTRIES = 32, - MIN_CTRL_TXQ_ENTRIES = 32, - MIN_RSPQ_ENTRIES = 128, - MIN_FL_ENTRIES = 16 -}; - -#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \ - NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\ - NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) - -#define CH_DEVICE(devid, data) { PCI_VDEVICE(CHELSIO, devid), (data) } - -static DEFINE_PCI_DEVICE_TABLE(cxgb4_pci_tbl) = { - CH_DEVICE(0xa000, 0), /* PE10K */ - CH_DEVICE(0x4001, -1), - CH_DEVICE(0x4002, -1), - CH_DEVICE(0x4003, -1), - CH_DEVICE(0x4004, -1), - CH_DEVICE(0x4005, -1), - CH_DEVICE(0x4006, -1), - CH_DEVICE(0x4007, -1), - CH_DEVICE(0x4008, -1), - CH_DEVICE(0x4009, -1), - CH_DEVICE(0x400a, -1), - CH_DEVICE(0x4401, 4), - CH_DEVICE(0x4402, 4), - CH_DEVICE(0x4403, 4), - CH_DEVICE(0x4404, 4), - CH_DEVICE(0x4405, 4), - CH_DEVICE(0x4406, 4), - CH_DEVICE(0x4407, 4), - CH_DEVICE(0x4408, 4), - CH_DEVICE(0x4409, 4), - CH_DEVICE(0x440a, 4), - { 0, } -}; - -#define FW_FNAME "cxgb4/t4fw.bin" - -MODULE_DESCRIPTION(DRV_DESC); -MODULE_AUTHOR("Chelsio Communications"); -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_VERSION(DRV_VERSION); -MODULE_DEVICE_TABLE(pci, cxgb4_pci_tbl); -MODULE_FIRMWARE(FW_FNAME); - -static int dflt_msg_enable = DFLT_MSG_ENABLE; - -module_param(dflt_msg_enable, int, 0644); -MODULE_PARM_DESC(dflt_msg_enable, "Chelsio T4 default message enable bitmap"); - -/* - * The driver uses the best interrupt scheme available on a platform in the - * order MSI-X, MSI, legacy INTx interrupts. This parameter determines which - * of these schemes the driver may consider as follows: - * - * msi = 2: choose from among all three options - * msi = 1: only consider MSI and INTx interrupts - * msi = 0: force INTx interrupts - */ -static int msi = 2; - -module_param(msi, int, 0644); -MODULE_PARM_DESC(msi, "whether to use INTx (0), MSI (1) or MSI-X (2)"); - -/* - * Queue interrupt hold-off timer values. Queues default to the first of these - * upon creation. - */ -static unsigned int intr_holdoff[SGE_NTIMERS - 1] = { 5, 10, 20, 50, 100 }; - -module_param_array(intr_holdoff, uint, NULL, 0644); -MODULE_PARM_DESC(intr_holdoff, "values for queue interrupt hold-off timers " - "0..4 in microseconds"); - -static unsigned int intr_cnt[SGE_NCOUNTERS - 1] = { 4, 8, 16 }; - -module_param_array(intr_cnt, uint, NULL, 0644); -MODULE_PARM_DESC(intr_cnt, - "thresholds 1..3 for queue interrupt packet counters"); - -static int vf_acls; - -#ifdef CONFIG_PCI_IOV -module_param(vf_acls, bool, 0644); -MODULE_PARM_DESC(vf_acls, "if set enable virtualization L2 ACL enforcement"); - -static unsigned int num_vf[4]; - -module_param_array(num_vf, uint, NULL, 0644); -MODULE_PARM_DESC(num_vf, "number of VFs for each of PFs 0-3"); -#endif - -static struct dentry *cxgb4_debugfs_root; - -static LIST_HEAD(adapter_list); -static DEFINE_MUTEX(uld_mutex); -static struct cxgb4_uld_info ulds[CXGB4_ULD_MAX]; -static const char *uld_str[] = { "RDMA", "iSCSI" }; - -static void link_report(struct net_device *dev) -{ - if (!netif_carrier_ok(dev)) - netdev_info(dev, "link down\n"); - else { - static const char *fc[] = { "no", "Rx", "Tx", "Tx/Rx" }; - - const char *s = "10Mbps"; - const struct port_info *p = netdev_priv(dev); - - switch (p->link_cfg.speed) { - case SPEED_10000: - s = "10Gbps"; - break; - case SPEED_1000: - s = "1000Mbps"; - break; - case SPEED_100: - s = "100Mbps"; - break; - } - - netdev_info(dev, "link up, %s, full-duplex, %s PAUSE\n", s, - fc[p->link_cfg.fc]); - } -} - -void t4_os_link_changed(struct adapter *adapter, int port_id, int link_stat) -{ - struct net_device *dev = adapter->port[port_id]; - - /* Skip changes from disabled ports. */ - if (netif_running(dev) && link_stat != netif_carrier_ok(dev)) { - if (link_stat) - netif_carrier_on(dev); - else - netif_carrier_off(dev); - - link_report(dev); - } -} - -void t4_os_portmod_changed(const struct adapter *adap, int port_id) -{ - static const char *mod_str[] = { - NULL, "LR", "SR", "ER", "passive DA", "active DA", "LRM" - }; - - const struct net_device *dev = adap->port[port_id]; - const struct port_info *pi = netdev_priv(dev); - - if (pi->mod_type == FW_PORT_MOD_TYPE_NONE) - netdev_info(dev, "port module unplugged\n"); - else if (pi->mod_type < ARRAY_SIZE(mod_str)) - netdev_info(dev, "%s module inserted\n", mod_str[pi->mod_type]); -} - -/* - * Configure the exact and hash address filters to handle a port's multicast - * and secondary unicast MAC addresses. - */ -static int set_addr_filters(const struct net_device *dev, bool sleep) -{ - u64 mhash = 0; - u64 uhash = 0; - bool free = true; - u16 filt_idx[7]; - const u8 *addr[7]; - int ret, naddr = 0; - const struct netdev_hw_addr *ha; - int uc_cnt = netdev_uc_count(dev); - int mc_cnt = netdev_mc_count(dev); - const struct port_info *pi = netdev_priv(dev); - unsigned int mb = pi->adapter->fn; - - /* first do the secondary unicast addresses */ - netdev_for_each_uc_addr(ha, dev) { - addr[naddr++] = ha->addr; - if (--uc_cnt == 0 || naddr >= ARRAY_SIZE(addr)) { - ret = t4_alloc_mac_filt(pi->adapter, mb, pi->viid, free, - naddr, addr, filt_idx, &uhash, sleep); - if (ret < 0) - return ret; - - free = false; - naddr = 0; - } - } - - /* next set up the multicast addresses */ - netdev_for_each_mc_addr(ha, dev) { - addr[naddr++] = ha->addr; - if (--mc_cnt == 0 || naddr >= ARRAY_SIZE(addr)) { - ret = t4_alloc_mac_filt(pi->adapter, mb, pi->viid, free, - naddr, addr, filt_idx, &mhash, sleep); - if (ret < 0) - return ret; - - free = false; - naddr = 0; - } - } - - return t4_set_addr_hash(pi->adapter, mb, pi->viid, uhash != 0, - uhash | mhash, sleep); -} - -/* - * Set Rx properties of a port, such as promiscruity, address filters, and MTU. - * If @mtu is -1 it is left unchanged. - */ -static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok) -{ - int ret; - struct port_info *pi = netdev_priv(dev); - - ret = set_addr_filters(dev, sleep_ok); - if (ret == 0) - ret = t4_set_rxmode(pi->adapter, pi->adapter->fn, pi->viid, mtu, - (dev->flags & IFF_PROMISC) ? 1 : 0, - (dev->flags & IFF_ALLMULTI) ? 1 : 0, 1, -1, - sleep_ok); - return ret; -} - -/** - * link_start - enable a port - * @dev: the port to enable - * - * Performs the MAC and PHY actions needed to enable a port. - */ -static int link_start(struct net_device *dev) -{ - int ret; - struct port_info *pi = netdev_priv(dev); - unsigned int mb = pi->adapter->fn; - - /* - * We do not set address filters and promiscuity here, the stack does - * that step explicitly. - */ - ret = t4_set_rxmode(pi->adapter, mb, pi->viid, dev->mtu, -1, -1, -1, - !!(dev->features & NETIF_F_HW_VLAN_RX), true); - if (ret == 0) { - ret = t4_change_mac(pi->adapter, mb, pi->viid, - pi->xact_addr_filt, dev->dev_addr, true, - true); - if (ret >= 0) { - pi->xact_addr_filt = ret; - ret = 0; - } - } - if (ret == 0) - ret = t4_link_start(pi->adapter, mb, pi->tx_chan, - &pi->link_cfg); - if (ret == 0) - ret = t4_enable_vi(pi->adapter, mb, pi->viid, true, true); - return ret; -} - -/* - * Response queue handler for the FW event queue. - */ -static int fwevtq_handler(struct sge_rspq *q, const __be64 *rsp, - const struct pkt_gl *gl) -{ - u8 opcode = ((const struct rss_header *)rsp)->opcode; - - rsp++; /* skip RSS header */ - if (likely(opcode == CPL_SGE_EGR_UPDATE)) { - const struct cpl_sge_egr_update *p = (void *)rsp; - unsigned int qid = EGR_QID(ntohl(p->opcode_qid)); - struct sge_txq *txq; - - txq = q->adap->sge.egr_map[qid - q->adap->sge.egr_start]; - txq->restarts++; - if ((u8 *)txq < (u8 *)q->adap->sge.ofldtxq) { - struct sge_eth_txq *eq; - - eq = container_of(txq, struct sge_eth_txq, q); - netif_tx_wake_queue(eq->txq); - } else { - struct sge_ofld_txq *oq; - - oq = container_of(txq, struct sge_ofld_txq, q); - tasklet_schedule(&oq->qresume_tsk); - } - } else if (opcode == CPL_FW6_MSG || opcode == CPL_FW4_MSG) { - const struct cpl_fw6_msg *p = (void *)rsp; - - if (p->type == 0) - t4_handle_fw_rpl(q->adap, p->data); - } else if (opcode == CPL_L2T_WRITE_RPL) { - const struct cpl_l2t_write_rpl *p = (void *)rsp; - - do_l2t_write_rpl(q->adap, p); - } else - dev_err(q->adap->pdev_dev, - "unexpected CPL %#x on FW event queue\n", opcode); - return 0; -} - -/** - * uldrx_handler - response queue handler for ULD queues - * @q: the response queue that received the packet - * @rsp: the response queue descriptor holding the offload message - * @gl: the gather list of packet fragments - * - * Deliver an ingress offload packet to a ULD. All processing is done by - * the ULD, we just maintain statistics. - */ -static int uldrx_handler(struct sge_rspq *q, const __be64 *rsp, - const struct pkt_gl *gl) -{ - struct sge_ofld_rxq *rxq = container_of(q, struct sge_ofld_rxq, rspq); - - if (ulds[q->uld].rx_handler(q->adap->uld_handle[q->uld], rsp, gl)) { - rxq->stats.nomem++; - return -1; - } - if (gl == NULL) - rxq->stats.imm++; - else if (gl == CXGB4_MSG_AN) - rxq->stats.an++; - else - rxq->stats.pkts++; - return 0; -} - -static void disable_msi(struct adapter *adapter) -{ - if (adapter->flags & USING_MSIX) { - pci_disable_msix(adapter->pdev); - adapter->flags &= ~USING_MSIX; - } else if (adapter->flags & USING_MSI) { - pci_disable_msi(adapter->pdev); - adapter->flags &= ~USING_MSI; - } -} - -/* - * Interrupt handler for non-data events used with MSI-X. - */ -static irqreturn_t t4_nondata_intr(int irq, void *cookie) -{ - struct adapter *adap = cookie; - - u32 v = t4_read_reg(adap, MYPF_REG(PL_PF_INT_CAUSE)); - if (v & PFSW) { - adap->swintr = 1; - t4_write_reg(adap, MYPF_REG(PL_PF_INT_CAUSE), v); - } - t4_slow_intr_handler(adap); - return IRQ_HANDLED; -} - -/* - * Name the MSI-X interrupts. - */ -static void name_msix_vecs(struct adapter *adap) -{ - int i, j, msi_idx = 2, n = sizeof(adap->msix_info[0].desc); - - /* non-data interrupts */ - snprintf(adap->msix_info[0].desc, n, "%s", adap->port[0]->name); - - /* FW events */ - snprintf(adap->msix_info[1].desc, n, "%s-FWeventq", - adap->port[0]->name); - - /* Ethernet queues */ - for_each_port(adap, j) { - struct net_device *d = adap->port[j]; - const struct port_info *pi = netdev_priv(d); - - for (i = 0; i < pi->nqsets; i++, msi_idx++) - snprintf(adap->msix_info[msi_idx].desc, n, "%s-Rx%d", - d->name, i); - } - - /* offload queues */ - for_each_ofldrxq(&adap->sge, i) - snprintf(adap->msix_info[msi_idx++].desc, n, "%s-ofld%d", - adap->port[0]->name, i); - - for_each_rdmarxq(&adap->sge, i) - snprintf(adap->msix_info[msi_idx++].desc, n, "%s-rdma%d", - adap->port[0]->name, i); -} - -static int request_msix_queue_irqs(struct adapter *adap) -{ - struct sge *s = &adap->sge; - int err, ethqidx, ofldqidx = 0, rdmaqidx = 0, msi = 2; - - err = request_irq(adap->msix_info[1].vec, t4_sge_intr_msix, 0, - adap->msix_info[1].desc, &s->fw_evtq); - if (err) - return err; - - for_each_ethrxq(s, ethqidx) { - err = request_irq(adap->msix_info[msi].vec, t4_sge_intr_msix, 0, - adap->msix_info[msi].desc, - &s->ethrxq[ethqidx].rspq); - if (err) - goto unwind; - msi++; - } - for_each_ofldrxq(s, ofldqidx) { - err = request_irq(adap->msix_info[msi].vec, t4_sge_intr_msix, 0, - adap->msix_info[msi].desc, - &s->ofldrxq[ofldqidx].rspq); - if (err) - goto unwind; - msi++; - } - for_each_rdmarxq(s, rdmaqidx) { - err = request_irq(adap->msix_info[msi].vec, t4_sge_intr_msix, 0, - adap->msix_info[msi].desc, - &s->rdmarxq[rdmaqidx].rspq); - if (err) - goto unwind; - msi++; - } - return 0; - -unwind: - while (--rdmaqidx >= 0) - free_irq(adap->msix_info[--msi].vec, - &s->rdmarxq[rdmaqidx].rspq); - while (--ofldqidx >= 0) - free_irq(adap->msix_info[--msi].vec, - &s->ofldrxq[ofldqidx].rspq); - while (--ethqidx >= 0) - free_irq(adap->msix_info[--msi].vec, &s->ethrxq[ethqidx].rspq); - free_irq(adap->msix_info[1].vec, &s->fw_evtq); - return err; -} - -static void free_msix_queue_irqs(struct adapter *adap) -{ - int i, msi = 2; - struct sge *s = &adap->sge; - - free_irq(adap->msix_info[1].vec, &s->fw_evtq); - for_each_ethrxq(s, i) - free_irq(adap->msix_info[msi++].vec, &s->ethrxq[i].rspq); - for_each_ofldrxq(s, i) - free_irq(adap->msix_info[msi++].vec, &s->ofldrxq[i].rspq); - for_each_rdmarxq(s, i) - free_irq(adap->msix_info[msi++].vec, &s->rdmarxq[i].rspq); -} - -/** - * write_rss - write the RSS table for a given port - * @pi: the port - * @queues: array of queue indices for RSS - * - * Sets up the portion of the HW RSS table for the port's VI to distribute - * packets to the Rx queues in @queues. - */ -static int write_rss(const struct port_info *pi, const u16 *queues) -{ - u16 *rss; - int i, err; - const struct sge_eth_rxq *q = &pi->adapter->sge.ethrxq[pi->first_qset]; - - rss = kmalloc(pi->rss_size * sizeof(u16), GFP_KERNEL); - if (!rss) - return -ENOMEM; - - /* map the queue indices to queue ids */ - for (i = 0; i < pi->rss_size; i++, queues++) - rss[i] = q[*queues].rspq.abs_id; - - err = t4_config_rss_range(pi->adapter, pi->adapter->fn, pi->viid, 0, - pi->rss_size, rss, pi->rss_size); - kfree(rss); - return err; -} - -/** - * setup_rss - configure RSS - * @adap: the adapter - * - * Sets up RSS for each port. - */ -static int setup_rss(struct adapter *adap) -{ - int i, err; - - for_each_port(adap, i) { - const struct port_info *pi = adap2pinfo(adap, i); - - err = write_rss(pi, pi->rss); - if (err) - return err; - } - return 0; -} - -/* - * Return the channel of the ingress queue with the given qid. - */ -static unsigned int rxq_to_chan(const struct sge *p, unsigned int qid) -{ - qid -= p->ingr_start; - return netdev2pinfo(p->ingr_map[qid]->netdev)->tx_chan; -} - -/* - * Wait until all NAPI handlers are descheduled. - */ -static void quiesce_rx(struct adapter *adap) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(adap->sge.ingr_map); i++) { - struct sge_rspq *q = adap->sge.ingr_map[i]; - - if (q && q->handler) - napi_disable(&q->napi); - } -} - -/* - * Enable NAPI scheduling and interrupt generation for all Rx queues. - */ -static void enable_rx(struct adapter *adap) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(adap->sge.ingr_map); i++) { - struct sge_rspq *q = adap->sge.ingr_map[i]; - - if (!q) - continue; - if (q->handler) - napi_enable(&q->napi); - /* 0-increment GTS to start the timer and enable interrupts */ - t4_write_reg(adap, MYPF_REG(SGE_PF_GTS), - SEINTARM(q->intr_params) | - INGRESSQID(q->cntxt_id)); - } -} - -/** - * setup_sge_queues - configure SGE Tx/Rx/response queues - * @adap: the adapter - * - * Determines how many sets of SGE queues to use and initializes them. - * We support multiple queue sets per port if we have MSI-X, otherwise - * just one queue set per port. - */ -static int setup_sge_queues(struct adapter *adap) -{ - int err, msi_idx, i, j; - struct sge *s = &adap->sge; - - bitmap_zero(s->starving_fl, MAX_EGRQ); - bitmap_zero(s->txq_maperr, MAX_EGRQ); - - if (adap->flags & USING_MSIX) - msi_idx = 1; /* vector 0 is for non-queue interrupts */ - else { - err = t4_sge_alloc_rxq(adap, &s->intrq, false, adap->port[0], 0, - NULL, NULL); - if (err) - return err; - msi_idx = -((int)s->intrq.abs_id + 1); - } - - err = t4_sge_alloc_rxq(adap, &s->fw_evtq, true, adap->port[0], - msi_idx, NULL, fwevtq_handler); - if (err) { -freeout: t4_free_sge_resources(adap); - return err; - } - - for_each_port(adap, i) { - struct net_device *dev = adap->port[i]; - struct port_info *pi = netdev_priv(dev); - struct sge_eth_rxq *q = &s->ethrxq[pi->first_qset]; - struct sge_eth_txq *t = &s->ethtxq[pi->first_qset]; - - for (j = 0; j < pi->nqsets; j++, q++) { - if (msi_idx > 0) - msi_idx++; - err = t4_sge_alloc_rxq(adap, &q->rspq, false, dev, - msi_idx, &q->fl, - t4_ethrx_handler); - if (err) - goto freeout; - q->rspq.idx = j; - memset(&q->stats, 0, sizeof(q->stats)); - } - for (j = 0; j < pi->nqsets; j++, t++) { - err = t4_sge_alloc_eth_txq(adap, t, dev, - netdev_get_tx_queue(dev, j), - s->fw_evtq.cntxt_id); - if (err) - goto freeout; - } - } - - j = s->ofldqsets / adap->params.nports; /* ofld queues per channel */ - for_each_ofldrxq(s, i) { - struct sge_ofld_rxq *q = &s->ofldrxq[i]; - struct net_device *dev = adap->port[i / j]; - - if (msi_idx > 0) - msi_idx++; - err = t4_sge_alloc_rxq(adap, &q->rspq, false, dev, msi_idx, - &q->fl, uldrx_handler); - if (err) - goto freeout; - memset(&q->stats, 0, sizeof(q->stats)); - s->ofld_rxq[i] = q->rspq.abs_id; - err = t4_sge_alloc_ofld_txq(adap, &s->ofldtxq[i], dev, - s->fw_evtq.cntxt_id); - if (err) - goto freeout; - } - - for_each_rdmarxq(s, i) { - struct sge_ofld_rxq *q = &s->rdmarxq[i]; - - if (msi_idx > 0) - msi_idx++; - err = t4_sge_alloc_rxq(adap, &q->rspq, false, adap->port[i], - msi_idx, &q->fl, uldrx_handler); - if (err) - goto freeout; - memset(&q->stats, 0, sizeof(q->stats)); - s->rdma_rxq[i] = q->rspq.abs_id; - } - - for_each_port(adap, i) { - /* - * Note that ->rdmarxq[i].rspq.cntxt_id below is 0 if we don't - * have RDMA queues, and that's the right value. - */ - err = t4_sge_alloc_ctrl_txq(adap, &s->ctrlq[i], adap->port[i], - s->fw_evtq.cntxt_id, - s->rdmarxq[i].rspq.cntxt_id); - if (err) - goto freeout; - } - - t4_write_reg(adap, MPS_TRC_RSS_CONTROL, - RSSCONTROL(netdev2pinfo(adap->port[0])->tx_chan) | - QUEUENUMBER(s->ethrxq[0].rspq.abs_id)); - return 0; -} - -/* - * Returns 0 if new FW was successfully loaded, a positive errno if a load was - * started but failed, and a negative errno if flash load couldn't start. - */ -static int upgrade_fw(struct adapter *adap) -{ - int ret; - u32 vers; - const struct fw_hdr *hdr; - const struct firmware *fw; - struct device *dev = adap->pdev_dev; - - ret = request_firmware(&fw, FW_FNAME, dev); - if (ret < 0) { - dev_err(dev, "unable to load firmware image " FW_FNAME - ", error %d\n", ret); - return ret; - } - - hdr = (const struct fw_hdr *)fw->data; - vers = ntohl(hdr->fw_ver); - if (FW_HDR_FW_VER_MAJOR_GET(vers) != FW_VERSION_MAJOR) { - ret = -EINVAL; /* wrong major version, won't do */ - goto out; - } - - /* - * If the flash FW is unusable or we found something newer, load it. - */ - if (FW_HDR_FW_VER_MAJOR_GET(adap->params.fw_vers) != FW_VERSION_MAJOR || - vers > adap->params.fw_vers) { - ret = -t4_load_fw(adap, fw->data, fw->size); - if (!ret) - dev_info(dev, "firmware upgraded to version %pI4 from " - FW_FNAME "\n", &hdr->fw_ver); - } -out: release_firmware(fw); - return ret; -} - -/* - * Allocate a chunk of memory using kmalloc or, if that fails, vmalloc. - * The allocated memory is cleared. - */ -void *t4_alloc_mem(size_t size) -{ - void *p = kzalloc(size, GFP_KERNEL); - - if (!p) - p = vzalloc(size); - return p; -} - -/* - * Free memory allocated through alloc_mem(). - */ -static void t4_free_mem(void *addr) -{ - if (is_vmalloc_addr(addr)) - vfree(addr); - else - kfree(addr); -} - -static inline int is_offload(const struct adapter *adap) -{ - return adap->params.offload; -} - -/* - * Implementation of ethtool operations. - */ - -static u32 get_msglevel(struct net_device *dev) -{ - return netdev2adap(dev)->msg_enable; -} - -static void set_msglevel(struct net_device *dev, u32 val) -{ - netdev2adap(dev)->msg_enable = val; -} - -static char stats_strings[][ETH_GSTRING_LEN] = { - "TxOctetsOK ", - "TxFramesOK ", - "TxBroadcastFrames ", - "TxMulticastFrames ", - "TxUnicastFrames ", - "TxErrorFrames ", - - "TxFrames64 ", - "TxFrames65To127 ", - "TxFrames128To255 ", - "TxFrames256To511 ", - "TxFrames512To1023 ", - "TxFrames1024To1518 ", - "TxFrames1519ToMax ", - - "TxFramesDropped ", - "TxPauseFrames ", - "TxPPP0Frames ", - "TxPPP1Frames ", - "TxPPP2Frames ", - "TxPPP3Frames ", - "TxPPP4Frames ", - "TxPPP5Frames ", - "TxPPP6Frames ", - "TxPPP7Frames ", - - "RxOctetsOK ", - "RxFramesOK ", - "RxBroadcastFrames ", - "RxMulticastFrames ", - "RxUnicastFrames ", - - "RxFramesTooLong ", - "RxJabberErrors ", - "RxFCSErrors ", - "RxLengthErrors ", - "RxSymbolErrors ", - "RxRuntFrames ", - - "RxFrames64 ", - "RxFrames65To127 ", - "RxFrames128To255 ", - "RxFrames256To511 ", - "RxFrames512To1023 ", - "RxFrames1024To1518 ", - "RxFrames1519ToMax ", - - "RxPauseFrames ", - "RxPPP0Frames ", - "RxPPP1Frames ", - "RxPPP2Frames ", - "RxPPP3Frames ", - "RxPPP4Frames ", - "RxPPP5Frames ", - "RxPPP6Frames ", - "RxPPP7Frames ", - - "RxBG0FramesDropped ", - "RxBG1FramesDropped ", - "RxBG2FramesDropped ", - "RxBG3FramesDropped ", - "RxBG0FramesTrunc ", - "RxBG1FramesTrunc ", - "RxBG2FramesTrunc ", - "RxBG3FramesTrunc ", - - "TSO ", - "TxCsumOffload ", - "RxCsumGood ", - "VLANextractions ", - "VLANinsertions ", - "GROpackets ", - "GROmerged ", -}; - -static int get_sset_count(struct net_device *dev, int sset) -{ - switch (sset) { - case ETH_SS_STATS: - return ARRAY_SIZE(stats_strings); - default: - return -EOPNOTSUPP; - } -} - -#define T4_REGMAP_SIZE (160 * 1024) - -static int get_regs_len(struct net_device *dev) -{ - return T4_REGMAP_SIZE; -} - -static int get_eeprom_len(struct net_device *dev) -{ - return EEPROMSIZE; -} - -static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - struct adapter *adapter = netdev2adap(dev); - - strcpy(info->driver, KBUILD_MODNAME); - strcpy(info->version, DRV_VERSION); - strcpy(info->bus_info, pci_name(adapter->pdev)); - - if (!adapter->params.fw_vers) - strcpy(info->fw_version, "N/A"); - else - snprintf(info->fw_version, sizeof(info->fw_version), - "%u.%u.%u.%u, TP %u.%u.%u.%u", - FW_HDR_FW_VER_MAJOR_GET(adapter->params.fw_vers), - FW_HDR_FW_VER_MINOR_GET(adapter->params.fw_vers), - FW_HDR_FW_VER_MICRO_GET(adapter->params.fw_vers), - FW_HDR_FW_VER_BUILD_GET(adapter->params.fw_vers), - FW_HDR_FW_VER_MAJOR_GET(adapter->params.tp_vers), - FW_HDR_FW_VER_MINOR_GET(adapter->params.tp_vers), - FW_HDR_FW_VER_MICRO_GET(adapter->params.tp_vers), - FW_HDR_FW_VER_BUILD_GET(adapter->params.tp_vers)); -} - -static void get_strings(struct net_device *dev, u32 stringset, u8 *data) -{ - if (stringset == ETH_SS_STATS) - memcpy(data, stats_strings, sizeof(stats_strings)); -} - -/* - * port stats maintained per queue of the port. They should be in the same - * order as in stats_strings above. - */ -struct queue_port_stats { - u64 tso; - u64 tx_csum; - u64 rx_csum; - u64 vlan_ex; - u64 vlan_ins; - u64 gro_pkts; - u64 gro_merged; -}; - -static void collect_sge_port_stats(const struct adapter *adap, - const struct port_info *p, struct queue_port_stats *s) -{ - int i; - const struct sge_eth_txq *tx = &adap->sge.ethtxq[p->first_qset]; - const struct sge_eth_rxq *rx = &adap->sge.ethrxq[p->first_qset]; - - memset(s, 0, sizeof(*s)); - for (i = 0; i < p->nqsets; i++, rx++, tx++) { - s->tso += tx->tso; - s->tx_csum += tx->tx_cso; - s->rx_csum += rx->stats.rx_cso; - s->vlan_ex += rx->stats.vlan_ex; - s->vlan_ins += tx->vlan_ins; - s->gro_pkts += rx->stats.lro_pkts; - s->gro_merged += rx->stats.lro_merged; - } -} - -static void get_stats(struct net_device *dev, struct ethtool_stats *stats, - u64 *data) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - - t4_get_port_stats(adapter, pi->tx_chan, (struct port_stats *)data); - - data += sizeof(struct port_stats) / sizeof(u64); - collect_sge_port_stats(adapter, pi, (struct queue_port_stats *)data); -} - -/* - * Return a version number to identify the type of adapter. The scheme is: - * - bits 0..9: chip version - * - bits 10..15: chip revision - * - bits 16..23: register dump version - */ -static inline unsigned int mk_adap_vers(const struct adapter *ap) -{ - return 4 | (ap->params.rev << 10) | (1 << 16); -} - -static void reg_block_dump(struct adapter *ap, void *buf, unsigned int start, - unsigned int end) -{ - u32 *p = buf + start; - - for ( ; start <= end; start += sizeof(u32)) - *p++ = t4_read_reg(ap, start); -} - -static void get_regs(struct net_device *dev, struct ethtool_regs *regs, - void *buf) -{ - static const unsigned int reg_ranges[] = { - 0x1008, 0x1108, - 0x1180, 0x11b4, - 0x11fc, 0x123c, - 0x1300, 0x173c, - 0x1800, 0x18fc, - 0x3000, 0x30d8, - 0x30e0, 0x5924, - 0x5960, 0x59d4, - 0x5a00, 0x5af8, - 0x6000, 0x6098, - 0x6100, 0x6150, - 0x6200, 0x6208, - 0x6240, 0x6248, - 0x6280, 0x6338, - 0x6370, 0x638c, - 0x6400, 0x643c, - 0x6500, 0x6524, - 0x6a00, 0x6a38, - 0x6a60, 0x6a78, - 0x6b00, 0x6b84, - 0x6bf0, 0x6c84, - 0x6cf0, 0x6d84, - 0x6df0, 0x6e84, - 0x6ef0, 0x6f84, - 0x6ff0, 0x7084, - 0x70f0, 0x7184, - 0x71f0, 0x7284, - 0x72f0, 0x7384, - 0x73f0, 0x7450, - 0x7500, 0x7530, - 0x7600, 0x761c, - 0x7680, 0x76cc, - 0x7700, 0x7798, - 0x77c0, 0x77fc, - 0x7900, 0x79fc, - 0x7b00, 0x7c38, - 0x7d00, 0x7efc, - 0x8dc0, 0x8e1c, - 0x8e30, 0x8e78, - 0x8ea0, 0x8f6c, - 0x8fc0, 0x9074, - 0x90fc, 0x90fc, - 0x9400, 0x9458, - 0x9600, 0x96bc, - 0x9800, 0x9808, - 0x9820, 0x983c, - 0x9850, 0x9864, - 0x9c00, 0x9c6c, - 0x9c80, 0x9cec, - 0x9d00, 0x9d6c, - 0x9d80, 0x9dec, - 0x9e00, 0x9e6c, - 0x9e80, 0x9eec, - 0x9f00, 0x9f6c, - 0x9f80, 0x9fec, - 0xd004, 0xd03c, - 0xdfc0, 0xdfe0, - 0xe000, 0xea7c, - 0xf000, 0x11190, - 0x19040, 0x1906c, - 0x19078, 0x19080, - 0x1908c, 0x19124, - 0x19150, 0x191b0, - 0x191d0, 0x191e8, - 0x19238, 0x1924c, - 0x193f8, 0x19474, - 0x19490, 0x194f8, - 0x19800, 0x19f30, - 0x1a000, 0x1a06c, - 0x1a0b0, 0x1a120, - 0x1a128, 0x1a138, - 0x1a190, 0x1a1c4, - 0x1a1fc, 0x1a1fc, - 0x1e040, 0x1e04c, - 0x1e284, 0x1e28c, - 0x1e2c0, 0x1e2c0, - 0x1e2e0, 0x1e2e0, - 0x1e300, 0x1e384, - 0x1e3c0, 0x1e3c8, - 0x1e440, 0x1e44c, - 0x1e684, 0x1e68c, - 0x1e6c0, 0x1e6c0, - 0x1e6e0, 0x1e6e0, - 0x1e700, 0x1e784, - 0x1e7c0, 0x1e7c8, - 0x1e840, 0x1e84c, - 0x1ea84, 0x1ea8c, - 0x1eac0, 0x1eac0, - 0x1eae0, 0x1eae0, - 0x1eb00, 0x1eb84, - 0x1ebc0, 0x1ebc8, - 0x1ec40, 0x1ec4c, - 0x1ee84, 0x1ee8c, - 0x1eec0, 0x1eec0, - 0x1eee0, 0x1eee0, - 0x1ef00, 0x1ef84, - 0x1efc0, 0x1efc8, - 0x1f040, 0x1f04c, - 0x1f284, 0x1f28c, - 0x1f2c0, 0x1f2c0, - 0x1f2e0, 0x1f2e0, - 0x1f300, 0x1f384, - 0x1f3c0, 0x1f3c8, - 0x1f440, 0x1f44c, - 0x1f684, 0x1f68c, - 0x1f6c0, 0x1f6c0, - 0x1f6e0, 0x1f6e0, - 0x1f700, 0x1f784, - 0x1f7c0, 0x1f7c8, - 0x1f840, 0x1f84c, - 0x1fa84, 0x1fa8c, - 0x1fac0, 0x1fac0, - 0x1fae0, 0x1fae0, - 0x1fb00, 0x1fb84, - 0x1fbc0, 0x1fbc8, - 0x1fc40, 0x1fc4c, - 0x1fe84, 0x1fe8c, - 0x1fec0, 0x1fec0, - 0x1fee0, 0x1fee0, - 0x1ff00, 0x1ff84, - 0x1ffc0, 0x1ffc8, - 0x20000, 0x2002c, - 0x20100, 0x2013c, - 0x20190, 0x201c8, - 0x20200, 0x20318, - 0x20400, 0x20528, - 0x20540, 0x20614, - 0x21000, 0x21040, - 0x2104c, 0x21060, - 0x210c0, 0x210ec, - 0x21200, 0x21268, - 0x21270, 0x21284, - 0x212fc, 0x21388, - 0x21400, 0x21404, - 0x21500, 0x21518, - 0x2152c, 0x2153c, - 0x21550, 0x21554, - 0x21600, 0x21600, - 0x21608, 0x21628, - 0x21630, 0x2163c, - 0x21700, 0x2171c, - 0x21780, 0x2178c, - 0x21800, 0x21c38, - 0x21c80, 0x21d7c, - 0x21e00, 0x21e04, - 0x22000, 0x2202c, - 0x22100, 0x2213c, - 0x22190, 0x221c8, - 0x22200, 0x22318, - 0x22400, 0x22528, - 0x22540, 0x22614, - 0x23000, 0x23040, - 0x2304c, 0x23060, - 0x230c0, 0x230ec, - 0x23200, 0x23268, - 0x23270, 0x23284, - 0x232fc, 0x23388, - 0x23400, 0x23404, - 0x23500, 0x23518, - 0x2352c, 0x2353c, - 0x23550, 0x23554, - 0x23600, 0x23600, - 0x23608, 0x23628, - 0x23630, 0x2363c, - 0x23700, 0x2371c, - 0x23780, 0x2378c, - 0x23800, 0x23c38, - 0x23c80, 0x23d7c, - 0x23e00, 0x23e04, - 0x24000, 0x2402c, - 0x24100, 0x2413c, - 0x24190, 0x241c8, - 0x24200, 0x24318, - 0x24400, 0x24528, - 0x24540, 0x24614, - 0x25000, 0x25040, - 0x2504c, 0x25060, - 0x250c0, 0x250ec, - 0x25200, 0x25268, - 0x25270, 0x25284, - 0x252fc, 0x25388, - 0x25400, 0x25404, - 0x25500, 0x25518, - 0x2552c, 0x2553c, - 0x25550, 0x25554, - 0x25600, 0x25600, - 0x25608, 0x25628, - 0x25630, 0x2563c, - 0x25700, 0x2571c, - 0x25780, 0x2578c, - 0x25800, 0x25c38, - 0x25c80, 0x25d7c, - 0x25e00, 0x25e04, - 0x26000, 0x2602c, - 0x26100, 0x2613c, - 0x26190, 0x261c8, - 0x26200, 0x26318, - 0x26400, 0x26528, - 0x26540, 0x26614, - 0x27000, 0x27040, - 0x2704c, 0x27060, - 0x270c0, 0x270ec, - 0x27200, 0x27268, - 0x27270, 0x27284, - 0x272fc, 0x27388, - 0x27400, 0x27404, - 0x27500, 0x27518, - 0x2752c, 0x2753c, - 0x27550, 0x27554, - 0x27600, 0x27600, - 0x27608, 0x27628, - 0x27630, 0x2763c, - 0x27700, 0x2771c, - 0x27780, 0x2778c, - 0x27800, 0x27c38, - 0x27c80, 0x27d7c, - 0x27e00, 0x27e04 - }; - - int i; - struct adapter *ap = netdev2adap(dev); - - regs->version = mk_adap_vers(ap); - - memset(buf, 0, T4_REGMAP_SIZE); - for (i = 0; i < ARRAY_SIZE(reg_ranges); i += 2) - reg_block_dump(ap, buf, reg_ranges[i], reg_ranges[i + 1]); -} - -static int restart_autoneg(struct net_device *dev) -{ - struct port_info *p = netdev_priv(dev); - - if (!netif_running(dev)) - return -EAGAIN; - if (p->link_cfg.autoneg != AUTONEG_ENABLE) - return -EINVAL; - t4_restart_aneg(p->adapter, p->adapter->fn, p->tx_chan); - return 0; -} - -static int identify_port(struct net_device *dev, - enum ethtool_phys_id_state state) -{ - unsigned int val; - struct adapter *adap = netdev2adap(dev); - - if (state == ETHTOOL_ID_ACTIVE) - val = 0xffff; - else if (state == ETHTOOL_ID_INACTIVE) - val = 0; - else - return -EINVAL; - - return t4_identify_port(adap, adap->fn, netdev2pinfo(dev)->viid, val); -} - -static unsigned int from_fw_linkcaps(unsigned int type, unsigned int caps) -{ - unsigned int v = 0; - - if (type == FW_PORT_TYPE_BT_SGMII || type == FW_PORT_TYPE_BT_XFI || - type == FW_PORT_TYPE_BT_XAUI) { - v |= SUPPORTED_TP; - if (caps & FW_PORT_CAP_SPEED_100M) - v |= SUPPORTED_100baseT_Full; - if (caps & FW_PORT_CAP_SPEED_1G) - v |= SUPPORTED_1000baseT_Full; - if (caps & FW_PORT_CAP_SPEED_10G) - v |= SUPPORTED_10000baseT_Full; - } else if (type == FW_PORT_TYPE_KX4 || type == FW_PORT_TYPE_KX) { - v |= SUPPORTED_Backplane; - if (caps & FW_PORT_CAP_SPEED_1G) - v |= SUPPORTED_1000baseKX_Full; - if (caps & FW_PORT_CAP_SPEED_10G) - v |= SUPPORTED_10000baseKX4_Full; - } else if (type == FW_PORT_TYPE_KR) - v |= SUPPORTED_Backplane | SUPPORTED_10000baseKR_Full; - else if (type == FW_PORT_TYPE_BP_AP) - v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC | - SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full; - else if (type == FW_PORT_TYPE_BP4_AP) - v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC | - SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full | - SUPPORTED_10000baseKX4_Full; - else if (type == FW_PORT_TYPE_FIBER_XFI || - type == FW_PORT_TYPE_FIBER_XAUI || type == FW_PORT_TYPE_SFP) - v |= SUPPORTED_FIBRE; - - if (caps & FW_PORT_CAP_ANEG) - v |= SUPPORTED_Autoneg; - return v; -} - -static unsigned int to_fw_linkcaps(unsigned int caps) -{ - unsigned int v = 0; - - if (caps & ADVERTISED_100baseT_Full) - v |= FW_PORT_CAP_SPEED_100M; - if (caps & ADVERTISED_1000baseT_Full) - v |= FW_PORT_CAP_SPEED_1G; - if (caps & ADVERTISED_10000baseT_Full) - v |= FW_PORT_CAP_SPEED_10G; - return v; -} - -static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - const struct port_info *p = netdev_priv(dev); - - if (p->port_type == FW_PORT_TYPE_BT_SGMII || - p->port_type == FW_PORT_TYPE_BT_XFI || - p->port_type == FW_PORT_TYPE_BT_XAUI) - cmd->port = PORT_TP; - else if (p->port_type == FW_PORT_TYPE_FIBER_XFI || - p->port_type == FW_PORT_TYPE_FIBER_XAUI) - cmd->port = PORT_FIBRE; - else if (p->port_type == FW_PORT_TYPE_SFP) { - if (p->mod_type == FW_PORT_MOD_TYPE_TWINAX_PASSIVE || - p->mod_type == FW_PORT_MOD_TYPE_TWINAX_ACTIVE) - cmd->port = PORT_DA; - else - cmd->port = PORT_FIBRE; - } else - cmd->port = PORT_OTHER; - - if (p->mdio_addr >= 0) { - cmd->phy_address = p->mdio_addr; - cmd->transceiver = XCVR_EXTERNAL; - cmd->mdio_support = p->port_type == FW_PORT_TYPE_BT_SGMII ? - MDIO_SUPPORTS_C22 : MDIO_SUPPORTS_C45; - } else { - cmd->phy_address = 0; /* not really, but no better option */ - cmd->transceiver = XCVR_INTERNAL; - cmd->mdio_support = 0; - } - - cmd->supported = from_fw_linkcaps(p->port_type, p->link_cfg.supported); - cmd->advertising = from_fw_linkcaps(p->port_type, - p->link_cfg.advertising); - ethtool_cmd_speed_set(cmd, - netif_carrier_ok(dev) ? p->link_cfg.speed : 0); - cmd->duplex = DUPLEX_FULL; - cmd->autoneg = p->link_cfg.autoneg; - cmd->maxtxpkt = 0; - cmd->maxrxpkt = 0; - return 0; -} - -static unsigned int speed_to_caps(int speed) -{ - if (speed == SPEED_100) - return FW_PORT_CAP_SPEED_100M; - if (speed == SPEED_1000) - return FW_PORT_CAP_SPEED_1G; - if (speed == SPEED_10000) - return FW_PORT_CAP_SPEED_10G; - return 0; -} - -static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - unsigned int cap; - struct port_info *p = netdev_priv(dev); - struct link_config *lc = &p->link_cfg; - u32 speed = ethtool_cmd_speed(cmd); - - if (cmd->duplex != DUPLEX_FULL) /* only full-duplex supported */ - return -EINVAL; - - if (!(lc->supported & FW_PORT_CAP_ANEG)) { - /* - * PHY offers a single speed. See if that's what's - * being requested. - */ - if (cmd->autoneg == AUTONEG_DISABLE && - (lc->supported & speed_to_caps(speed))) - return 0; - return -EINVAL; - } - - if (cmd->autoneg == AUTONEG_DISABLE) { - cap = speed_to_caps(speed); - - if (!(lc->supported & cap) || (speed == SPEED_1000) || - (speed == SPEED_10000)) - return -EINVAL; - lc->requested_speed = cap; - lc->advertising = 0; - } else { - cap = to_fw_linkcaps(cmd->advertising); - if (!(lc->supported & cap)) - return -EINVAL; - lc->requested_speed = 0; - lc->advertising = cap | FW_PORT_CAP_ANEG; - } - lc->autoneg = cmd->autoneg; - - if (netif_running(dev)) - return t4_link_start(p->adapter, p->adapter->fn, p->tx_chan, - lc); - return 0; -} - -static void get_pauseparam(struct net_device *dev, - struct ethtool_pauseparam *epause) -{ - struct port_info *p = netdev_priv(dev); - - epause->autoneg = (p->link_cfg.requested_fc & PAUSE_AUTONEG) != 0; - epause->rx_pause = (p->link_cfg.fc & PAUSE_RX) != 0; - epause->tx_pause = (p->link_cfg.fc & PAUSE_TX) != 0; -} - -static int set_pauseparam(struct net_device *dev, - struct ethtool_pauseparam *epause) -{ - struct port_info *p = netdev_priv(dev); - struct link_config *lc = &p->link_cfg; - - if (epause->autoneg == AUTONEG_DISABLE) - lc->requested_fc = 0; - else if (lc->supported & FW_PORT_CAP_ANEG) - lc->requested_fc = PAUSE_AUTONEG; - else - return -EINVAL; - - if (epause->rx_pause) - lc->requested_fc |= PAUSE_RX; - if (epause->tx_pause) - lc->requested_fc |= PAUSE_TX; - if (netif_running(dev)) - return t4_link_start(p->adapter, p->adapter->fn, p->tx_chan, - lc); - return 0; -} - -static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) -{ - const struct port_info *pi = netdev_priv(dev); - const struct sge *s = &pi->adapter->sge; - - e->rx_max_pending = MAX_RX_BUFFERS; - e->rx_mini_max_pending = MAX_RSPQ_ENTRIES; - e->rx_jumbo_max_pending = 0; - e->tx_max_pending = MAX_TXQ_ENTRIES; - - e->rx_pending = s->ethrxq[pi->first_qset].fl.size - 8; - e->rx_mini_pending = s->ethrxq[pi->first_qset].rspq.size; - e->rx_jumbo_pending = 0; - e->tx_pending = s->ethtxq[pi->first_qset].q.size; -} - -static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e) -{ - int i; - const struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - struct sge *s = &adapter->sge; - - if (e->rx_pending > MAX_RX_BUFFERS || e->rx_jumbo_pending || - e->tx_pending > MAX_TXQ_ENTRIES || - e->rx_mini_pending > MAX_RSPQ_ENTRIES || - e->rx_mini_pending < MIN_RSPQ_ENTRIES || - e->rx_pending < MIN_FL_ENTRIES || e->tx_pending < MIN_TXQ_ENTRIES) - return -EINVAL; - - if (adapter->flags & FULL_INIT_DONE) - return -EBUSY; - - for (i = 0; i < pi->nqsets; ++i) { - s->ethtxq[pi->first_qset + i].q.size = e->tx_pending; - s->ethrxq[pi->first_qset + i].fl.size = e->rx_pending + 8; - s->ethrxq[pi->first_qset + i].rspq.size = e->rx_mini_pending; - } - return 0; -} - -static int closest_timer(const struct sge *s, int time) -{ - int i, delta, match = 0, min_delta = INT_MAX; - - for (i = 0; i < ARRAY_SIZE(s->timer_val); i++) { - delta = time - s->timer_val[i]; - if (delta < 0) - delta = -delta; - if (delta < min_delta) { - min_delta = delta; - match = i; - } - } - return match; -} - -static int closest_thres(const struct sge *s, int thres) -{ - int i, delta, match = 0, min_delta = INT_MAX; - - for (i = 0; i < ARRAY_SIZE(s->counter_val); i++) { - delta = thres - s->counter_val[i]; - if (delta < 0) - delta = -delta; - if (delta < min_delta) { - min_delta = delta; - match = i; - } - } - return match; -} - -/* - * Return a queue's interrupt hold-off time in us. 0 means no timer. - */ -static unsigned int qtimer_val(const struct adapter *adap, - const struct sge_rspq *q) -{ - unsigned int idx = q->intr_params >> 1; - - return idx < SGE_NTIMERS ? adap->sge.timer_val[idx] : 0; -} - -/** - * set_rxq_intr_params - set a queue's interrupt holdoff parameters - * @adap: the adapter - * @q: the Rx queue - * @us: the hold-off time in us, or 0 to disable timer - * @cnt: the hold-off packet count, or 0 to disable counter - * - * Sets an Rx queue's interrupt hold-off time and packet count. At least - * one of the two needs to be enabled for the queue to generate interrupts. - */ -static int set_rxq_intr_params(struct adapter *adap, struct sge_rspq *q, - unsigned int us, unsigned int cnt) -{ - if ((us | cnt) == 0) - cnt = 1; - - if (cnt) { - int err; - u32 v, new_idx; - - new_idx = closest_thres(&adap->sge, cnt); - if (q->desc && q->pktcnt_idx != new_idx) { - /* the queue has already been created, update it */ - v = FW_PARAMS_MNEM(FW_PARAMS_MNEM_DMAQ) | - FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DMAQ_IQ_INTCNTTHRESH) | - FW_PARAMS_PARAM_YZ(q->cntxt_id); - err = t4_set_params(adap, adap->fn, adap->fn, 0, 1, &v, - &new_idx); - if (err) - return err; - } - q->pktcnt_idx = new_idx; - } - - us = us == 0 ? 6 : closest_timer(&adap->sge, us); - q->intr_params = QINTR_TIMER_IDX(us) | (cnt > 0 ? QINTR_CNT_EN : 0); - return 0; -} - -static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c) -{ - const struct port_info *pi = netdev_priv(dev); - struct adapter *adap = pi->adapter; - - return set_rxq_intr_params(adap, &adap->sge.ethrxq[pi->first_qset].rspq, - c->rx_coalesce_usecs, c->rx_max_coalesced_frames); -} - -static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c) -{ - const struct port_info *pi = netdev_priv(dev); - const struct adapter *adap = pi->adapter; - const struct sge_rspq *rq = &adap->sge.ethrxq[pi->first_qset].rspq; - - c->rx_coalesce_usecs = qtimer_val(adap, rq); - c->rx_max_coalesced_frames = (rq->intr_params & QINTR_CNT_EN) ? - adap->sge.counter_val[rq->pktcnt_idx] : 0; - return 0; -} - -/** - * eeprom_ptov - translate a physical EEPROM address to virtual - * @phys_addr: the physical EEPROM address - * @fn: the PCI function number - * @sz: size of function-specific area - * - * Translate a physical EEPROM address to virtual. The first 1K is - * accessed through virtual addresses starting at 31K, the rest is - * accessed through virtual addresses starting at 0. - * - * The mapping is as follows: - * [0..1K) -> [31K..32K) - * [1K..1K+A) -> [31K-A..31K) - * [1K+A..ES) -> [0..ES-A-1K) - * - * where A = @fn * @sz, and ES = EEPROM size. - */ -static int eeprom_ptov(unsigned int phys_addr, unsigned int fn, unsigned int sz) -{ - fn *= sz; - if (phys_addr < 1024) - return phys_addr + (31 << 10); - if (phys_addr < 1024 + fn) - return 31744 - fn + phys_addr - 1024; - if (phys_addr < EEPROMSIZE) - return phys_addr - 1024 - fn; - return -EINVAL; -} - -/* - * The next two routines implement eeprom read/write from physical addresses. - */ -static int eeprom_rd_phys(struct adapter *adap, unsigned int phys_addr, u32 *v) -{ - int vaddr = eeprom_ptov(phys_addr, adap->fn, EEPROMPFSIZE); - - if (vaddr >= 0) - vaddr = pci_read_vpd(adap->pdev, vaddr, sizeof(u32), v); - return vaddr < 0 ? vaddr : 0; -} - -static int eeprom_wr_phys(struct adapter *adap, unsigned int phys_addr, u32 v) -{ - int vaddr = eeprom_ptov(phys_addr, adap->fn, EEPROMPFSIZE); - - if (vaddr >= 0) - vaddr = pci_write_vpd(adap->pdev, vaddr, sizeof(u32), &v); - return vaddr < 0 ? vaddr : 0; -} - -#define EEPROM_MAGIC 0x38E2F10C - -static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e, - u8 *data) -{ - int i, err = 0; - struct adapter *adapter = netdev2adap(dev); - - u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - e->magic = EEPROM_MAGIC; - for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4) - err = eeprom_rd_phys(adapter, i, (u32 *)&buf[i]); - - if (!err) - memcpy(data, buf + e->offset, e->len); - kfree(buf); - return err; -} - -static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, - u8 *data) -{ - u8 *buf; - int err = 0; - u32 aligned_offset, aligned_len, *p; - struct adapter *adapter = netdev2adap(dev); - - if (eeprom->magic != EEPROM_MAGIC) - return -EINVAL; - - aligned_offset = eeprom->offset & ~3; - aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3; - - if (adapter->fn > 0) { - u32 start = 1024 + adapter->fn * EEPROMPFSIZE; - - if (aligned_offset < start || - aligned_offset + aligned_len > start + EEPROMPFSIZE) - return -EPERM; - } - - if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) { - /* - * RMW possibly needed for first or last words. - */ - buf = kmalloc(aligned_len, GFP_KERNEL); - if (!buf) - return -ENOMEM; - err = eeprom_rd_phys(adapter, aligned_offset, (u32 *)buf); - if (!err && aligned_len > 4) - err = eeprom_rd_phys(adapter, - aligned_offset + aligned_len - 4, - (u32 *)&buf[aligned_len - 4]); - if (err) - goto out; - memcpy(buf + (eeprom->offset & 3), data, eeprom->len); - } else - buf = data; - - err = t4_seeprom_wp(adapter, false); - if (err) - goto out; - - for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) { - err = eeprom_wr_phys(adapter, aligned_offset, *p); - aligned_offset += 4; - } - - if (!err) - err = t4_seeprom_wp(adapter, true); -out: - if (buf != data) - kfree(buf); - return err; -} - -static int set_flash(struct net_device *netdev, struct ethtool_flash *ef) -{ - int ret; - const struct firmware *fw; - struct adapter *adap = netdev2adap(netdev); - - ef->data[sizeof(ef->data) - 1] = '\0'; - ret = request_firmware(&fw, ef->data, adap->pdev_dev); - if (ret < 0) - return ret; - - ret = t4_load_fw(adap, fw->data, fw->size); - release_firmware(fw); - if (!ret) - dev_info(adap->pdev_dev, "loaded firmware %s\n", ef->data); - return ret; -} - -#define WOL_SUPPORTED (WAKE_BCAST | WAKE_MAGIC) -#define BCAST_CRC 0xa0ccc1a6 - -static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) -{ - wol->supported = WAKE_BCAST | WAKE_MAGIC; - wol->wolopts = netdev2adap(dev)->wol; - memset(&wol->sopass, 0, sizeof(wol->sopass)); -} - -static int set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) -{ - int err = 0; - struct port_info *pi = netdev_priv(dev); - - if (wol->wolopts & ~WOL_SUPPORTED) - return -EINVAL; - t4_wol_magic_enable(pi->adapter, pi->tx_chan, - (wol->wolopts & WAKE_MAGIC) ? dev->dev_addr : NULL); - if (wol->wolopts & WAKE_BCAST) { - err = t4_wol_pat_enable(pi->adapter, pi->tx_chan, 0xfe, ~0ULL, - ~0ULL, 0, false); - if (!err) - err = t4_wol_pat_enable(pi->adapter, pi->tx_chan, 1, - ~6ULL, ~0ULL, BCAST_CRC, true); - } else - t4_wol_pat_enable(pi->adapter, pi->tx_chan, 0, 0, 0, 0, false); - return err; -} - -static int cxgb_set_features(struct net_device *dev, u32 features) -{ - const struct port_info *pi = netdev_priv(dev); - u32 changed = dev->features ^ features; - int err; - - if (!(changed & NETIF_F_HW_VLAN_RX)) - return 0; - - err = t4_set_rxmode(pi->adapter, pi->adapter->fn, pi->viid, -1, - -1, -1, -1, - !!(features & NETIF_F_HW_VLAN_RX), true); - if (unlikely(err)) - dev->features = features ^ NETIF_F_HW_VLAN_RX; - return err; -} - -static int get_rss_table(struct net_device *dev, struct ethtool_rxfh_indir *p) -{ - const struct port_info *pi = netdev_priv(dev); - unsigned int n = min_t(unsigned int, p->size, pi->rss_size); - - p->size = pi->rss_size; - while (n--) - p->ring_index[n] = pi->rss[n]; - return 0; -} - -static int set_rss_table(struct net_device *dev, - const struct ethtool_rxfh_indir *p) -{ - unsigned int i; - struct port_info *pi = netdev_priv(dev); - - if (p->size != pi->rss_size) - return -EINVAL; - for (i = 0; i < p->size; i++) - if (p->ring_index[i] >= pi->nqsets) - return -EINVAL; - for (i = 0; i < p->size; i++) - pi->rss[i] = p->ring_index[i]; - if (pi->adapter->flags & FULL_INIT_DONE) - return write_rss(pi, pi->rss); - return 0; -} - -static int get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, - void *rules) -{ - const struct port_info *pi = netdev_priv(dev); - - switch (info->cmd) { - case ETHTOOL_GRXFH: { - unsigned int v = pi->rss_mode; - - info->data = 0; - switch (info->flow_type) { - case TCP_V4_FLOW: - if (v & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN) - info->data = RXH_IP_SRC | RXH_IP_DST | - RXH_L4_B_0_1 | RXH_L4_B_2_3; - else if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN) - info->data = RXH_IP_SRC | RXH_IP_DST; - break; - case UDP_V4_FLOW: - if ((v & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN) && - (v & FW_RSS_VI_CONFIG_CMD_UDPEN)) - info->data = RXH_IP_SRC | RXH_IP_DST | - RXH_L4_B_0_1 | RXH_L4_B_2_3; - else if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN) - info->data = RXH_IP_SRC | RXH_IP_DST; - break; - case SCTP_V4_FLOW: - case AH_ESP_V4_FLOW: - case IPV4_FLOW: - if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN) - info->data = RXH_IP_SRC | RXH_IP_DST; - break; - case TCP_V6_FLOW: - if (v & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN) - info->data = RXH_IP_SRC | RXH_IP_DST | - RXH_L4_B_0_1 | RXH_L4_B_2_3; - else if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN) - info->data = RXH_IP_SRC | RXH_IP_DST; - break; - case UDP_V6_FLOW: - if ((v & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN) && - (v & FW_RSS_VI_CONFIG_CMD_UDPEN)) - info->data = RXH_IP_SRC | RXH_IP_DST | - RXH_L4_B_0_1 | RXH_L4_B_2_3; - else if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN) - info->data = RXH_IP_SRC | RXH_IP_DST; - break; - case SCTP_V6_FLOW: - case AH_ESP_V6_FLOW: - case IPV6_FLOW: - if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN) - info->data = RXH_IP_SRC | RXH_IP_DST; - break; - } - return 0; - } - case ETHTOOL_GRXRINGS: - info->data = pi->nqsets; - return 0; - } - return -EOPNOTSUPP; -} - -static struct ethtool_ops cxgb_ethtool_ops = { - .get_settings = get_settings, - .set_settings = set_settings, - .get_drvinfo = get_drvinfo, - .get_msglevel = get_msglevel, - .set_msglevel = set_msglevel, - .get_ringparam = get_sge_param, - .set_ringparam = set_sge_param, - .get_coalesce = get_coalesce, - .set_coalesce = set_coalesce, - .get_eeprom_len = get_eeprom_len, - .get_eeprom = get_eeprom, - .set_eeprom = set_eeprom, - .get_pauseparam = get_pauseparam, - .set_pauseparam = set_pauseparam, - .get_link = ethtool_op_get_link, - .get_strings = get_strings, - .set_phys_id = identify_port, - .nway_reset = restart_autoneg, - .get_sset_count = get_sset_count, - .get_ethtool_stats = get_stats, - .get_regs_len = get_regs_len, - .get_regs = get_regs, - .get_wol = get_wol, - .set_wol = set_wol, - .get_rxnfc = get_rxnfc, - .get_rxfh_indir = get_rss_table, - .set_rxfh_indir = set_rss_table, - .flash_device = set_flash, -}; - -/* - * debugfs support - */ - -static int mem_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t mem_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) -{ - loff_t pos = *ppos; - loff_t avail = file->f_path.dentry->d_inode->i_size; - unsigned int mem = (uintptr_t)file->private_data & 3; - struct adapter *adap = file->private_data - mem; - - if (pos < 0) - return -EINVAL; - if (pos >= avail) - return 0; - if (count > avail - pos) - count = avail - pos; - - while (count) { - size_t len; - int ret, ofst; - __be32 data[16]; - - if (mem == MEM_MC) - ret = t4_mc_read(adap, pos, data, NULL); - else - ret = t4_edc_read(adap, mem, pos, data, NULL); - if (ret) - return ret; - - ofst = pos % sizeof(data); - len = min(count, sizeof(data) - ofst); - if (copy_to_user(buf, (u8 *)data + ofst, len)) - return -EFAULT; - - buf += len; - pos += len; - count -= len; - } - count = pos - *ppos; - *ppos = pos; - return count; -} - -static const struct file_operations mem_debugfs_fops = { - .owner = THIS_MODULE, - .open = mem_open, - .read = mem_read, - .llseek = default_llseek, -}; - -static void __devinit add_debugfs_mem(struct adapter *adap, const char *name, - unsigned int idx, unsigned int size_mb) -{ - struct dentry *de; - - de = debugfs_create_file(name, S_IRUSR, adap->debugfs_root, - (void *)adap + idx, &mem_debugfs_fops); - if (de && de->d_inode) - de->d_inode->i_size = size_mb << 20; -} - -static int __devinit setup_debugfs(struct adapter *adap) -{ - int i; - - if (IS_ERR_OR_NULL(adap->debugfs_root)) - return -1; - - i = t4_read_reg(adap, MA_TARGET_MEM_ENABLE); - if (i & EDRAM0_ENABLE) - add_debugfs_mem(adap, "edc0", MEM_EDC0, 5); - if (i & EDRAM1_ENABLE) - add_debugfs_mem(adap, "edc1", MEM_EDC1, 5); - if (i & EXT_MEM_ENABLE) - add_debugfs_mem(adap, "mc", MEM_MC, - EXT_MEM_SIZE_GET(t4_read_reg(adap, MA_EXT_MEMORY_BAR))); - if (adap->l2t) - debugfs_create_file("l2t", S_IRUSR, adap->debugfs_root, adap, - &t4_l2t_fops); - return 0; -} - -/* - * upper-layer driver support - */ - -/* - * Allocate an active-open TID and set it to the supplied value. - */ -int cxgb4_alloc_atid(struct tid_info *t, void *data) -{ - int atid = -1; - - spin_lock_bh(&t->atid_lock); - if (t->afree) { - union aopen_entry *p = t->afree; - - atid = p - t->atid_tab; - t->afree = p->next; - p->data = data; - t->atids_in_use++; - } - spin_unlock_bh(&t->atid_lock); - return atid; -} -EXPORT_SYMBOL(cxgb4_alloc_atid); - -/* - * Release an active-open TID. - */ -void cxgb4_free_atid(struct tid_info *t, unsigned int atid) -{ - union aopen_entry *p = &t->atid_tab[atid]; - - spin_lock_bh(&t->atid_lock); - p->next = t->afree; - t->afree = p; - t->atids_in_use--; - spin_unlock_bh(&t->atid_lock); -} -EXPORT_SYMBOL(cxgb4_free_atid); - -/* - * Allocate a server TID and set it to the supplied value. - */ -int cxgb4_alloc_stid(struct tid_info *t, int family, void *data) -{ - int stid; - - spin_lock_bh(&t->stid_lock); - if (family == PF_INET) { - stid = find_first_zero_bit(t->stid_bmap, t->nstids); - if (stid < t->nstids) - __set_bit(stid, t->stid_bmap); - else - stid = -1; - } else { - stid = bitmap_find_free_region(t->stid_bmap, t->nstids, 2); - if (stid < 0) - stid = -1; - } - if (stid >= 0) { - t->stid_tab[stid].data = data; - stid += t->stid_base; - t->stids_in_use++; - } - spin_unlock_bh(&t->stid_lock); - return stid; -} -EXPORT_SYMBOL(cxgb4_alloc_stid); - -/* - * Release a server TID. - */ -void cxgb4_free_stid(struct tid_info *t, unsigned int stid, int family) -{ - stid -= t->stid_base; - spin_lock_bh(&t->stid_lock); - if (family == PF_INET) - __clear_bit(stid, t->stid_bmap); - else - bitmap_release_region(t->stid_bmap, stid, 2); - t->stid_tab[stid].data = NULL; - t->stids_in_use--; - spin_unlock_bh(&t->stid_lock); -} -EXPORT_SYMBOL(cxgb4_free_stid); - -/* - * Populate a TID_RELEASE WR. Caller must properly size the skb. - */ -static void mk_tid_release(struct sk_buff *skb, unsigned int chan, - unsigned int tid) -{ - struct cpl_tid_release *req; - - set_wr_txq(skb, CPL_PRIORITY_SETUP, chan); - req = (struct cpl_tid_release *)__skb_put(skb, sizeof(*req)); - INIT_TP_WR(req, tid); - OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, tid)); -} - -/* - * Queue a TID release request and if necessary schedule a work queue to - * process it. - */ -static void cxgb4_queue_tid_release(struct tid_info *t, unsigned int chan, - unsigned int tid) -{ - void **p = &t->tid_tab[tid]; - struct adapter *adap = container_of(t, struct adapter, tids); - - spin_lock_bh(&adap->tid_release_lock); - *p = adap->tid_release_head; - /* Low 2 bits encode the Tx channel number */ - adap->tid_release_head = (void **)((uintptr_t)p | chan); - if (!adap->tid_release_task_busy) { - adap->tid_release_task_busy = true; - schedule_work(&adap->tid_release_task); - } - spin_unlock_bh(&adap->tid_release_lock); -} - -/* - * Process the list of pending TID release requests. - */ -static void process_tid_release_list(struct work_struct *work) -{ - struct sk_buff *skb; - struct adapter *adap; - - adap = container_of(work, struct adapter, tid_release_task); - - spin_lock_bh(&adap->tid_release_lock); - while (adap->tid_release_head) { - void **p = adap->tid_release_head; - unsigned int chan = (uintptr_t)p & 3; - p = (void *)p - chan; - - adap->tid_release_head = *p; - *p = NULL; - spin_unlock_bh(&adap->tid_release_lock); - - while (!(skb = alloc_skb(sizeof(struct cpl_tid_release), - GFP_KERNEL))) - schedule_timeout_uninterruptible(1); - - mk_tid_release(skb, chan, p - adap->tids.tid_tab); - t4_ofld_send(adap, skb); - spin_lock_bh(&adap->tid_release_lock); - } - adap->tid_release_task_busy = false; - spin_unlock_bh(&adap->tid_release_lock); -} - -/* - * Release a TID and inform HW. If we are unable to allocate the release - * message we defer to a work queue. - */ -void cxgb4_remove_tid(struct tid_info *t, unsigned int chan, unsigned int tid) -{ - void *old; - struct sk_buff *skb; - struct adapter *adap = container_of(t, struct adapter, tids); - - old = t->tid_tab[tid]; - skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_ATOMIC); - if (likely(skb)) { - t->tid_tab[tid] = NULL; - mk_tid_release(skb, chan, tid); - t4_ofld_send(adap, skb); - } else - cxgb4_queue_tid_release(t, chan, tid); - if (old) - atomic_dec(&t->tids_in_use); -} -EXPORT_SYMBOL(cxgb4_remove_tid); - -/* - * Allocate and initialize the TID tables. Returns 0 on success. - */ -static int tid_init(struct tid_info *t) -{ - size_t size; - unsigned int natids = t->natids; - - size = t->ntids * sizeof(*t->tid_tab) + natids * sizeof(*t->atid_tab) + - t->nstids * sizeof(*t->stid_tab) + - BITS_TO_LONGS(t->nstids) * sizeof(long); - t->tid_tab = t4_alloc_mem(size); - if (!t->tid_tab) - return -ENOMEM; - - t->atid_tab = (union aopen_entry *)&t->tid_tab[t->ntids]; - t->stid_tab = (struct serv_entry *)&t->atid_tab[natids]; - t->stid_bmap = (unsigned long *)&t->stid_tab[t->nstids]; - spin_lock_init(&t->stid_lock); - spin_lock_init(&t->atid_lock); - - t->stids_in_use = 0; - t->afree = NULL; - t->atids_in_use = 0; - atomic_set(&t->tids_in_use, 0); - - /* Setup the free list for atid_tab and clear the stid bitmap. */ - if (natids) { - while (--natids) - t->atid_tab[natids - 1].next = &t->atid_tab[natids]; - t->afree = t->atid_tab; - } - bitmap_zero(t->stid_bmap, t->nstids); - return 0; -} - -/** - * cxgb4_create_server - create an IP server - * @dev: the device - * @stid: the server TID - * @sip: local IP address to bind server to - * @sport: the server's TCP port - * @queue: queue to direct messages from this server to - * - * Create an IP server for the given port and address. - * Returns <0 on error and one of the %NET_XMIT_* values on success. - */ -int cxgb4_create_server(const struct net_device *dev, unsigned int stid, - __be32 sip, __be16 sport, unsigned int queue) -{ - unsigned int chan; - struct sk_buff *skb; - struct adapter *adap; - struct cpl_pass_open_req *req; - - skb = alloc_skb(sizeof(*req), GFP_KERNEL); - if (!skb) - return -ENOMEM; - - adap = netdev2adap(dev); - req = (struct cpl_pass_open_req *)__skb_put(skb, sizeof(*req)); - INIT_TP_WR(req, 0); - OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_PASS_OPEN_REQ, stid)); - req->local_port = sport; - req->peer_port = htons(0); - req->local_ip = sip; - req->peer_ip = htonl(0); - chan = rxq_to_chan(&adap->sge, queue); - req->opt0 = cpu_to_be64(TX_CHAN(chan)); - req->opt1 = cpu_to_be64(CONN_POLICY_ASK | - SYN_RSS_ENABLE | SYN_RSS_QUEUE(queue)); - return t4_mgmt_tx(adap, skb); -} -EXPORT_SYMBOL(cxgb4_create_server); - -/** - * cxgb4_best_mtu - find the entry in the MTU table closest to an MTU - * @mtus: the HW MTU table - * @mtu: the target MTU - * @idx: index of selected entry in the MTU table - * - * Returns the index and the value in the HW MTU table that is closest to - * but does not exceed @mtu, unless @mtu is smaller than any value in the - * table, in which case that smallest available value is selected. - */ -unsigned int cxgb4_best_mtu(const unsigned short *mtus, unsigned short mtu, - unsigned int *idx) -{ - unsigned int i = 0; - - while (i < NMTUS - 1 && mtus[i + 1] <= mtu) - ++i; - if (idx) - *idx = i; - return mtus[i]; -} -EXPORT_SYMBOL(cxgb4_best_mtu); - -/** - * cxgb4_port_chan - get the HW channel of a port - * @dev: the net device for the port - * - * Return the HW Tx channel of the given port. - */ -unsigned int cxgb4_port_chan(const struct net_device *dev) -{ - return netdev2pinfo(dev)->tx_chan; -} -EXPORT_SYMBOL(cxgb4_port_chan); - -/** - * cxgb4_port_viid - get the VI id of a port - * @dev: the net device for the port - * - * Return the VI id of the given port. - */ -unsigned int cxgb4_port_viid(const struct net_device *dev) -{ - return netdev2pinfo(dev)->viid; -} -EXPORT_SYMBOL(cxgb4_port_viid); - -/** - * cxgb4_port_idx - get the index of a port - * @dev: the net device for the port - * - * Return the index of the given port. - */ -unsigned int cxgb4_port_idx(const struct net_device *dev) -{ - return netdev2pinfo(dev)->port_id; -} -EXPORT_SYMBOL(cxgb4_port_idx); - -void cxgb4_get_tcp_stats(struct pci_dev *pdev, struct tp_tcp_stats *v4, - struct tp_tcp_stats *v6) -{ - struct adapter *adap = pci_get_drvdata(pdev); - - spin_lock(&adap->stats_lock); - t4_tp_get_tcp_stats(adap, v4, v6); - spin_unlock(&adap->stats_lock); -} -EXPORT_SYMBOL(cxgb4_get_tcp_stats); - -void cxgb4_iscsi_init(struct net_device *dev, unsigned int tag_mask, - const unsigned int *pgsz_order) -{ - struct adapter *adap = netdev2adap(dev); - - t4_write_reg(adap, ULP_RX_ISCSI_TAGMASK, tag_mask); - t4_write_reg(adap, ULP_RX_ISCSI_PSZ, HPZ0(pgsz_order[0]) | - HPZ1(pgsz_order[1]) | HPZ2(pgsz_order[2]) | - HPZ3(pgsz_order[3])); -} -EXPORT_SYMBOL(cxgb4_iscsi_init); - -static struct pci_driver cxgb4_driver; - -static void check_neigh_update(struct neighbour *neigh) -{ - const struct device *parent; - const struct net_device *netdev = neigh->dev; - - if (netdev->priv_flags & IFF_802_1Q_VLAN) - netdev = vlan_dev_real_dev(netdev); - parent = netdev->dev.parent; - if (parent && parent->driver == &cxgb4_driver.driver) - t4_l2t_update(dev_get_drvdata(parent), neigh); -} - -static int netevent_cb(struct notifier_block *nb, unsigned long event, - void *data) -{ - switch (event) { - case NETEVENT_NEIGH_UPDATE: - check_neigh_update(data); - break; - case NETEVENT_REDIRECT: - default: - break; - } - return 0; -} - -static bool netevent_registered; -static struct notifier_block cxgb4_netevent_nb = { - .notifier_call = netevent_cb -}; - -static void uld_attach(struct adapter *adap, unsigned int uld) -{ - void *handle; - struct cxgb4_lld_info lli; - - lli.pdev = adap->pdev; - lli.l2t = adap->l2t; - lli.tids = &adap->tids; - lli.ports = adap->port; - lli.vr = &adap->vres; - lli.mtus = adap->params.mtus; - if (uld == CXGB4_ULD_RDMA) { - lli.rxq_ids = adap->sge.rdma_rxq; - lli.nrxq = adap->sge.rdmaqs; - } else if (uld == CXGB4_ULD_ISCSI) { - lli.rxq_ids = adap->sge.ofld_rxq; - lli.nrxq = adap->sge.ofldqsets; - } - lli.ntxq = adap->sge.ofldqsets; - lli.nchan = adap->params.nports; - lli.nports = adap->params.nports; - lli.wr_cred = adap->params.ofldq_wr_cred; - lli.adapter_type = adap->params.rev; - lli.iscsi_iolen = MAXRXDATA_GET(t4_read_reg(adap, TP_PARA_REG2)); - lli.udb_density = 1 << QUEUESPERPAGEPF0_GET( - t4_read_reg(adap, SGE_EGRESS_QUEUES_PER_PAGE_PF) >> - (adap->fn * 4)); - lli.ucq_density = 1 << QUEUESPERPAGEPF0_GET( - t4_read_reg(adap, SGE_INGRESS_QUEUES_PER_PAGE_PF) >> - (adap->fn * 4)); - lli.gts_reg = adap->regs + MYPF_REG(SGE_PF_GTS); - lli.db_reg = adap->regs + MYPF_REG(SGE_PF_KDOORBELL); - lli.fw_vers = adap->params.fw_vers; - - handle = ulds[uld].add(&lli); - if (IS_ERR(handle)) { - dev_warn(adap->pdev_dev, - "could not attach to the %s driver, error %ld\n", - uld_str[uld], PTR_ERR(handle)); - return; - } - - adap->uld_handle[uld] = handle; - - if (!netevent_registered) { - register_netevent_notifier(&cxgb4_netevent_nb); - netevent_registered = true; - } - - if (adap->flags & FULL_INIT_DONE) - ulds[uld].state_change(handle, CXGB4_STATE_UP); -} - -static void attach_ulds(struct adapter *adap) -{ - unsigned int i; - - mutex_lock(&uld_mutex); - list_add_tail(&adap->list_node, &adapter_list); - for (i = 0; i < CXGB4_ULD_MAX; i++) - if (ulds[i].add) - uld_attach(adap, i); - mutex_unlock(&uld_mutex); -} - -static void detach_ulds(struct adapter *adap) -{ - unsigned int i; - - mutex_lock(&uld_mutex); - list_del(&adap->list_node); - for (i = 0; i < CXGB4_ULD_MAX; i++) - if (adap->uld_handle[i]) { - ulds[i].state_change(adap->uld_handle[i], - CXGB4_STATE_DETACH); - adap->uld_handle[i] = NULL; - } - if (netevent_registered && list_empty(&adapter_list)) { - unregister_netevent_notifier(&cxgb4_netevent_nb); - netevent_registered = false; - } - mutex_unlock(&uld_mutex); -} - -static void notify_ulds(struct adapter *adap, enum cxgb4_state new_state) -{ - unsigned int i; - - mutex_lock(&uld_mutex); - for (i = 0; i < CXGB4_ULD_MAX; i++) - if (adap->uld_handle[i]) - ulds[i].state_change(adap->uld_handle[i], new_state); - mutex_unlock(&uld_mutex); -} - -/** - * cxgb4_register_uld - register an upper-layer driver - * @type: the ULD type - * @p: the ULD methods - * - * Registers an upper-layer driver with this driver and notifies the ULD - * about any presently available devices that support its type. Returns - * %-EBUSY if a ULD of the same type is already registered. - */ -int cxgb4_register_uld(enum cxgb4_uld type, const struct cxgb4_uld_info *p) -{ - int ret = 0; - struct adapter *adap; - - if (type >= CXGB4_ULD_MAX) - return -EINVAL; - mutex_lock(&uld_mutex); - if (ulds[type].add) { - ret = -EBUSY; - goto out; - } - ulds[type] = *p; - list_for_each_entry(adap, &adapter_list, list_node) - uld_attach(adap, type); -out: mutex_unlock(&uld_mutex); - return ret; -} -EXPORT_SYMBOL(cxgb4_register_uld); - -/** - * cxgb4_unregister_uld - unregister an upper-layer driver - * @type: the ULD type - * - * Unregisters an existing upper-layer driver. - */ -int cxgb4_unregister_uld(enum cxgb4_uld type) -{ - struct adapter *adap; - - if (type >= CXGB4_ULD_MAX) - return -EINVAL; - mutex_lock(&uld_mutex); - list_for_each_entry(adap, &adapter_list, list_node) - adap->uld_handle[type] = NULL; - ulds[type].add = NULL; - mutex_unlock(&uld_mutex); - return 0; -} -EXPORT_SYMBOL(cxgb4_unregister_uld); - -/** - * cxgb_up - enable the adapter - * @adap: adapter being enabled - * - * Called when the first port is enabled, this function performs the - * actions necessary to make an adapter operational, such as completing - * the initialization of HW modules, and enabling interrupts. - * - * Must be called with the rtnl lock held. - */ -static int cxgb_up(struct adapter *adap) -{ - int err; - - err = setup_sge_queues(adap); - if (err) - goto out; - err = setup_rss(adap); - if (err) - goto freeq; - - if (adap->flags & USING_MSIX) { - name_msix_vecs(adap); - err = request_irq(adap->msix_info[0].vec, t4_nondata_intr, 0, - adap->msix_info[0].desc, adap); - if (err) - goto irq_err; - - err = request_msix_queue_irqs(adap); - if (err) { - free_irq(adap->msix_info[0].vec, adap); - goto irq_err; - } - } else { - err = request_irq(adap->pdev->irq, t4_intr_handler(adap), - (adap->flags & USING_MSI) ? 0 : IRQF_SHARED, - adap->port[0]->name, adap); - if (err) - goto irq_err; - } - enable_rx(adap); - t4_sge_start(adap); - t4_intr_enable(adap); - adap->flags |= FULL_INIT_DONE; - notify_ulds(adap, CXGB4_STATE_UP); - out: - return err; - irq_err: - dev_err(adap->pdev_dev, "request_irq failed, err %d\n", err); - freeq: - t4_free_sge_resources(adap); - goto out; -} - -static void cxgb_down(struct adapter *adapter) -{ - t4_intr_disable(adapter); - cancel_work_sync(&adapter->tid_release_task); - adapter->tid_release_task_busy = false; - adapter->tid_release_head = NULL; - - if (adapter->flags & USING_MSIX) { - free_msix_queue_irqs(adapter); - free_irq(adapter->msix_info[0].vec, adapter); - } else - free_irq(adapter->pdev->irq, adapter); - quiesce_rx(adapter); - t4_sge_stop(adapter); - t4_free_sge_resources(adapter); - adapter->flags &= ~FULL_INIT_DONE; -} - -/* - * net_device operations - */ -static int cxgb_open(struct net_device *dev) -{ - int err; - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - - netif_carrier_off(dev); - - if (!(adapter->flags & FULL_INIT_DONE)) { - err = cxgb_up(adapter); - if (err < 0) - return err; - } - - err = link_start(dev); - if (!err) - netif_tx_start_all_queues(dev); - return err; -} - -static int cxgb_close(struct net_device *dev) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - - netif_tx_stop_all_queues(dev); - netif_carrier_off(dev); - return t4_enable_vi(adapter, adapter->fn, pi->viid, false, false); -} - -static struct rtnl_link_stats64 *cxgb_get_stats(struct net_device *dev, - struct rtnl_link_stats64 *ns) -{ - struct port_stats stats; - struct port_info *p = netdev_priv(dev); - struct adapter *adapter = p->adapter; - - spin_lock(&adapter->stats_lock); - t4_get_port_stats(adapter, p->tx_chan, &stats); - spin_unlock(&adapter->stats_lock); - - ns->tx_bytes = stats.tx_octets; - ns->tx_packets = stats.tx_frames; - ns->rx_bytes = stats.rx_octets; - ns->rx_packets = stats.rx_frames; - ns->multicast = stats.rx_mcast_frames; - - /* detailed rx_errors */ - ns->rx_length_errors = stats.rx_jabber + stats.rx_too_long + - stats.rx_runt; - ns->rx_over_errors = 0; - ns->rx_crc_errors = stats.rx_fcs_err; - ns->rx_frame_errors = stats.rx_symbol_err; - ns->rx_fifo_errors = stats.rx_ovflow0 + stats.rx_ovflow1 + - stats.rx_ovflow2 + stats.rx_ovflow3 + - stats.rx_trunc0 + stats.rx_trunc1 + - stats.rx_trunc2 + stats.rx_trunc3; - ns->rx_missed_errors = 0; - - /* detailed tx_errors */ - ns->tx_aborted_errors = 0; - ns->tx_carrier_errors = 0; - ns->tx_fifo_errors = 0; - ns->tx_heartbeat_errors = 0; - ns->tx_window_errors = 0; - - ns->tx_errors = stats.tx_error_frames; - ns->rx_errors = stats.rx_symbol_err + stats.rx_fcs_err + - ns->rx_length_errors + stats.rx_len_err + ns->rx_fifo_errors; - return ns; -} - -static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd) -{ - unsigned int mbox; - int ret = 0, prtad, devad; - struct port_info *pi = netdev_priv(dev); - struct mii_ioctl_data *data = (struct mii_ioctl_data *)&req->ifr_data; - - switch (cmd) { - case SIOCGMIIPHY: - if (pi->mdio_addr < 0) - return -EOPNOTSUPP; - data->phy_id = pi->mdio_addr; - break; - case SIOCGMIIREG: - case SIOCSMIIREG: - if (mdio_phy_id_is_c45(data->phy_id)) { - prtad = mdio_phy_id_prtad(data->phy_id); - devad = mdio_phy_id_devad(data->phy_id); - } else if (data->phy_id < 32) { - prtad = data->phy_id; - devad = 0; - data->reg_num &= 0x1f; - } else - return -EINVAL; - - mbox = pi->adapter->fn; - if (cmd == SIOCGMIIREG) - ret = t4_mdio_rd(pi->adapter, mbox, prtad, devad, - data->reg_num, &data->val_out); - else - ret = t4_mdio_wr(pi->adapter, mbox, prtad, devad, - data->reg_num, data->val_in); - break; - default: - return -EOPNOTSUPP; - } - return ret; -} - -static void cxgb_set_rxmode(struct net_device *dev) -{ - /* unfortunately we can't return errors to the stack */ - set_rxmode(dev, -1, false); -} - -static int cxgb_change_mtu(struct net_device *dev, int new_mtu) -{ - int ret; - struct port_info *pi = netdev_priv(dev); - - if (new_mtu < 81 || new_mtu > MAX_MTU) /* accommodate SACK */ - return -EINVAL; - ret = t4_set_rxmode(pi->adapter, pi->adapter->fn, pi->viid, new_mtu, -1, - -1, -1, -1, true); - if (!ret) - dev->mtu = new_mtu; - return ret; -} - -static int cxgb_set_mac_addr(struct net_device *dev, void *p) -{ - int ret; - struct sockaddr *addr = p; - struct port_info *pi = netdev_priv(dev); - - if (!is_valid_ether_addr(addr->sa_data)) - return -EINVAL; - - ret = t4_change_mac(pi->adapter, pi->adapter->fn, pi->viid, - pi->xact_addr_filt, addr->sa_data, true, true); - if (ret < 0) - return ret; - - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - pi->xact_addr_filt = ret; - return 0; -} - -#ifdef CONFIG_NET_POLL_CONTROLLER -static void cxgb_netpoll(struct net_device *dev) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adap = pi->adapter; - - if (adap->flags & USING_MSIX) { - int i; - struct sge_eth_rxq *rx = &adap->sge.ethrxq[pi->first_qset]; - - for (i = pi->nqsets; i; i--, rx++) - t4_sge_intr_msix(0, &rx->rspq); - } else - t4_intr_handler(adap)(0, adap); -} -#endif - -static const struct net_device_ops cxgb4_netdev_ops = { - .ndo_open = cxgb_open, - .ndo_stop = cxgb_close, - .ndo_start_xmit = t4_eth_xmit, - .ndo_get_stats64 = cxgb_get_stats, - .ndo_set_rx_mode = cxgb_set_rxmode, - .ndo_set_mac_address = cxgb_set_mac_addr, - .ndo_set_features = cxgb_set_features, - .ndo_validate_addr = eth_validate_addr, - .ndo_do_ioctl = cxgb_ioctl, - .ndo_change_mtu = cxgb_change_mtu, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = cxgb_netpoll, -#endif -}; - -void t4_fatal_err(struct adapter *adap) -{ - t4_set_reg_field(adap, SGE_CONTROL, GLOBALENABLE, 0); - t4_intr_disable(adap); - dev_alert(adap->pdev_dev, "encountered fatal error, adapter stopped\n"); -} - -static void setup_memwin(struct adapter *adap) -{ - u32 bar0; - - bar0 = pci_resource_start(adap->pdev, 0); /* truncation intentional */ - t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 0), - (bar0 + MEMWIN0_BASE) | BIR(0) | - WINDOW(ilog2(MEMWIN0_APERTURE) - 10)); - t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 1), - (bar0 + MEMWIN1_BASE) | BIR(0) | - WINDOW(ilog2(MEMWIN1_APERTURE) - 10)); - t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 2), - (bar0 + MEMWIN2_BASE) | BIR(0) | - WINDOW(ilog2(MEMWIN2_APERTURE) - 10)); - if (adap->vres.ocq.size) { - unsigned int start, sz_kb; - - start = pci_resource_start(adap->pdev, 2) + - OCQ_WIN_OFFSET(adap->pdev, &adap->vres); - sz_kb = roundup_pow_of_two(adap->vres.ocq.size) >> 10; - t4_write_reg(adap, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 3), - start | BIR(1) | WINDOW(ilog2(sz_kb))); - t4_write_reg(adap, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, 3), - adap->vres.ocq.start); - t4_read_reg(adap, - PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, 3)); - } -} - -static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c) -{ - u32 v; - int ret; - - /* get device capabilities */ - memset(c, 0, sizeof(*c)); - c->op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) | - FW_CMD_REQUEST | FW_CMD_READ); - c->retval_len16 = htonl(FW_LEN16(*c)); - ret = t4_wr_mbox(adap, adap->fn, c, sizeof(*c), c); - if (ret < 0) - return ret; - - /* select capabilities we'll be using */ - if (c->niccaps & htons(FW_CAPS_CONFIG_NIC_VM)) { - if (!vf_acls) - c->niccaps ^= htons(FW_CAPS_CONFIG_NIC_VM); - else - c->niccaps = htons(FW_CAPS_CONFIG_NIC_VM); - } else if (vf_acls) { - dev_err(adap->pdev_dev, "virtualization ACLs not supported"); - return ret; - } - c->op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) | - FW_CMD_REQUEST | FW_CMD_WRITE); - ret = t4_wr_mbox(adap, adap->fn, c, sizeof(*c), NULL); - if (ret < 0) - return ret; - - ret = t4_config_glbl_rss(adap, adap->fn, - FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL, - FW_RSS_GLB_CONFIG_CMD_TNLMAPEN | - FW_RSS_GLB_CONFIG_CMD_TNLALLLKP); - if (ret < 0) - return ret; - - ret = t4_cfg_pfvf(adap, adap->fn, adap->fn, 0, MAX_EGRQ, 64, MAX_INGQ, - 0, 0, 4, 0xf, 0xf, 16, FW_CMD_CAP_PF, FW_CMD_CAP_PF); - if (ret < 0) - return ret; - - t4_sge_init(adap); - - /* tweak some settings */ - t4_write_reg(adap, TP_SHIFT_CNT, 0x64f8849); - t4_write_reg(adap, ULP_RX_TDDP_PSZ, HPZ0(PAGE_SHIFT - 12)); - t4_write_reg(adap, TP_PIO_ADDR, TP_INGRESS_CONFIG); - v = t4_read_reg(adap, TP_PIO_DATA); - t4_write_reg(adap, TP_PIO_DATA, v & ~CSUM_HAS_PSEUDO_HDR); - - /* get basic stuff going */ - return t4_early_init(adap, adap->fn); -} - -/* - * Max # of ATIDs. The absolute HW max is 16K but we keep it lower. - */ -#define MAX_ATIDS 8192U - -/* - * Phase 0 of initialization: contact FW, obtain config, perform basic init. - */ -static int adap_init0(struct adapter *adap) -{ - int ret; - u32 v, port_vec; - enum dev_state state; - u32 params[7], val[7]; - struct fw_caps_config_cmd c; - - ret = t4_check_fw_version(adap); - if (ret == -EINVAL || ret > 0) { - if (upgrade_fw(adap) >= 0) /* recache FW version */ - ret = t4_check_fw_version(adap); - } - if (ret < 0) - return ret; - - /* contact FW, request master */ - ret = t4_fw_hello(adap, adap->fn, adap->fn, MASTER_MUST, &state); - if (ret < 0) { - dev_err(adap->pdev_dev, "could not connect to FW, error %d\n", - ret); - return ret; - } - - /* reset device */ - ret = t4_fw_reset(adap, adap->fn, PIORSTMODE | PIORST); - if (ret < 0) - goto bye; - - for (v = 0; v < SGE_NTIMERS - 1; v++) - adap->sge.timer_val[v] = min(intr_holdoff[v], MAX_SGE_TIMERVAL); - adap->sge.timer_val[SGE_NTIMERS - 1] = MAX_SGE_TIMERVAL; - adap->sge.counter_val[0] = 1; - for (v = 1; v < SGE_NCOUNTERS; v++) - adap->sge.counter_val[v] = min(intr_cnt[v - 1], - THRESHOLD_3_MASK); -#define FW_PARAM_DEV(param) \ - (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \ - FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param)) - - params[0] = FW_PARAM_DEV(CCLK); - ret = t4_query_params(adap, adap->fn, adap->fn, 0, 1, params, val); - if (ret < 0) - goto bye; - adap->params.vpd.cclk = val[0]; - - ret = adap_init1(adap, &c); - if (ret < 0) - goto bye; - -#define FW_PARAM_PFVF(param) \ - (FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \ - FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param) | \ - FW_PARAMS_PARAM_Y(adap->fn)) - - params[0] = FW_PARAM_DEV(PORTVEC); - params[1] = FW_PARAM_PFVF(L2T_START); - params[2] = FW_PARAM_PFVF(L2T_END); - params[3] = FW_PARAM_PFVF(FILTER_START); - params[4] = FW_PARAM_PFVF(FILTER_END); - params[5] = FW_PARAM_PFVF(IQFLINT_START); - params[6] = FW_PARAM_PFVF(EQ_START); - ret = t4_query_params(adap, adap->fn, adap->fn, 0, 7, params, val); - if (ret < 0) - goto bye; - port_vec = val[0]; - adap->tids.ftid_base = val[3]; - adap->tids.nftids = val[4] - val[3] + 1; - adap->sge.ingr_start = val[5]; - adap->sge.egr_start = val[6]; - - if (c.ofldcaps) { - /* query offload-related parameters */ - params[0] = FW_PARAM_DEV(NTID); - params[1] = FW_PARAM_PFVF(SERVER_START); - params[2] = FW_PARAM_PFVF(SERVER_END); - params[3] = FW_PARAM_PFVF(TDDP_START); - params[4] = FW_PARAM_PFVF(TDDP_END); - params[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ); - ret = t4_query_params(adap, adap->fn, adap->fn, 0, 6, params, - val); - if (ret < 0) - goto bye; - adap->tids.ntids = val[0]; - adap->tids.natids = min(adap->tids.ntids / 2, MAX_ATIDS); - adap->tids.stid_base = val[1]; - adap->tids.nstids = val[2] - val[1] + 1; - adap->vres.ddp.start = val[3]; - adap->vres.ddp.size = val[4] - val[3] + 1; - adap->params.ofldq_wr_cred = val[5]; - adap->params.offload = 1; - } - if (c.rdmacaps) { - params[0] = FW_PARAM_PFVF(STAG_START); - params[1] = FW_PARAM_PFVF(STAG_END); - params[2] = FW_PARAM_PFVF(RQ_START); - params[3] = FW_PARAM_PFVF(RQ_END); - params[4] = FW_PARAM_PFVF(PBL_START); - params[5] = FW_PARAM_PFVF(PBL_END); - ret = t4_query_params(adap, adap->fn, adap->fn, 0, 6, params, - val); - if (ret < 0) - goto bye; - adap->vres.stag.start = val[0]; - adap->vres.stag.size = val[1] - val[0] + 1; - adap->vres.rq.start = val[2]; - adap->vres.rq.size = val[3] - val[2] + 1; - adap->vres.pbl.start = val[4]; - adap->vres.pbl.size = val[5] - val[4] + 1; - - params[0] = FW_PARAM_PFVF(SQRQ_START); - params[1] = FW_PARAM_PFVF(SQRQ_END); - params[2] = FW_PARAM_PFVF(CQ_START); - params[3] = FW_PARAM_PFVF(CQ_END); - params[4] = FW_PARAM_PFVF(OCQ_START); - params[5] = FW_PARAM_PFVF(OCQ_END); - ret = t4_query_params(adap, adap->fn, adap->fn, 0, 6, params, - val); - if (ret < 0) - goto bye; - adap->vres.qp.start = val[0]; - adap->vres.qp.size = val[1] - val[0] + 1; - adap->vres.cq.start = val[2]; - adap->vres.cq.size = val[3] - val[2] + 1; - adap->vres.ocq.start = val[4]; - adap->vres.ocq.size = val[5] - val[4] + 1; - } - if (c.iscsicaps) { - params[0] = FW_PARAM_PFVF(ISCSI_START); - params[1] = FW_PARAM_PFVF(ISCSI_END); - ret = t4_query_params(adap, adap->fn, adap->fn, 0, 2, params, - val); - if (ret < 0) - goto bye; - adap->vres.iscsi.start = val[0]; - adap->vres.iscsi.size = val[1] - val[0] + 1; - } -#undef FW_PARAM_PFVF -#undef FW_PARAM_DEV - - adap->params.nports = hweight32(port_vec); - adap->params.portvec = port_vec; - adap->flags |= FW_OK; - - /* These are finalized by FW initialization, load their values now */ - v = t4_read_reg(adap, TP_TIMER_RESOLUTION); - adap->params.tp.tre = TIMERRESOLUTION_GET(v); - t4_read_mtu_tbl(adap, adap->params.mtus, NULL); - t4_load_mtus(adap, adap->params.mtus, adap->params.a_wnd, - adap->params.b_wnd); - -#ifdef CONFIG_PCI_IOV - /* - * Provision resource limits for Virtual Functions. We currently - * grant them all the same static resource limits except for the Port - * Access Rights Mask which we're assigning based on the PF. All of - * the static provisioning stuff for both the PF and VF really needs - * to be managed in a persistent manner for each device which the - * firmware controls. - */ - { - int pf, vf; - - for (pf = 0; pf < ARRAY_SIZE(num_vf); pf++) { - if (num_vf[pf] <= 0) - continue; - - /* VF numbering starts at 1! */ - for (vf = 1; vf <= num_vf[pf]; vf++) { - ret = t4_cfg_pfvf(adap, adap->fn, pf, vf, - VFRES_NEQ, VFRES_NETHCTRL, - VFRES_NIQFLINT, VFRES_NIQ, - VFRES_TC, VFRES_NVI, - FW_PFVF_CMD_CMASK_MASK, - pfvfres_pmask(adap, pf, vf), - VFRES_NEXACTF, - VFRES_R_CAPS, VFRES_WX_CAPS); - if (ret < 0) - dev_warn(adap->pdev_dev, "failed to " - "provision pf/vf=%d/%d; " - "err=%d\n", pf, vf, ret); - } - } - } -#endif - - setup_memwin(adap); - return 0; - - /* - * If a command timed out or failed with EIO FW does not operate within - * its spec or something catastrophic happened to HW/FW, stop issuing - * commands. - */ -bye: if (ret != -ETIMEDOUT && ret != -EIO) - t4_fw_bye(adap, adap->fn); - return ret; -} - -/* EEH callbacks */ - -static pci_ers_result_t eeh_err_detected(struct pci_dev *pdev, - pci_channel_state_t state) -{ - int i; - struct adapter *adap = pci_get_drvdata(pdev); - - if (!adap) - goto out; - - rtnl_lock(); - adap->flags &= ~FW_OK; - notify_ulds(adap, CXGB4_STATE_START_RECOVERY); - for_each_port(adap, i) { - struct net_device *dev = adap->port[i]; - - netif_device_detach(dev); - netif_carrier_off(dev); - } - if (adap->flags & FULL_INIT_DONE) - cxgb_down(adap); - rtnl_unlock(); - pci_disable_device(pdev); -out: return state == pci_channel_io_perm_failure ? - PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET; -} - -static pci_ers_result_t eeh_slot_reset(struct pci_dev *pdev) -{ - int i, ret; - struct fw_caps_config_cmd c; - struct adapter *adap = pci_get_drvdata(pdev); - - if (!adap) { - pci_restore_state(pdev); - pci_save_state(pdev); - return PCI_ERS_RESULT_RECOVERED; - } - - if (pci_enable_device(pdev)) { - dev_err(&pdev->dev, "cannot reenable PCI device after reset\n"); - return PCI_ERS_RESULT_DISCONNECT; - } - - pci_set_master(pdev); - pci_restore_state(pdev); - pci_save_state(pdev); - pci_cleanup_aer_uncorrect_error_status(pdev); - - if (t4_wait_dev_ready(adap) < 0) - return PCI_ERS_RESULT_DISCONNECT; - if (t4_fw_hello(adap, adap->fn, adap->fn, MASTER_MUST, NULL)) - return PCI_ERS_RESULT_DISCONNECT; - adap->flags |= FW_OK; - if (adap_init1(adap, &c)) - return PCI_ERS_RESULT_DISCONNECT; - - for_each_port(adap, i) { - struct port_info *p = adap2pinfo(adap, i); - - ret = t4_alloc_vi(adap, adap->fn, p->tx_chan, adap->fn, 0, 1, - NULL, NULL); - if (ret < 0) - return PCI_ERS_RESULT_DISCONNECT; - p->viid = ret; - p->xact_addr_filt = -1; - } - - t4_load_mtus(adap, adap->params.mtus, adap->params.a_wnd, - adap->params.b_wnd); - setup_memwin(adap); - if (cxgb_up(adap)) - return PCI_ERS_RESULT_DISCONNECT; - return PCI_ERS_RESULT_RECOVERED; -} - -static void eeh_resume(struct pci_dev *pdev) -{ - int i; - struct adapter *adap = pci_get_drvdata(pdev); - - if (!adap) - return; - - rtnl_lock(); - for_each_port(adap, i) { - struct net_device *dev = adap->port[i]; - - if (netif_running(dev)) { - link_start(dev); - cxgb_set_rxmode(dev); - } - netif_device_attach(dev); - } - rtnl_unlock(); -} - -static struct pci_error_handlers cxgb4_eeh = { - .error_detected = eeh_err_detected, - .slot_reset = eeh_slot_reset, - .resume = eeh_resume, -}; - -static inline bool is_10g_port(const struct link_config *lc) -{ - return (lc->supported & FW_PORT_CAP_SPEED_10G) != 0; -} - -static inline void init_rspq(struct sge_rspq *q, u8 timer_idx, u8 pkt_cnt_idx, - unsigned int size, unsigned int iqe_size) -{ - q->intr_params = QINTR_TIMER_IDX(timer_idx) | - (pkt_cnt_idx < SGE_NCOUNTERS ? QINTR_CNT_EN : 0); - q->pktcnt_idx = pkt_cnt_idx < SGE_NCOUNTERS ? pkt_cnt_idx : 0; - q->iqe_len = iqe_size; - q->size = size; -} - -/* - * Perform default configuration of DMA queues depending on the number and type - * of ports we found and the number of available CPUs. Most settings can be - * modified by the admin prior to actual use. - */ -static void __devinit cfg_queues(struct adapter *adap) -{ - struct sge *s = &adap->sge; - int i, q10g = 0, n10g = 0, qidx = 0; - - for_each_port(adap, i) - n10g += is_10g_port(&adap2pinfo(adap, i)->link_cfg); - - /* - * We default to 1 queue per non-10G port and up to # of cores queues - * per 10G port. - */ - if (n10g) - q10g = (MAX_ETH_QSETS - (adap->params.nports - n10g)) / n10g; - if (q10g > num_online_cpus()) - q10g = num_online_cpus(); - - for_each_port(adap, i) { - struct port_info *pi = adap2pinfo(adap, i); - - pi->first_qset = qidx; - pi->nqsets = is_10g_port(&pi->link_cfg) ? q10g : 1; - qidx += pi->nqsets; - } - - s->ethqsets = qidx; - s->max_ethqsets = qidx; /* MSI-X may lower it later */ - - if (is_offload(adap)) { - /* - * For offload we use 1 queue/channel if all ports are up to 1G, - * otherwise we divide all available queues amongst the channels - * capped by the number of available cores. - */ - if (n10g) { - i = min_t(int, ARRAY_SIZE(s->ofldrxq), - num_online_cpus()); - s->ofldqsets = roundup(i, adap->params.nports); - } else - s->ofldqsets = adap->params.nports; - /* For RDMA one Rx queue per channel suffices */ - s->rdmaqs = adap->params.nports; - } - - for (i = 0; i < ARRAY_SIZE(s->ethrxq); i++) { - struct sge_eth_rxq *r = &s->ethrxq[i]; - - init_rspq(&r->rspq, 0, 0, 1024, 64); - r->fl.size = 72; - } - - for (i = 0; i < ARRAY_SIZE(s->ethtxq); i++) - s->ethtxq[i].q.size = 1024; - - for (i = 0; i < ARRAY_SIZE(s->ctrlq); i++) - s->ctrlq[i].q.size = 512; - - for (i = 0; i < ARRAY_SIZE(s->ofldtxq); i++) - s->ofldtxq[i].q.size = 1024; - - for (i = 0; i < ARRAY_SIZE(s->ofldrxq); i++) { - struct sge_ofld_rxq *r = &s->ofldrxq[i]; - - init_rspq(&r->rspq, 0, 0, 1024, 64); - r->rspq.uld = CXGB4_ULD_ISCSI; - r->fl.size = 72; - } - - for (i = 0; i < ARRAY_SIZE(s->rdmarxq); i++) { - struct sge_ofld_rxq *r = &s->rdmarxq[i]; - - init_rspq(&r->rspq, 0, 0, 511, 64); - r->rspq.uld = CXGB4_ULD_RDMA; - r->fl.size = 72; - } - - init_rspq(&s->fw_evtq, 6, 0, 512, 64); - init_rspq(&s->intrq, 6, 0, 2 * MAX_INGQ, 64); -} - -/* - * Reduce the number of Ethernet queues across all ports to at most n. - * n provides at least one queue per port. - */ -static void __devinit reduce_ethqs(struct adapter *adap, int n) -{ - int i; - struct port_info *pi; - - while (n < adap->sge.ethqsets) - for_each_port(adap, i) { - pi = adap2pinfo(adap, i); - if (pi->nqsets > 1) { - pi->nqsets--; - adap->sge.ethqsets--; - if (adap->sge.ethqsets <= n) - break; - } - } - - n = 0; - for_each_port(adap, i) { - pi = adap2pinfo(adap, i); - pi->first_qset = n; - n += pi->nqsets; - } -} - -/* 2 MSI-X vectors needed for the FW queue and non-data interrupts */ -#define EXTRA_VECS 2 - -static int __devinit enable_msix(struct adapter *adap) -{ - int ofld_need = 0; - int i, err, want, need; - struct sge *s = &adap->sge; - unsigned int nchan = adap->params.nports; - struct msix_entry entries[MAX_INGQ + 1]; - - for (i = 0; i < ARRAY_SIZE(entries); ++i) - entries[i].entry = i; - - want = s->max_ethqsets + EXTRA_VECS; - if (is_offload(adap)) { - want += s->rdmaqs + s->ofldqsets; - /* need nchan for each possible ULD */ - ofld_need = 2 * nchan; - } - need = adap->params.nports + EXTRA_VECS + ofld_need; - - while ((err = pci_enable_msix(adap->pdev, entries, want)) >= need) - want = err; - - if (!err) { - /* - * Distribute available vectors to the various queue groups. - * Every group gets its minimum requirement and NIC gets top - * priority for leftovers. - */ - i = want - EXTRA_VECS - ofld_need; - if (i < s->max_ethqsets) { - s->max_ethqsets = i; - if (i < s->ethqsets) - reduce_ethqs(adap, i); - } - if (is_offload(adap)) { - i = want - EXTRA_VECS - s->max_ethqsets; - i -= ofld_need - nchan; - s->ofldqsets = (i / nchan) * nchan; /* round down */ - } - for (i = 0; i < want; ++i) - adap->msix_info[i].vec = entries[i].vector; - } else if (err > 0) - dev_info(adap->pdev_dev, - "only %d MSI-X vectors left, not using MSI-X\n", err); - return err; -} - -#undef EXTRA_VECS - -static int __devinit init_rss(struct adapter *adap) -{ - unsigned int i, j; - - for_each_port(adap, i) { - struct port_info *pi = adap2pinfo(adap, i); - - pi->rss = kcalloc(pi->rss_size, sizeof(u16), GFP_KERNEL); - if (!pi->rss) - return -ENOMEM; - for (j = 0; j < pi->rss_size; j++) - pi->rss[j] = j % pi->nqsets; - } - return 0; -} - -static void __devinit print_port_info(const struct net_device *dev) -{ - static const char *base[] = { - "R XFI", "R XAUI", "T SGMII", "T XFI", "T XAUI", "KX4", "CX4", - "KX", "KR", "R SFP+", "KR/KX", "KR/KX/KX4" - }; - - char buf[80]; - char *bufp = buf; - const char *spd = ""; - const struct port_info *pi = netdev_priv(dev); - const struct adapter *adap = pi->adapter; - - if (adap->params.pci.speed == PCI_EXP_LNKSTA_CLS_2_5GB) - spd = " 2.5 GT/s"; - else if (adap->params.pci.speed == PCI_EXP_LNKSTA_CLS_5_0GB) - spd = " 5 GT/s"; - - if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_100M) - bufp += sprintf(bufp, "100/"); - if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_1G) - bufp += sprintf(bufp, "1000/"); - if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_10G) - bufp += sprintf(bufp, "10G/"); - if (bufp != buf) - --bufp; - sprintf(bufp, "BASE-%s", base[pi->port_type]); - - netdev_info(dev, "Chelsio %s rev %d %s %sNIC PCIe x%d%s%s\n", - adap->params.vpd.id, adap->params.rev, buf, - is_offload(adap) ? "R" : "", adap->params.pci.width, spd, - (adap->flags & USING_MSIX) ? " MSI-X" : - (adap->flags & USING_MSI) ? " MSI" : ""); - netdev_info(dev, "S/N: %s, E/C: %s\n", - adap->params.vpd.sn, adap->params.vpd.ec); -} - -static void __devinit enable_pcie_relaxed_ordering(struct pci_dev *dev) -{ - u16 v; - int pos; - - pos = pci_pcie_cap(dev); - if (pos > 0) { - pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &v); - v |= PCI_EXP_DEVCTL_RELAX_EN; - pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, v); - } -} - -/* - * Free the following resources: - * - memory used for tables - * - MSI/MSI-X - * - net devices - * - resources FW is holding for us - */ -static void free_some_resources(struct adapter *adapter) -{ - unsigned int i; - - t4_free_mem(adapter->l2t); - t4_free_mem(adapter->tids.tid_tab); - disable_msi(adapter); - - for_each_port(adapter, i) - if (adapter->port[i]) { - kfree(adap2pinfo(adapter, i)->rss); - free_netdev(adapter->port[i]); - } - if (adapter->flags & FW_OK) - t4_fw_bye(adapter, adapter->fn); -} - -#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN) -#define VLAN_FEAT (NETIF_F_SG | NETIF_F_IP_CSUM | TSO_FLAGS | \ - NETIF_F_IPV6_CSUM | NETIF_F_HIGHDMA) - -static int __devinit init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int func, i, err; - struct port_info *pi; - unsigned int highdma = 0; - struct adapter *adapter = NULL; - - printk_once(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION); - - err = pci_request_regions(pdev, KBUILD_MODNAME); - if (err) { - /* Just info, some other driver may have claimed the device. */ - dev_info(&pdev->dev, "cannot obtain PCI resources\n"); - return err; - } - - /* We control everything through one PF */ - func = PCI_FUNC(pdev->devfn); - if (func != ent->driver_data) { - pci_save_state(pdev); /* to restore SR-IOV later */ - goto sriov; - } - - err = pci_enable_device(pdev); - if (err) { - dev_err(&pdev->dev, "cannot enable PCI device\n"); - goto out_release_regions; - } - - if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { - highdma = NETIF_F_HIGHDMA; - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); - if (err) { - dev_err(&pdev->dev, "unable to obtain 64-bit DMA for " - "coherent allocations\n"); - goto out_disable_device; - } - } else { - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (err) { - dev_err(&pdev->dev, "no usable DMA configuration\n"); - goto out_disable_device; - } - } - - pci_enable_pcie_error_reporting(pdev); - enable_pcie_relaxed_ordering(pdev); - pci_set_master(pdev); - pci_save_state(pdev); - - adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); - if (!adapter) { - err = -ENOMEM; - goto out_disable_device; - } - - adapter->regs = pci_ioremap_bar(pdev, 0); - if (!adapter->regs) { - dev_err(&pdev->dev, "cannot map device registers\n"); - err = -ENOMEM; - goto out_free_adapter; - } - - adapter->pdev = pdev; - adapter->pdev_dev = &pdev->dev; - adapter->fn = func; - adapter->msg_enable = dflt_msg_enable; - memset(adapter->chan_map, 0xff, sizeof(adapter->chan_map)); - - spin_lock_init(&adapter->stats_lock); - spin_lock_init(&adapter->tid_release_lock); - - INIT_WORK(&adapter->tid_release_task, process_tid_release_list); - - err = t4_prep_adapter(adapter); - if (err) - goto out_unmap_bar; - err = adap_init0(adapter); - if (err) - goto out_unmap_bar; - - for_each_port(adapter, i) { - struct net_device *netdev; - - netdev = alloc_etherdev_mq(sizeof(struct port_info), - MAX_ETH_QSETS); - if (!netdev) { - err = -ENOMEM; - goto out_free_dev; - } - - SET_NETDEV_DEV(netdev, &pdev->dev); - - adapter->port[i] = netdev; - pi = netdev_priv(netdev); - pi->adapter = adapter; - pi->xact_addr_filt = -1; - pi->port_id = i; - netdev->irq = pdev->irq; - - netdev->hw_features = NETIF_F_SG | TSO_FLAGS | - NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_RXCSUM | NETIF_F_RXHASH | - NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - netdev->features |= netdev->hw_features | highdma; - netdev->vlan_features = netdev->features & VLAN_FEAT; - - netdev->netdev_ops = &cxgb4_netdev_ops; - SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops); - } - - pci_set_drvdata(pdev, adapter); - - if (adapter->flags & FW_OK) { - err = t4_port_init(adapter, func, func, 0); - if (err) - goto out_free_dev; - } - - /* - * Configure queues and allocate tables now, they can be needed as - * soon as the first register_netdev completes. - */ - cfg_queues(adapter); - - adapter->l2t = t4_init_l2t(); - if (!adapter->l2t) { - /* We tolerate a lack of L2T, giving up some functionality */ - dev_warn(&pdev->dev, "could not allocate L2T, continuing\n"); - adapter->params.offload = 0; - } - - if (is_offload(adapter) && tid_init(&adapter->tids) < 0) { - dev_warn(&pdev->dev, "could not allocate TID table, " - "continuing\n"); - adapter->params.offload = 0; - } - - /* See what interrupts we'll be using */ - if (msi > 1 && enable_msix(adapter) == 0) - adapter->flags |= USING_MSIX; - else if (msi > 0 && pci_enable_msi(pdev) == 0) - adapter->flags |= USING_MSI; - - err = init_rss(adapter); - if (err) - goto out_free_dev; - - /* - * The card is now ready to go. If any errors occur during device - * registration we do not fail the whole card but rather proceed only - * with the ports we manage to register successfully. However we must - * register at least one net device. - */ - for_each_port(adapter, i) { - pi = adap2pinfo(adapter, i); - netif_set_real_num_tx_queues(adapter->port[i], pi->nqsets); - netif_set_real_num_rx_queues(adapter->port[i], pi->nqsets); - - err = register_netdev(adapter->port[i]); - if (err) - break; - adapter->chan_map[pi->tx_chan] = i; - print_port_info(adapter->port[i]); - } - if (i == 0) { - dev_err(&pdev->dev, "could not register any net devices\n"); - goto out_free_dev; - } - if (err) { - dev_warn(&pdev->dev, "only %d net devices registered\n", i); - err = 0; - } - - if (cxgb4_debugfs_root) { - adapter->debugfs_root = debugfs_create_dir(pci_name(pdev), - cxgb4_debugfs_root); - setup_debugfs(adapter); - } - - if (is_offload(adapter)) - attach_ulds(adapter); - -sriov: -#ifdef CONFIG_PCI_IOV - if (func < ARRAY_SIZE(num_vf) && num_vf[func] > 0) - if (pci_enable_sriov(pdev, num_vf[func]) == 0) - dev_info(&pdev->dev, - "instantiated %u virtual functions\n", - num_vf[func]); -#endif - return 0; - - out_free_dev: - free_some_resources(adapter); - out_unmap_bar: - iounmap(adapter->regs); - out_free_adapter: - kfree(adapter); - out_disable_device: - pci_disable_pcie_error_reporting(pdev); - pci_disable_device(pdev); - out_release_regions: - pci_release_regions(pdev); - pci_set_drvdata(pdev, NULL); - return err; -} - -static void __devexit remove_one(struct pci_dev *pdev) -{ - struct adapter *adapter = pci_get_drvdata(pdev); - - pci_disable_sriov(pdev); - - if (adapter) { - int i; - - if (is_offload(adapter)) - detach_ulds(adapter); - - for_each_port(adapter, i) - if (adapter->port[i]->reg_state == NETREG_REGISTERED) - unregister_netdev(adapter->port[i]); - - if (adapter->debugfs_root) - debugfs_remove_recursive(adapter->debugfs_root); - - if (adapter->flags & FULL_INIT_DONE) - cxgb_down(adapter); - - free_some_resources(adapter); - iounmap(adapter->regs); - kfree(adapter); - pci_disable_pcie_error_reporting(pdev); - pci_disable_device(pdev); - pci_release_regions(pdev); - pci_set_drvdata(pdev, NULL); - } else - pci_release_regions(pdev); -} - -static struct pci_driver cxgb4_driver = { - .name = KBUILD_MODNAME, - .id_table = cxgb4_pci_tbl, - .probe = init_one, - .remove = __devexit_p(remove_one), - .err_handler = &cxgb4_eeh, -}; - -static int __init cxgb4_init_module(void) -{ - int ret; - - /* Debugfs support is optional, just warn if this fails */ - cxgb4_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (!cxgb4_debugfs_root) - pr_warning("could not create debugfs entry, continuing\n"); - - ret = pci_register_driver(&cxgb4_driver); - if (ret < 0) - debugfs_remove(cxgb4_debugfs_root); - return ret; -} - -static void __exit cxgb4_cleanup_module(void) -{ - pci_unregister_driver(&cxgb4_driver); - debugfs_remove(cxgb4_debugfs_root); /* NULL ok */ -} - -module_init(cxgb4_init_module); -module_exit(cxgb4_cleanup_module); diff --git a/drivers/net/cxgb4/cxgb4_uld.h b/drivers/net/cxgb4/cxgb4_uld.h deleted file mode 100644 index b1d39b8d141a..000000000000 --- a/drivers/net/cxgb4/cxgb4_uld.h +++ /dev/null @@ -1,239 +0,0 @@ -/* - * This file is part of the Chelsio T4 Ethernet driver for Linux. - * - * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef __CXGB4_OFLD_H -#define __CXGB4_OFLD_H - -#include -#include -#include -#include - -/* CPL message priority levels */ -enum { - CPL_PRIORITY_DATA = 0, /* data messages */ - CPL_PRIORITY_SETUP = 1, /* connection setup messages */ - CPL_PRIORITY_TEARDOWN = 0, /* connection teardown messages */ - CPL_PRIORITY_LISTEN = 1, /* listen start/stop messages */ - CPL_PRIORITY_ACK = 1, /* RX ACK messages */ - CPL_PRIORITY_CONTROL = 1 /* control messages */ -}; - -#define INIT_TP_WR(w, tid) do { \ - (w)->wr.wr_hi = htonl(FW_WR_OP(FW_TP_WR) | \ - FW_WR_IMMDLEN(sizeof(*w) - sizeof(w->wr))); \ - (w)->wr.wr_mid = htonl(FW_WR_LEN16(DIV_ROUND_UP(sizeof(*w), 16)) | \ - FW_WR_FLOWID(tid)); \ - (w)->wr.wr_lo = cpu_to_be64(0); \ -} while (0) - -#define INIT_TP_WR_CPL(w, cpl, tid) do { \ - INIT_TP_WR(w, tid); \ - OPCODE_TID(w) = htonl(MK_OPCODE_TID(cpl, tid)); \ -} while (0) - -#define INIT_ULPTX_WR(w, wrlen, atomic, tid) do { \ - (w)->wr.wr_hi = htonl(FW_WR_OP(FW_ULPTX_WR) | FW_WR_ATOMIC(atomic)); \ - (w)->wr.wr_mid = htonl(FW_WR_LEN16(DIV_ROUND_UP(wrlen, 16)) | \ - FW_WR_FLOWID(tid)); \ - (w)->wr.wr_lo = cpu_to_be64(0); \ -} while (0) - -/* Special asynchronous notification message */ -#define CXGB4_MSG_AN ((void *)1) - -struct serv_entry { - void *data; -}; - -union aopen_entry { - void *data; - union aopen_entry *next; -}; - -/* - * Holds the size, base address, free list start, etc of the TID, server TID, - * and active-open TID tables. The tables themselves are allocated dynamically. - */ -struct tid_info { - void **tid_tab; - unsigned int ntids; - - struct serv_entry *stid_tab; - unsigned long *stid_bmap; - unsigned int nstids; - unsigned int stid_base; - - union aopen_entry *atid_tab; - unsigned int natids; - - unsigned int nftids; - unsigned int ftid_base; - - spinlock_t atid_lock ____cacheline_aligned_in_smp; - union aopen_entry *afree; - unsigned int atids_in_use; - - spinlock_t stid_lock; - unsigned int stids_in_use; - - atomic_t tids_in_use; -}; - -static inline void *lookup_tid(const struct tid_info *t, unsigned int tid) -{ - return tid < t->ntids ? t->tid_tab[tid] : NULL; -} - -static inline void *lookup_atid(const struct tid_info *t, unsigned int atid) -{ - return atid < t->natids ? t->atid_tab[atid].data : NULL; -} - -static inline void *lookup_stid(const struct tid_info *t, unsigned int stid) -{ - stid -= t->stid_base; - return stid < t->nstids ? t->stid_tab[stid].data : NULL; -} - -static inline void cxgb4_insert_tid(struct tid_info *t, void *data, - unsigned int tid) -{ - t->tid_tab[tid] = data; - atomic_inc(&t->tids_in_use); -} - -int cxgb4_alloc_atid(struct tid_info *t, void *data); -int cxgb4_alloc_stid(struct tid_info *t, int family, void *data); -void cxgb4_free_atid(struct tid_info *t, unsigned int atid); -void cxgb4_free_stid(struct tid_info *t, unsigned int stid, int family); -void cxgb4_remove_tid(struct tid_info *t, unsigned int qid, unsigned int tid); - -struct in6_addr; - -int cxgb4_create_server(const struct net_device *dev, unsigned int stid, - __be32 sip, __be16 sport, unsigned int queue); - -static inline void set_wr_txq(struct sk_buff *skb, int prio, int queue) -{ - skb_set_queue_mapping(skb, (queue << 1) | prio); -} - -enum cxgb4_uld { - CXGB4_ULD_RDMA, - CXGB4_ULD_ISCSI, - CXGB4_ULD_MAX -}; - -enum cxgb4_state { - CXGB4_STATE_UP, - CXGB4_STATE_START_RECOVERY, - CXGB4_STATE_DOWN, - CXGB4_STATE_DETACH -}; - -struct pci_dev; -struct l2t_data; -struct net_device; -struct pkt_gl; -struct tp_tcp_stats; - -struct cxgb4_range { - unsigned int start; - unsigned int size; -}; - -struct cxgb4_virt_res { /* virtualized HW resources */ - struct cxgb4_range ddp; - struct cxgb4_range iscsi; - struct cxgb4_range stag; - struct cxgb4_range rq; - struct cxgb4_range pbl; - struct cxgb4_range qp; - struct cxgb4_range cq; - struct cxgb4_range ocq; -}; - -#define OCQ_WIN_OFFSET(pdev, vres) \ - (pci_resource_len((pdev), 2) - roundup_pow_of_two((vres)->ocq.size)) - -/* - * Block of information the LLD provides to ULDs attaching to a device. - */ -struct cxgb4_lld_info { - struct pci_dev *pdev; /* associated PCI device */ - struct l2t_data *l2t; /* L2 table */ - struct tid_info *tids; /* TID table */ - struct net_device **ports; /* device ports */ - const struct cxgb4_virt_res *vr; /* assorted HW resources */ - const unsigned short *mtus; /* MTU table */ - const unsigned short *rxq_ids; /* the ULD's Rx queue ids */ - unsigned short nrxq; /* # of Rx queues */ - unsigned short ntxq; /* # of Tx queues */ - unsigned char nchan:4; /* # of channels */ - unsigned char nports:4; /* # of ports */ - unsigned char wr_cred; /* WR 16-byte credits */ - unsigned char adapter_type; /* type of adapter */ - unsigned char fw_api_ver; /* FW API version */ - unsigned int fw_vers; /* FW version */ - unsigned int iscsi_iolen; /* iSCSI max I/O length */ - unsigned short udb_density; /* # of user DB/page */ - unsigned short ucq_density; /* # of user CQs/page */ - void __iomem *gts_reg; /* address of GTS register */ - void __iomem *db_reg; /* address of kernel doorbell */ -}; - -struct cxgb4_uld_info { - const char *name; - void *(*add)(const struct cxgb4_lld_info *p); - int (*rx_handler)(void *handle, const __be64 *rsp, - const struct pkt_gl *gl); - int (*state_change)(void *handle, enum cxgb4_state new_state); -}; - -int cxgb4_register_uld(enum cxgb4_uld type, const struct cxgb4_uld_info *p); -int cxgb4_unregister_uld(enum cxgb4_uld type); -int cxgb4_ofld_send(struct net_device *dev, struct sk_buff *skb); -unsigned int cxgb4_port_chan(const struct net_device *dev); -unsigned int cxgb4_port_viid(const struct net_device *dev); -unsigned int cxgb4_port_idx(const struct net_device *dev); -unsigned int cxgb4_best_mtu(const unsigned short *mtus, unsigned short mtu, - unsigned int *idx); -void cxgb4_get_tcp_stats(struct pci_dev *pdev, struct tp_tcp_stats *v4, - struct tp_tcp_stats *v6); -void cxgb4_iscsi_init(struct net_device *dev, unsigned int tag_mask, - const unsigned int *pgsz_order); -struct sk_buff *cxgb4_pktgl_to_skb(const struct pkt_gl *gl, - unsigned int skb_len, unsigned int pull_len); -#endif /* !__CXGB4_OFLD_H */ diff --git a/drivers/net/cxgb4/l2t.c b/drivers/net/cxgb4/l2t.c deleted file mode 100644 index a2d323c473f8..000000000000 --- a/drivers/net/cxgb4/l2t.c +++ /dev/null @@ -1,597 +0,0 @@ -/* - * This file is part of the Chelsio T4 Ethernet driver for Linux. - * - * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include "cxgb4.h" -#include "l2t.h" -#include "t4_msg.h" -#include "t4fw_api.h" - -#define VLAN_NONE 0xfff - -/* identifies sync vs async L2T_WRITE_REQs */ -#define F_SYNC_WR (1 << 12) - -enum { - L2T_STATE_VALID, /* entry is up to date */ - L2T_STATE_STALE, /* entry may be used but needs revalidation */ - L2T_STATE_RESOLVING, /* entry needs address resolution */ - L2T_STATE_SYNC_WRITE, /* synchronous write of entry underway */ - - /* when state is one of the below the entry is not hashed */ - L2T_STATE_SWITCHING, /* entry is being used by a switching filter */ - L2T_STATE_UNUSED /* entry not in use */ -}; - -struct l2t_data { - rwlock_t lock; - atomic_t nfree; /* number of free entries */ - struct l2t_entry *rover; /* starting point for next allocation */ - struct l2t_entry l2tab[L2T_SIZE]; -}; - -static inline unsigned int vlan_prio(const struct l2t_entry *e) -{ - return e->vlan >> 13; -} - -static inline void l2t_hold(struct l2t_data *d, struct l2t_entry *e) -{ - if (atomic_add_return(1, &e->refcnt) == 1) /* 0 -> 1 transition */ - atomic_dec(&d->nfree); -} - -/* - * To avoid having to check address families we do not allow v4 and v6 - * neighbors to be on the same hash chain. We keep v4 entries in the first - * half of available hash buckets and v6 in the second. - */ -enum { - L2T_SZ_HALF = L2T_SIZE / 2, - L2T_HASH_MASK = L2T_SZ_HALF - 1 -}; - -static inline unsigned int arp_hash(const u32 *key, int ifindex) -{ - return jhash_2words(*key, ifindex, 0) & L2T_HASH_MASK; -} - -static inline unsigned int ipv6_hash(const u32 *key, int ifindex) -{ - u32 xor = key[0] ^ key[1] ^ key[2] ^ key[3]; - - return L2T_SZ_HALF + (jhash_2words(xor, ifindex, 0) & L2T_HASH_MASK); -} - -static unsigned int addr_hash(const u32 *addr, int addr_len, int ifindex) -{ - return addr_len == 4 ? arp_hash(addr, ifindex) : - ipv6_hash(addr, ifindex); -} - -/* - * Checks if an L2T entry is for the given IP/IPv6 address. It does not check - * whether the L2T entry and the address are of the same address family. - * Callers ensure an address is only checked against L2T entries of the same - * family, something made trivial by the separation of IP and IPv6 hash chains - * mentioned above. Returns 0 if there's a match, - */ -static int addreq(const struct l2t_entry *e, const u32 *addr) -{ - if (e->v6) - return (e->addr[0] ^ addr[0]) | (e->addr[1] ^ addr[1]) | - (e->addr[2] ^ addr[2]) | (e->addr[3] ^ addr[3]); - return e->addr[0] ^ addr[0]; -} - -static void neigh_replace(struct l2t_entry *e, struct neighbour *n) -{ - neigh_hold(n); - if (e->neigh) - neigh_release(e->neigh); - e->neigh = n; -} - -/* - * Write an L2T entry. Must be called with the entry locked. - * The write may be synchronous or asynchronous. - */ -static int write_l2e(struct adapter *adap, struct l2t_entry *e, int sync) -{ - struct sk_buff *skb; - struct cpl_l2t_write_req *req; - - skb = alloc_skb(sizeof(*req), GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req)); - INIT_TP_WR(req, 0); - - OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, - e->idx | (sync ? F_SYNC_WR : 0) | - TID_QID(adap->sge.fw_evtq.abs_id))); - req->params = htons(L2T_W_PORT(e->lport) | L2T_W_NOREPLY(!sync)); - req->l2t_idx = htons(e->idx); - req->vlan = htons(e->vlan); - if (e->neigh) - memcpy(e->dmac, e->neigh->ha, sizeof(e->dmac)); - memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac)); - - set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0); - t4_ofld_send(adap, skb); - - if (sync && e->state != L2T_STATE_SWITCHING) - e->state = L2T_STATE_SYNC_WRITE; - return 0; -} - -/* - * Send packets waiting in an L2T entry's ARP queue. Must be called with the - * entry locked. - */ -static void send_pending(struct adapter *adap, struct l2t_entry *e) -{ - while (e->arpq_head) { - struct sk_buff *skb = e->arpq_head; - - e->arpq_head = skb->next; - skb->next = NULL; - t4_ofld_send(adap, skb); - } - e->arpq_tail = NULL; -} - -/* - * Process a CPL_L2T_WRITE_RPL. Wake up the ARP queue if it completes a - * synchronous L2T_WRITE. Note that the TID in the reply is really the L2T - * index it refers to. - */ -void do_l2t_write_rpl(struct adapter *adap, const struct cpl_l2t_write_rpl *rpl) -{ - unsigned int tid = GET_TID(rpl); - unsigned int idx = tid & (L2T_SIZE - 1); - - if (unlikely(rpl->status != CPL_ERR_NONE)) { - dev_err(adap->pdev_dev, - "Unexpected L2T_WRITE_RPL status %u for entry %u\n", - rpl->status, idx); - return; - } - - if (tid & F_SYNC_WR) { - struct l2t_entry *e = &adap->l2t->l2tab[idx]; - - spin_lock(&e->lock); - if (e->state != L2T_STATE_SWITCHING) { - send_pending(adap, e); - e->state = (e->neigh->nud_state & NUD_STALE) ? - L2T_STATE_STALE : L2T_STATE_VALID; - } - spin_unlock(&e->lock); - } -} - -/* - * Add a packet to an L2T entry's queue of packets awaiting resolution. - * Must be called with the entry's lock held. - */ -static inline void arpq_enqueue(struct l2t_entry *e, struct sk_buff *skb) -{ - skb->next = NULL; - if (e->arpq_head) - e->arpq_tail->next = skb; - else - e->arpq_head = skb; - e->arpq_tail = skb; -} - -int cxgb4_l2t_send(struct net_device *dev, struct sk_buff *skb, - struct l2t_entry *e) -{ - struct adapter *adap = netdev2adap(dev); - -again: - switch (e->state) { - case L2T_STATE_STALE: /* entry is stale, kick off revalidation */ - neigh_event_send(e->neigh, NULL); - spin_lock_bh(&e->lock); - if (e->state == L2T_STATE_STALE) - e->state = L2T_STATE_VALID; - spin_unlock_bh(&e->lock); - case L2T_STATE_VALID: /* fast-path, send the packet on */ - return t4_ofld_send(adap, skb); - case L2T_STATE_RESOLVING: - case L2T_STATE_SYNC_WRITE: - spin_lock_bh(&e->lock); - if (e->state != L2T_STATE_SYNC_WRITE && - e->state != L2T_STATE_RESOLVING) { - spin_unlock_bh(&e->lock); - goto again; - } - arpq_enqueue(e, skb); - spin_unlock_bh(&e->lock); - - if (e->state == L2T_STATE_RESOLVING && - !neigh_event_send(e->neigh, NULL)) { - spin_lock_bh(&e->lock); - if (e->state == L2T_STATE_RESOLVING && e->arpq_head) - write_l2e(adap, e, 1); - spin_unlock_bh(&e->lock); - } - } - return 0; -} -EXPORT_SYMBOL(cxgb4_l2t_send); - -/* - * Allocate a free L2T entry. Must be called with l2t_data.lock held. - */ -static struct l2t_entry *alloc_l2e(struct l2t_data *d) -{ - struct l2t_entry *end, *e, **p; - - if (!atomic_read(&d->nfree)) - return NULL; - - /* there's definitely a free entry */ - for (e = d->rover, end = &d->l2tab[L2T_SIZE]; e != end; ++e) - if (atomic_read(&e->refcnt) == 0) - goto found; - - for (e = d->l2tab; atomic_read(&e->refcnt); ++e) - ; -found: - d->rover = e + 1; - atomic_dec(&d->nfree); - - /* - * The entry we found may be an inactive entry that is - * presently in the hash table. We need to remove it. - */ - if (e->state < L2T_STATE_SWITCHING) - for (p = &d->l2tab[e->hash].first; *p; p = &(*p)->next) - if (*p == e) { - *p = e->next; - e->next = NULL; - break; - } - - e->state = L2T_STATE_UNUSED; - return e; -} - -/* - * Called when an L2T entry has no more users. - */ -static void t4_l2e_free(struct l2t_entry *e) -{ - struct l2t_data *d; - - spin_lock_bh(&e->lock); - if (atomic_read(&e->refcnt) == 0) { /* hasn't been recycled */ - if (e->neigh) { - neigh_release(e->neigh); - e->neigh = NULL; - } - while (e->arpq_head) { - struct sk_buff *skb = e->arpq_head; - - e->arpq_head = skb->next; - kfree_skb(skb); - } - e->arpq_tail = NULL; - } - spin_unlock_bh(&e->lock); - - d = container_of(e, struct l2t_data, l2tab[e->idx]); - atomic_inc(&d->nfree); -} - -void cxgb4_l2t_release(struct l2t_entry *e) -{ - if (atomic_dec_and_test(&e->refcnt)) - t4_l2e_free(e); -} -EXPORT_SYMBOL(cxgb4_l2t_release); - -/* - * Update an L2T entry that was previously used for the same next hop as neigh. - * Must be called with softirqs disabled. - */ -static void reuse_entry(struct l2t_entry *e, struct neighbour *neigh) -{ - unsigned int nud_state; - - spin_lock(&e->lock); /* avoid race with t4_l2t_free */ - if (neigh != e->neigh) - neigh_replace(e, neigh); - nud_state = neigh->nud_state; - if (memcmp(e->dmac, neigh->ha, sizeof(e->dmac)) || - !(nud_state & NUD_VALID)) - e->state = L2T_STATE_RESOLVING; - else if (nud_state & NUD_CONNECTED) - e->state = L2T_STATE_VALID; - else - e->state = L2T_STATE_STALE; - spin_unlock(&e->lock); -} - -struct l2t_entry *cxgb4_l2t_get(struct l2t_data *d, struct neighbour *neigh, - const struct net_device *physdev, - unsigned int priority) -{ - u8 lport; - u16 vlan; - struct l2t_entry *e; - int addr_len = neigh->tbl->key_len; - u32 *addr = (u32 *)neigh->primary_key; - int ifidx = neigh->dev->ifindex; - int hash = addr_hash(addr, addr_len, ifidx); - - if (neigh->dev->flags & IFF_LOOPBACK) - lport = netdev2pinfo(physdev)->tx_chan + 4; - else - lport = netdev2pinfo(physdev)->lport; - - if (neigh->dev->priv_flags & IFF_802_1Q_VLAN) - vlan = vlan_dev_vlan_id(neigh->dev); - else - vlan = VLAN_NONE; - - write_lock_bh(&d->lock); - for (e = d->l2tab[hash].first; e; e = e->next) - if (!addreq(e, addr) && e->ifindex == ifidx && - e->vlan == vlan && e->lport == lport) { - l2t_hold(d, e); - if (atomic_read(&e->refcnt) == 1) - reuse_entry(e, neigh); - goto done; - } - - /* Need to allocate a new entry */ - e = alloc_l2e(d); - if (e) { - spin_lock(&e->lock); /* avoid race with t4_l2t_free */ - e->state = L2T_STATE_RESOLVING; - memcpy(e->addr, addr, addr_len); - e->ifindex = ifidx; - e->hash = hash; - e->lport = lport; - e->v6 = addr_len == 16; - atomic_set(&e->refcnt, 1); - neigh_replace(e, neigh); - e->vlan = vlan; - e->next = d->l2tab[hash].first; - d->l2tab[hash].first = e; - spin_unlock(&e->lock); - } -done: - write_unlock_bh(&d->lock); - return e; -} -EXPORT_SYMBOL(cxgb4_l2t_get); - -/* - * Called when address resolution fails for an L2T entry to handle packets - * on the arpq head. If a packet specifies a failure handler it is invoked, - * otherwise the packet is sent to the device. - */ -static void handle_failed_resolution(struct adapter *adap, struct sk_buff *arpq) -{ - while (arpq) { - struct sk_buff *skb = arpq; - const struct l2t_skb_cb *cb = L2T_SKB_CB(skb); - - arpq = skb->next; - skb->next = NULL; - if (cb->arp_err_handler) - cb->arp_err_handler(cb->handle, skb); - else - t4_ofld_send(adap, skb); - } -} - -/* - * Called when the host's neighbor layer makes a change to some entry that is - * loaded into the HW L2 table. - */ -void t4_l2t_update(struct adapter *adap, struct neighbour *neigh) -{ - struct l2t_entry *e; - struct sk_buff *arpq = NULL; - struct l2t_data *d = adap->l2t; - int addr_len = neigh->tbl->key_len; - u32 *addr = (u32 *) neigh->primary_key; - int ifidx = neigh->dev->ifindex; - int hash = addr_hash(addr, addr_len, ifidx); - - read_lock_bh(&d->lock); - for (e = d->l2tab[hash].first; e; e = e->next) - if (!addreq(e, addr) && e->ifindex == ifidx) { - spin_lock(&e->lock); - if (atomic_read(&e->refcnt)) - goto found; - spin_unlock(&e->lock); - break; - } - read_unlock_bh(&d->lock); - return; - - found: - read_unlock(&d->lock); - - if (neigh != e->neigh) - neigh_replace(e, neigh); - - if (e->state == L2T_STATE_RESOLVING) { - if (neigh->nud_state & NUD_FAILED) { - arpq = e->arpq_head; - e->arpq_head = e->arpq_tail = NULL; - } else if ((neigh->nud_state & (NUD_CONNECTED | NUD_STALE)) && - e->arpq_head) { - write_l2e(adap, e, 1); - } - } else { - e->state = neigh->nud_state & NUD_CONNECTED ? - L2T_STATE_VALID : L2T_STATE_STALE; - if (memcmp(e->dmac, neigh->ha, sizeof(e->dmac))) - write_l2e(adap, e, 0); - } - - spin_unlock_bh(&e->lock); - - if (arpq) - handle_failed_resolution(adap, arpq); -} - -struct l2t_data *t4_init_l2t(void) -{ - int i; - struct l2t_data *d; - - d = t4_alloc_mem(sizeof(*d)); - if (!d) - return NULL; - - d->rover = d->l2tab; - atomic_set(&d->nfree, L2T_SIZE); - rwlock_init(&d->lock); - - for (i = 0; i < L2T_SIZE; ++i) { - d->l2tab[i].idx = i; - d->l2tab[i].state = L2T_STATE_UNUSED; - spin_lock_init(&d->l2tab[i].lock); - atomic_set(&d->l2tab[i].refcnt, 0); - } - return d; -} - -#include -#include -#include - -static inline void *l2t_get_idx(struct seq_file *seq, loff_t pos) -{ - struct l2t_entry *l2tab = seq->private; - - return pos >= L2T_SIZE ? NULL : &l2tab[pos]; -} - -static void *l2t_seq_start(struct seq_file *seq, loff_t *pos) -{ - return *pos ? l2t_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; -} - -static void *l2t_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - v = l2t_get_idx(seq, *pos); - if (v) - ++*pos; - return v; -} - -static void l2t_seq_stop(struct seq_file *seq, void *v) -{ -} - -static char l2e_state(const struct l2t_entry *e) -{ - switch (e->state) { - case L2T_STATE_VALID: return 'V'; - case L2T_STATE_STALE: return 'S'; - case L2T_STATE_SYNC_WRITE: return 'W'; - case L2T_STATE_RESOLVING: return e->arpq_head ? 'A' : 'R'; - case L2T_STATE_SWITCHING: return 'X'; - default: - return 'U'; - } -} - -static int l2t_seq_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) - seq_puts(seq, " Idx IP address " - "Ethernet address VLAN/P LP State Users Port\n"); - else { - char ip[60]; - struct l2t_entry *e = v; - - spin_lock_bh(&e->lock); - if (e->state == L2T_STATE_SWITCHING) - ip[0] = '\0'; - else - sprintf(ip, e->v6 ? "%pI6c" : "%pI4", e->addr); - seq_printf(seq, "%4u %-25s %17pM %4d %u %2u %c %5u %s\n", - e->idx, ip, e->dmac, - e->vlan & VLAN_VID_MASK, vlan_prio(e), e->lport, - l2e_state(e), atomic_read(&e->refcnt), - e->neigh ? e->neigh->dev->name : ""); - spin_unlock_bh(&e->lock); - } - return 0; -} - -static const struct seq_operations l2t_seq_ops = { - .start = l2t_seq_start, - .next = l2t_seq_next, - .stop = l2t_seq_stop, - .show = l2t_seq_show -}; - -static int l2t_seq_open(struct inode *inode, struct file *file) -{ - int rc = seq_open(file, &l2t_seq_ops); - - if (!rc) { - struct adapter *adap = inode->i_private; - struct seq_file *seq = file->private_data; - - seq->private = adap->l2t->l2tab; - } - return rc; -} - -const struct file_operations t4_l2t_fops = { - .owner = THIS_MODULE, - .open = l2t_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; diff --git a/drivers/net/cxgb4/l2t.h b/drivers/net/cxgb4/l2t.h deleted file mode 100644 index 02b31d0c6410..000000000000 --- a/drivers/net/cxgb4/l2t.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * This file is part of the Chelsio T4 Ethernet driver for Linux. - * - * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef __CXGB4_L2T_H -#define __CXGB4_L2T_H - -#include -#include -#include - -struct adapter; -struct l2t_data; -struct neighbour; -struct net_device; -struct file_operations; -struct cpl_l2t_write_rpl; - -/* - * Each L2T entry plays multiple roles. First of all, it keeps state for the - * corresponding entry of the HW L2 table and maintains a queue of offload - * packets awaiting address resolution. Second, it is a node of a hash table - * chain, where the nodes of the chain are linked together through their next - * pointer. Finally, each node is a bucket of a hash table, pointing to the - * first element in its chain through its first pointer. - */ -struct l2t_entry { - u16 state; /* entry state */ - u16 idx; /* entry index */ - u32 addr[4]; /* next hop IP or IPv6 address */ - int ifindex; /* neighbor's net_device's ifindex */ - struct neighbour *neigh; /* associated neighbour */ - struct l2t_entry *first; /* start of hash chain */ - struct l2t_entry *next; /* next l2t_entry on chain */ - struct sk_buff *arpq_head; /* queue of packets awaiting resolution */ - struct sk_buff *arpq_tail; - spinlock_t lock; - atomic_t refcnt; /* entry reference count */ - u16 hash; /* hash bucket the entry is on */ - u16 vlan; /* VLAN TCI (id: bits 0-11, prio: 13-15 */ - u8 v6; /* whether entry is for IPv6 */ - u8 lport; /* associated offload logical interface */ - u8 dmac[ETH_ALEN]; /* neighbour's MAC address */ -}; - -typedef void (*arp_err_handler_t)(void *handle, struct sk_buff *skb); - -/* - * Callback stored in an skb to handle address resolution failure. - */ -struct l2t_skb_cb { - void *handle; - arp_err_handler_t arp_err_handler; -}; - -#define L2T_SKB_CB(skb) ((struct l2t_skb_cb *)(skb)->cb) - -static inline void t4_set_arp_err_handler(struct sk_buff *skb, void *handle, - arp_err_handler_t handler) -{ - L2T_SKB_CB(skb)->handle = handle; - L2T_SKB_CB(skb)->arp_err_handler = handler; -} - -void cxgb4_l2t_release(struct l2t_entry *e); -int cxgb4_l2t_send(struct net_device *dev, struct sk_buff *skb, - struct l2t_entry *e); -struct l2t_entry *cxgb4_l2t_get(struct l2t_data *d, struct neighbour *neigh, - const struct net_device *physdev, - unsigned int priority); - -void t4_l2t_update(struct adapter *adap, struct neighbour *neigh); -struct l2t_data *t4_init_l2t(void); -void do_l2t_write_rpl(struct adapter *p, const struct cpl_l2t_write_rpl *rpl); - -extern const struct file_operations t4_l2t_fops; -#endif /* __CXGB4_L2T_H */ diff --git a/drivers/net/cxgb4/sge.c b/drivers/net/cxgb4/sge.c deleted file mode 100644 index 56adf448b9fe..000000000000 --- a/drivers/net/cxgb4/sge.c +++ /dev/null @@ -1,2442 +0,0 @@ -/* - * This file is part of the Chelsio T4 Ethernet driver for Linux. - * - * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "cxgb4.h" -#include "t4_regs.h" -#include "t4_msg.h" -#include "t4fw_api.h" - -/* - * Rx buffer size. We use largish buffers if possible but settle for single - * pages under memory shortage. - */ -#if PAGE_SHIFT >= 16 -# define FL_PG_ORDER 0 -#else -# define FL_PG_ORDER (16 - PAGE_SHIFT) -#endif - -/* RX_PULL_LEN should be <= RX_COPY_THRES */ -#define RX_COPY_THRES 256 -#define RX_PULL_LEN 128 - -/* - * Main body length for sk_buffs used for Rx Ethernet packets with fragments. - * Should be >= RX_PULL_LEN but possibly bigger to give pskb_may_pull some room. - */ -#define RX_PKT_SKB_LEN 512 - -/* Ethernet header padding prepended to RX_PKTs */ -#define RX_PKT_PAD 2 - -/* - * Max number of Tx descriptors we clean up at a time. Should be modest as - * freeing skbs isn't cheap and it happens while holding locks. We just need - * to free packets faster than they arrive, we eventually catch up and keep - * the amortized cost reasonable. Must be >= 2 * TXQ_STOP_THRES. - */ -#define MAX_TX_RECLAIM 16 - -/* - * Max number of Rx buffers we replenish at a time. Again keep this modest, - * allocating buffers isn't cheap either. - */ -#define MAX_RX_REFILL 16U - -/* - * Period of the Rx queue check timer. This timer is infrequent as it has - * something to do only when the system experiences severe memory shortage. - */ -#define RX_QCHECK_PERIOD (HZ / 2) - -/* - * Period of the Tx queue check timer. - */ -#define TX_QCHECK_PERIOD (HZ / 2) - -/* - * Max number of Tx descriptors to be reclaimed by the Tx timer. - */ -#define MAX_TIMER_TX_RECLAIM 100 - -/* - * Timer index used when backing off due to memory shortage. - */ -#define NOMEM_TMR_IDX (SGE_NTIMERS - 1) - -/* - * An FL with <= FL_STARVE_THRES buffers is starving and a periodic timer will - * attempt to refill it. - */ -#define FL_STARVE_THRES 4 - -/* - * Suspend an Ethernet Tx queue with fewer available descriptors than this. - * This is the same as calc_tx_descs() for a TSO packet with - * nr_frags == MAX_SKB_FRAGS. - */ -#define ETHTXQ_STOP_THRES \ - (1 + DIV_ROUND_UP((3 * MAX_SKB_FRAGS) / 2 + (MAX_SKB_FRAGS & 1), 8)) - -/* - * Suspension threshold for non-Ethernet Tx queues. We require enough room - * for a full sized WR. - */ -#define TXQ_STOP_THRES (SGE_MAX_WR_LEN / sizeof(struct tx_desc)) - -/* - * Max Tx descriptor space we allow for an Ethernet packet to be inlined - * into a WR. - */ -#define MAX_IMM_TX_PKT_LEN 128 - -/* - * Max size of a WR sent through a control Tx queue. - */ -#define MAX_CTRL_WR_LEN SGE_MAX_WR_LEN - -enum { - /* packet alignment in FL buffers */ - FL_ALIGN = L1_CACHE_BYTES < 32 ? 32 : L1_CACHE_BYTES, - /* egress status entry size */ - STAT_LEN = L1_CACHE_BYTES > 64 ? 128 : 64 -}; - -struct tx_sw_desc { /* SW state per Tx descriptor */ - struct sk_buff *skb; - struct ulptx_sgl *sgl; -}; - -struct rx_sw_desc { /* SW state per Rx descriptor */ - struct page *page; - dma_addr_t dma_addr; -}; - -/* - * The low bits of rx_sw_desc.dma_addr have special meaning. - */ -enum { - RX_LARGE_BUF = 1 << 0, /* buffer is larger than PAGE_SIZE */ - RX_UNMAPPED_BUF = 1 << 1, /* buffer is not mapped */ -}; - -static inline dma_addr_t get_buf_addr(const struct rx_sw_desc *d) -{ - return d->dma_addr & ~(dma_addr_t)(RX_LARGE_BUF | RX_UNMAPPED_BUF); -} - -static inline bool is_buf_mapped(const struct rx_sw_desc *d) -{ - return !(d->dma_addr & RX_UNMAPPED_BUF); -} - -/** - * txq_avail - return the number of available slots in a Tx queue - * @q: the Tx queue - * - * Returns the number of descriptors in a Tx queue available to write new - * packets. - */ -static inline unsigned int txq_avail(const struct sge_txq *q) -{ - return q->size - 1 - q->in_use; -} - -/** - * fl_cap - return the capacity of a free-buffer list - * @fl: the FL - * - * Returns the capacity of a free-buffer list. The capacity is less than - * the size because one descriptor needs to be left unpopulated, otherwise - * HW will think the FL is empty. - */ -static inline unsigned int fl_cap(const struct sge_fl *fl) -{ - return fl->size - 8; /* 1 descriptor = 8 buffers */ -} - -static inline bool fl_starving(const struct sge_fl *fl) -{ - return fl->avail - fl->pend_cred <= FL_STARVE_THRES; -} - -static int map_skb(struct device *dev, const struct sk_buff *skb, - dma_addr_t *addr) -{ - const skb_frag_t *fp, *end; - const struct skb_shared_info *si; - - *addr = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); - if (dma_mapping_error(dev, *addr)) - goto out_err; - - si = skb_shinfo(skb); - end = &si->frags[si->nr_frags]; - - for (fp = si->frags; fp < end; fp++) { - *++addr = dma_map_page(dev, fp->page, fp->page_offset, fp->size, - DMA_TO_DEVICE); - if (dma_mapping_error(dev, *addr)) - goto unwind; - } - return 0; - -unwind: - while (fp-- > si->frags) - dma_unmap_page(dev, *--addr, fp->size, DMA_TO_DEVICE); - - dma_unmap_single(dev, addr[-1], skb_headlen(skb), DMA_TO_DEVICE); -out_err: - return -ENOMEM; -} - -#ifdef CONFIG_NEED_DMA_MAP_STATE -static void unmap_skb(struct device *dev, const struct sk_buff *skb, - const dma_addr_t *addr) -{ - const skb_frag_t *fp, *end; - const struct skb_shared_info *si; - - dma_unmap_single(dev, *addr++, skb_headlen(skb), DMA_TO_DEVICE); - - si = skb_shinfo(skb); - end = &si->frags[si->nr_frags]; - for (fp = si->frags; fp < end; fp++) - dma_unmap_page(dev, *addr++, fp->size, DMA_TO_DEVICE); -} - -/** - * deferred_unmap_destructor - unmap a packet when it is freed - * @skb: the packet - * - * This is the packet destructor used for Tx packets that need to remain - * mapped until they are freed rather than until their Tx descriptors are - * freed. - */ -static void deferred_unmap_destructor(struct sk_buff *skb) -{ - unmap_skb(skb->dev->dev.parent, skb, (dma_addr_t *)skb->head); -} -#endif - -static void unmap_sgl(struct device *dev, const struct sk_buff *skb, - const struct ulptx_sgl *sgl, const struct sge_txq *q) -{ - const struct ulptx_sge_pair *p; - unsigned int nfrags = skb_shinfo(skb)->nr_frags; - - if (likely(skb_headlen(skb))) - dma_unmap_single(dev, be64_to_cpu(sgl->addr0), ntohl(sgl->len0), - DMA_TO_DEVICE); - else { - dma_unmap_page(dev, be64_to_cpu(sgl->addr0), ntohl(sgl->len0), - DMA_TO_DEVICE); - nfrags--; - } - - /* - * the complexity below is because of the possibility of a wrap-around - * in the middle of an SGL - */ - for (p = sgl->sge; nfrags >= 2; nfrags -= 2) { - if (likely((u8 *)(p + 1) <= (u8 *)q->stat)) { -unmap: dma_unmap_page(dev, be64_to_cpu(p->addr[0]), - ntohl(p->len[0]), DMA_TO_DEVICE); - dma_unmap_page(dev, be64_to_cpu(p->addr[1]), - ntohl(p->len[1]), DMA_TO_DEVICE); - p++; - } else if ((u8 *)p == (u8 *)q->stat) { - p = (const struct ulptx_sge_pair *)q->desc; - goto unmap; - } else if ((u8 *)p + 8 == (u8 *)q->stat) { - const __be64 *addr = (const __be64 *)q->desc; - - dma_unmap_page(dev, be64_to_cpu(addr[0]), - ntohl(p->len[0]), DMA_TO_DEVICE); - dma_unmap_page(dev, be64_to_cpu(addr[1]), - ntohl(p->len[1]), DMA_TO_DEVICE); - p = (const struct ulptx_sge_pair *)&addr[2]; - } else { - const __be64 *addr = (const __be64 *)q->desc; - - dma_unmap_page(dev, be64_to_cpu(p->addr[0]), - ntohl(p->len[0]), DMA_TO_DEVICE); - dma_unmap_page(dev, be64_to_cpu(addr[0]), - ntohl(p->len[1]), DMA_TO_DEVICE); - p = (const struct ulptx_sge_pair *)&addr[1]; - } - } - if (nfrags) { - __be64 addr; - - if ((u8 *)p == (u8 *)q->stat) - p = (const struct ulptx_sge_pair *)q->desc; - addr = (u8 *)p + 16 <= (u8 *)q->stat ? p->addr[0] : - *(const __be64 *)q->desc; - dma_unmap_page(dev, be64_to_cpu(addr), ntohl(p->len[0]), - DMA_TO_DEVICE); - } -} - -/** - * free_tx_desc - reclaims Tx descriptors and their buffers - * @adapter: the adapter - * @q: the Tx queue to reclaim descriptors from - * @n: the number of descriptors to reclaim - * @unmap: whether the buffers should be unmapped for DMA - * - * Reclaims Tx descriptors from an SGE Tx queue and frees the associated - * Tx buffers. Called with the Tx queue lock held. - */ -static void free_tx_desc(struct adapter *adap, struct sge_txq *q, - unsigned int n, bool unmap) -{ - struct tx_sw_desc *d; - unsigned int cidx = q->cidx; - struct device *dev = adap->pdev_dev; - - d = &q->sdesc[cidx]; - while (n--) { - if (d->skb) { /* an SGL is present */ - if (unmap) - unmap_sgl(dev, d->skb, d->sgl, q); - kfree_skb(d->skb); - d->skb = NULL; - } - ++d; - if (++cidx == q->size) { - cidx = 0; - d = q->sdesc; - } - } - q->cidx = cidx; -} - -/* - * Return the number of reclaimable descriptors in a Tx queue. - */ -static inline int reclaimable(const struct sge_txq *q) -{ - int hw_cidx = ntohs(q->stat->cidx); - hw_cidx -= q->cidx; - return hw_cidx < 0 ? hw_cidx + q->size : hw_cidx; -} - -/** - * reclaim_completed_tx - reclaims completed Tx descriptors - * @adap: the adapter - * @q: the Tx queue to reclaim completed descriptors from - * @unmap: whether the buffers should be unmapped for DMA - * - * Reclaims Tx descriptors that the SGE has indicated it has processed, - * and frees the associated buffers if possible. Called with the Tx - * queue locked. - */ -static inline void reclaim_completed_tx(struct adapter *adap, struct sge_txq *q, - bool unmap) -{ - int avail = reclaimable(q); - - if (avail) { - /* - * Limit the amount of clean up work we do at a time to keep - * the Tx lock hold time O(1). - */ - if (avail > MAX_TX_RECLAIM) - avail = MAX_TX_RECLAIM; - - free_tx_desc(adap, q, avail, unmap); - q->in_use -= avail; - } -} - -static inline int get_buf_size(const struct rx_sw_desc *d) -{ -#if FL_PG_ORDER > 0 - return (d->dma_addr & RX_LARGE_BUF) ? (PAGE_SIZE << FL_PG_ORDER) : - PAGE_SIZE; -#else - return PAGE_SIZE; -#endif -} - -/** - * free_rx_bufs - free the Rx buffers on an SGE free list - * @adap: the adapter - * @q: the SGE free list to free buffers from - * @n: how many buffers to free - * - * Release the next @n buffers on an SGE free-buffer Rx queue. The - * buffers must be made inaccessible to HW before calling this function. - */ -static void free_rx_bufs(struct adapter *adap, struct sge_fl *q, int n) -{ - while (n--) { - struct rx_sw_desc *d = &q->sdesc[q->cidx]; - - if (is_buf_mapped(d)) - dma_unmap_page(adap->pdev_dev, get_buf_addr(d), - get_buf_size(d), PCI_DMA_FROMDEVICE); - put_page(d->page); - d->page = NULL; - if (++q->cidx == q->size) - q->cidx = 0; - q->avail--; - } -} - -/** - * unmap_rx_buf - unmap the current Rx buffer on an SGE free list - * @adap: the adapter - * @q: the SGE free list - * - * Unmap the current buffer on an SGE free-buffer Rx queue. The - * buffer must be made inaccessible to HW before calling this function. - * - * This is similar to @free_rx_bufs above but does not free the buffer. - * Do note that the FL still loses any further access to the buffer. - */ -static void unmap_rx_buf(struct adapter *adap, struct sge_fl *q) -{ - struct rx_sw_desc *d = &q->sdesc[q->cidx]; - - if (is_buf_mapped(d)) - dma_unmap_page(adap->pdev_dev, get_buf_addr(d), - get_buf_size(d), PCI_DMA_FROMDEVICE); - d->page = NULL; - if (++q->cidx == q->size) - q->cidx = 0; - q->avail--; -} - -static inline void ring_fl_db(struct adapter *adap, struct sge_fl *q) -{ - if (q->pend_cred >= 8) { - wmb(); - t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL), DBPRIO | - QID(q->cntxt_id) | PIDX(q->pend_cred / 8)); - q->pend_cred &= 7; - } -} - -static inline void set_rx_sw_desc(struct rx_sw_desc *sd, struct page *pg, - dma_addr_t mapping) -{ - sd->page = pg; - sd->dma_addr = mapping; /* includes size low bits */ -} - -/** - * refill_fl - refill an SGE Rx buffer ring - * @adap: the adapter - * @q: the ring to refill - * @n: the number of new buffers to allocate - * @gfp: the gfp flags for the allocations - * - * (Re)populate an SGE free-buffer queue with up to @n new packet buffers, - * allocated with the supplied gfp flags. The caller must assure that - * @n does not exceed the queue's capacity. If afterwards the queue is - * found critically low mark it as starving in the bitmap of starving FLs. - * - * Returns the number of buffers allocated. - */ -static unsigned int refill_fl(struct adapter *adap, struct sge_fl *q, int n, - gfp_t gfp) -{ - struct page *pg; - dma_addr_t mapping; - unsigned int cred = q->avail; - __be64 *d = &q->desc[q->pidx]; - struct rx_sw_desc *sd = &q->sdesc[q->pidx]; - - gfp |= __GFP_NOWARN; /* failures are expected */ - -#if FL_PG_ORDER > 0 - /* - * Prefer large buffers - */ - while (n) { - pg = alloc_pages(gfp | __GFP_COMP, FL_PG_ORDER); - if (unlikely(!pg)) { - q->large_alloc_failed++; - break; /* fall back to single pages */ - } - - mapping = dma_map_page(adap->pdev_dev, pg, 0, - PAGE_SIZE << FL_PG_ORDER, - PCI_DMA_FROMDEVICE); - if (unlikely(dma_mapping_error(adap->pdev_dev, mapping))) { - __free_pages(pg, FL_PG_ORDER); - goto out; /* do not try small pages for this error */ - } - mapping |= RX_LARGE_BUF; - *d++ = cpu_to_be64(mapping); - - set_rx_sw_desc(sd, pg, mapping); - sd++; - - q->avail++; - if (++q->pidx == q->size) { - q->pidx = 0; - sd = q->sdesc; - d = q->desc; - } - n--; - } -#endif - - while (n--) { - pg = __netdev_alloc_page(adap->port[0], gfp); - if (unlikely(!pg)) { - q->alloc_failed++; - break; - } - - mapping = dma_map_page(adap->pdev_dev, pg, 0, PAGE_SIZE, - PCI_DMA_FROMDEVICE); - if (unlikely(dma_mapping_error(adap->pdev_dev, mapping))) { - netdev_free_page(adap->port[0], pg); - goto out; - } - *d++ = cpu_to_be64(mapping); - - set_rx_sw_desc(sd, pg, mapping); - sd++; - - q->avail++; - if (++q->pidx == q->size) { - q->pidx = 0; - sd = q->sdesc; - d = q->desc; - } - } - -out: cred = q->avail - cred; - q->pend_cred += cred; - ring_fl_db(adap, q); - - if (unlikely(fl_starving(q))) { - smp_wmb(); - set_bit(q->cntxt_id - adap->sge.egr_start, - adap->sge.starving_fl); - } - - return cred; -} - -static inline void __refill_fl(struct adapter *adap, struct sge_fl *fl) -{ - refill_fl(adap, fl, min(MAX_RX_REFILL, fl_cap(fl) - fl->avail), - GFP_ATOMIC); -} - -/** - * alloc_ring - allocate resources for an SGE descriptor ring - * @dev: the PCI device's core device - * @nelem: the number of descriptors - * @elem_size: the size of each descriptor - * @sw_size: the size of the SW state associated with each ring element - * @phys: the physical address of the allocated ring - * @metadata: address of the array holding the SW state for the ring - * @stat_size: extra space in HW ring for status information - * @node: preferred node for memory allocations - * - * Allocates resources for an SGE descriptor ring, such as Tx queues, - * free buffer lists, or response queues. Each SGE ring requires - * space for its HW descriptors plus, optionally, space for the SW state - * associated with each HW entry (the metadata). The function returns - * three values: the virtual address for the HW ring (the return value - * of the function), the bus address of the HW ring, and the address - * of the SW ring. - */ -static void *alloc_ring(struct device *dev, size_t nelem, size_t elem_size, - size_t sw_size, dma_addr_t *phys, void *metadata, - size_t stat_size, int node) -{ - size_t len = nelem * elem_size + stat_size; - void *s = NULL; - void *p = dma_alloc_coherent(dev, len, phys, GFP_KERNEL); - - if (!p) - return NULL; - if (sw_size) { - s = kzalloc_node(nelem * sw_size, GFP_KERNEL, node); - - if (!s) { - dma_free_coherent(dev, len, p, *phys); - return NULL; - } - } - if (metadata) - *(void **)metadata = s; - memset(p, 0, len); - return p; -} - -/** - * sgl_len - calculates the size of an SGL of the given capacity - * @n: the number of SGL entries - * - * Calculates the number of flits needed for a scatter/gather list that - * can hold the given number of entries. - */ -static inline unsigned int sgl_len(unsigned int n) -{ - n--; - return (3 * n) / 2 + (n & 1) + 2; -} - -/** - * flits_to_desc - returns the num of Tx descriptors for the given flits - * @n: the number of flits - * - * Returns the number of Tx descriptors needed for the supplied number - * of flits. - */ -static inline unsigned int flits_to_desc(unsigned int n) -{ - BUG_ON(n > SGE_MAX_WR_LEN / 8); - return DIV_ROUND_UP(n, 8); -} - -/** - * is_eth_imm - can an Ethernet packet be sent as immediate data? - * @skb: the packet - * - * Returns whether an Ethernet packet is small enough to fit as - * immediate data. - */ -static inline int is_eth_imm(const struct sk_buff *skb) -{ - return skb->len <= MAX_IMM_TX_PKT_LEN - sizeof(struct cpl_tx_pkt); -} - -/** - * calc_tx_flits - calculate the number of flits for a packet Tx WR - * @skb: the packet - * - * Returns the number of flits needed for a Tx WR for the given Ethernet - * packet, including the needed WR and CPL headers. - */ -static inline unsigned int calc_tx_flits(const struct sk_buff *skb) -{ - unsigned int flits; - - if (is_eth_imm(skb)) - return DIV_ROUND_UP(skb->len + sizeof(struct cpl_tx_pkt), 8); - - flits = sgl_len(skb_shinfo(skb)->nr_frags + 1) + 4; - if (skb_shinfo(skb)->gso_size) - flits += 2; - return flits; -} - -/** - * calc_tx_descs - calculate the number of Tx descriptors for a packet - * @skb: the packet - * - * Returns the number of Tx descriptors needed for the given Ethernet - * packet, including the needed WR and CPL headers. - */ -static inline unsigned int calc_tx_descs(const struct sk_buff *skb) -{ - return flits_to_desc(calc_tx_flits(skb)); -} - -/** - * write_sgl - populate a scatter/gather list for a packet - * @skb: the packet - * @q: the Tx queue we are writing into - * @sgl: starting location for writing the SGL - * @end: points right after the end of the SGL - * @start: start offset into skb main-body data to include in the SGL - * @addr: the list of bus addresses for the SGL elements - * - * Generates a gather list for the buffers that make up a packet. - * The caller must provide adequate space for the SGL that will be written. - * The SGL includes all of the packet's page fragments and the data in its - * main body except for the first @start bytes. @sgl must be 16-byte - * aligned and within a Tx descriptor with available space. @end points - * right after the end of the SGL but does not account for any potential - * wrap around, i.e., @end > @sgl. - */ -static void write_sgl(const struct sk_buff *skb, struct sge_txq *q, - struct ulptx_sgl *sgl, u64 *end, unsigned int start, - const dma_addr_t *addr) -{ - unsigned int i, len; - struct ulptx_sge_pair *to; - const struct skb_shared_info *si = skb_shinfo(skb); - unsigned int nfrags = si->nr_frags; - struct ulptx_sge_pair buf[MAX_SKB_FRAGS / 2 + 1]; - - len = skb_headlen(skb) - start; - if (likely(len)) { - sgl->len0 = htonl(len); - sgl->addr0 = cpu_to_be64(addr[0] + start); - nfrags++; - } else { - sgl->len0 = htonl(si->frags[0].size); - sgl->addr0 = cpu_to_be64(addr[1]); - } - - sgl->cmd_nsge = htonl(ULPTX_CMD(ULP_TX_SC_DSGL) | ULPTX_NSGE(nfrags)); - if (likely(--nfrags == 0)) - return; - /* - * Most of the complexity below deals with the possibility we hit the - * end of the queue in the middle of writing the SGL. For this case - * only we create the SGL in a temporary buffer and then copy it. - */ - to = (u8 *)end > (u8 *)q->stat ? buf : sgl->sge; - - for (i = (nfrags != si->nr_frags); nfrags >= 2; nfrags -= 2, to++) { - to->len[0] = cpu_to_be32(si->frags[i].size); - to->len[1] = cpu_to_be32(si->frags[++i].size); - to->addr[0] = cpu_to_be64(addr[i]); - to->addr[1] = cpu_to_be64(addr[++i]); - } - if (nfrags) { - to->len[0] = cpu_to_be32(si->frags[i].size); - to->len[1] = cpu_to_be32(0); - to->addr[0] = cpu_to_be64(addr[i + 1]); - } - if (unlikely((u8 *)end > (u8 *)q->stat)) { - unsigned int part0 = (u8 *)q->stat - (u8 *)sgl->sge, part1; - - if (likely(part0)) - memcpy(sgl->sge, buf, part0); - part1 = (u8 *)end - (u8 *)q->stat; - memcpy(q->desc, (u8 *)buf + part0, part1); - end = (void *)q->desc + part1; - } - if ((uintptr_t)end & 8) /* 0-pad to multiple of 16 */ - *(u64 *)end = 0; -} - -/** - * ring_tx_db - check and potentially ring a Tx queue's doorbell - * @adap: the adapter - * @q: the Tx queue - * @n: number of new descriptors to give to HW - * - * Ring the doorbel for a Tx queue. - */ -static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n) -{ - wmb(); /* write descriptors before telling HW */ - t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL), - QID(q->cntxt_id) | PIDX(n)); -} - -/** - * inline_tx_skb - inline a packet's data into Tx descriptors - * @skb: the packet - * @q: the Tx queue where the packet will be inlined - * @pos: starting position in the Tx queue where to inline the packet - * - * Inline a packet's contents directly into Tx descriptors, starting at - * the given position within the Tx DMA ring. - * Most of the complexity of this operation is dealing with wrap arounds - * in the middle of the packet we want to inline. - */ -static void inline_tx_skb(const struct sk_buff *skb, const struct sge_txq *q, - void *pos) -{ - u64 *p; - int left = (void *)q->stat - pos; - - if (likely(skb->len <= left)) { - if (likely(!skb->data_len)) - skb_copy_from_linear_data(skb, pos, skb->len); - else - skb_copy_bits(skb, 0, pos, skb->len); - pos += skb->len; - } else { - skb_copy_bits(skb, 0, pos, left); - skb_copy_bits(skb, left, q->desc, skb->len - left); - pos = (void *)q->desc + (skb->len - left); - } - - /* 0-pad to multiple of 16 */ - p = PTR_ALIGN(pos, 8); - if ((uintptr_t)p & 8) - *p = 0; -} - -/* - * Figure out what HW csum a packet wants and return the appropriate control - * bits. - */ -static u64 hwcsum(const struct sk_buff *skb) -{ - int csum_type; - const struct iphdr *iph = ip_hdr(skb); - - if (iph->version == 4) { - if (iph->protocol == IPPROTO_TCP) - csum_type = TX_CSUM_TCPIP; - else if (iph->protocol == IPPROTO_UDP) - csum_type = TX_CSUM_UDPIP; - else { -nocsum: /* - * unknown protocol, disable HW csum - * and hope a bad packet is detected - */ - return TXPKT_L4CSUM_DIS; - } - } else { - /* - * this doesn't work with extension headers - */ - const struct ipv6hdr *ip6h = (const struct ipv6hdr *)iph; - - if (ip6h->nexthdr == IPPROTO_TCP) - csum_type = TX_CSUM_TCPIP6; - else if (ip6h->nexthdr == IPPROTO_UDP) - csum_type = TX_CSUM_UDPIP6; - else - goto nocsum; - } - - if (likely(csum_type >= TX_CSUM_TCPIP)) - return TXPKT_CSUM_TYPE(csum_type) | - TXPKT_IPHDR_LEN(skb_network_header_len(skb)) | - TXPKT_ETHHDR_LEN(skb_network_offset(skb) - ETH_HLEN); - else { - int start = skb_transport_offset(skb); - - return TXPKT_CSUM_TYPE(csum_type) | TXPKT_CSUM_START(start) | - TXPKT_CSUM_LOC(start + skb->csum_offset); - } -} - -static void eth_txq_stop(struct sge_eth_txq *q) -{ - netif_tx_stop_queue(q->txq); - q->q.stops++; -} - -static inline void txq_advance(struct sge_txq *q, unsigned int n) -{ - q->in_use += n; - q->pidx += n; - if (q->pidx >= q->size) - q->pidx -= q->size; -} - -/** - * t4_eth_xmit - add a packet to an Ethernet Tx queue - * @skb: the packet - * @dev: the egress net device - * - * Add a packet to an SGE Ethernet Tx queue. Runs with softirqs disabled. - */ -netdev_tx_t t4_eth_xmit(struct sk_buff *skb, struct net_device *dev) -{ - u32 wr_mid; - u64 cntrl, *end; - int qidx, credits; - unsigned int flits, ndesc; - struct adapter *adap; - struct sge_eth_txq *q; - const struct port_info *pi; - struct fw_eth_tx_pkt_wr *wr; - struct cpl_tx_pkt_core *cpl; - const struct skb_shared_info *ssi; - dma_addr_t addr[MAX_SKB_FRAGS + 1]; - - /* - * The chip min packet length is 10 octets but play safe and reject - * anything shorter than an Ethernet header. - */ - if (unlikely(skb->len < ETH_HLEN)) { -out_free: dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - pi = netdev_priv(dev); - adap = pi->adapter; - qidx = skb_get_queue_mapping(skb); - q = &adap->sge.ethtxq[qidx + pi->first_qset]; - - reclaim_completed_tx(adap, &q->q, true); - - flits = calc_tx_flits(skb); - ndesc = flits_to_desc(flits); - credits = txq_avail(&q->q) - ndesc; - - if (unlikely(credits < 0)) { - eth_txq_stop(q); - dev_err(adap->pdev_dev, - "%s: Tx ring %u full while queue awake!\n", - dev->name, qidx); - return NETDEV_TX_BUSY; - } - - if (!is_eth_imm(skb) && - unlikely(map_skb(adap->pdev_dev, skb, addr) < 0)) { - q->mapping_err++; - goto out_free; - } - - wr_mid = FW_WR_LEN16(DIV_ROUND_UP(flits, 2)); - if (unlikely(credits < ETHTXQ_STOP_THRES)) { - eth_txq_stop(q); - wr_mid |= FW_WR_EQUEQ | FW_WR_EQUIQ; - } - - wr = (void *)&q->q.desc[q->q.pidx]; - wr->equiq_to_len16 = htonl(wr_mid); - wr->r3 = cpu_to_be64(0); - end = (u64 *)wr + flits; - - ssi = skb_shinfo(skb); - if (ssi->gso_size) { - struct cpl_tx_pkt_lso *lso = (void *)wr; - bool v6 = (ssi->gso_type & SKB_GSO_TCPV6) != 0; - int l3hdr_len = skb_network_header_len(skb); - int eth_xtra_len = skb_network_offset(skb) - ETH_HLEN; - - wr->op_immdlen = htonl(FW_WR_OP(FW_ETH_TX_PKT_WR) | - FW_WR_IMMDLEN(sizeof(*lso))); - lso->c.lso_ctrl = htonl(LSO_OPCODE(CPL_TX_PKT_LSO) | - LSO_FIRST_SLICE | LSO_LAST_SLICE | - LSO_IPV6(v6) | - LSO_ETHHDR_LEN(eth_xtra_len / 4) | - LSO_IPHDR_LEN(l3hdr_len / 4) | - LSO_TCPHDR_LEN(tcp_hdr(skb)->doff)); - lso->c.ipid_ofst = htons(0); - lso->c.mss = htons(ssi->gso_size); - lso->c.seqno_offset = htonl(0); - lso->c.len = htonl(skb->len); - cpl = (void *)(lso + 1); - cntrl = TXPKT_CSUM_TYPE(v6 ? TX_CSUM_TCPIP6 : TX_CSUM_TCPIP) | - TXPKT_IPHDR_LEN(l3hdr_len) | - TXPKT_ETHHDR_LEN(eth_xtra_len); - q->tso++; - q->tx_cso += ssi->gso_segs; - } else { - int len; - - len = is_eth_imm(skb) ? skb->len + sizeof(*cpl) : sizeof(*cpl); - wr->op_immdlen = htonl(FW_WR_OP(FW_ETH_TX_PKT_WR) | - FW_WR_IMMDLEN(len)); - cpl = (void *)(wr + 1); - if (skb->ip_summed == CHECKSUM_PARTIAL) { - cntrl = hwcsum(skb) | TXPKT_IPCSUM_DIS; - q->tx_cso++; - } else - cntrl = TXPKT_L4CSUM_DIS | TXPKT_IPCSUM_DIS; - } - - if (vlan_tx_tag_present(skb)) { - q->vlan_ins++; - cntrl |= TXPKT_VLAN_VLD | TXPKT_VLAN(vlan_tx_tag_get(skb)); - } - - cpl->ctrl0 = htonl(TXPKT_OPCODE(CPL_TX_PKT_XT) | - TXPKT_INTF(pi->tx_chan) | TXPKT_PF(adap->fn)); - cpl->pack = htons(0); - cpl->len = htons(skb->len); - cpl->ctrl1 = cpu_to_be64(cntrl); - - if (is_eth_imm(skb)) { - inline_tx_skb(skb, &q->q, cpl + 1); - dev_kfree_skb(skb); - } else { - int last_desc; - - write_sgl(skb, &q->q, (struct ulptx_sgl *)(cpl + 1), end, 0, - addr); - skb_orphan(skb); - - last_desc = q->q.pidx + ndesc - 1; - if (last_desc >= q->q.size) - last_desc -= q->q.size; - q->q.sdesc[last_desc].skb = skb; - q->q.sdesc[last_desc].sgl = (struct ulptx_sgl *)(cpl + 1); - } - - txq_advance(&q->q, ndesc); - - ring_tx_db(adap, &q->q, ndesc); - return NETDEV_TX_OK; -} - -/** - * reclaim_completed_tx_imm - reclaim completed control-queue Tx descs - * @q: the SGE control Tx queue - * - * This is a variant of reclaim_completed_tx() that is used for Tx queues - * that send only immediate data (presently just the control queues) and - * thus do not have any sk_buffs to release. - */ -static inline void reclaim_completed_tx_imm(struct sge_txq *q) -{ - int hw_cidx = ntohs(q->stat->cidx); - int reclaim = hw_cidx - q->cidx; - - if (reclaim < 0) - reclaim += q->size; - - q->in_use -= reclaim; - q->cidx = hw_cidx; -} - -/** - * is_imm - check whether a packet can be sent as immediate data - * @skb: the packet - * - * Returns true if a packet can be sent as a WR with immediate data. - */ -static inline int is_imm(const struct sk_buff *skb) -{ - return skb->len <= MAX_CTRL_WR_LEN; -} - -/** - * ctrlq_check_stop - check if a control queue is full and should stop - * @q: the queue - * @wr: most recent WR written to the queue - * - * Check if a control queue has become full and should be stopped. - * We clean up control queue descriptors very lazily, only when we are out. - * If the queue is still full after reclaiming any completed descriptors - * we suspend it and have the last WR wake it up. - */ -static void ctrlq_check_stop(struct sge_ctrl_txq *q, struct fw_wr_hdr *wr) -{ - reclaim_completed_tx_imm(&q->q); - if (unlikely(txq_avail(&q->q) < TXQ_STOP_THRES)) { - wr->lo |= htonl(FW_WR_EQUEQ | FW_WR_EQUIQ); - q->q.stops++; - q->full = 1; - } -} - -/** - * ctrl_xmit - send a packet through an SGE control Tx queue - * @q: the control queue - * @skb: the packet - * - * Send a packet through an SGE control Tx queue. Packets sent through - * a control queue must fit entirely as immediate data. - */ -static int ctrl_xmit(struct sge_ctrl_txq *q, struct sk_buff *skb) -{ - unsigned int ndesc; - struct fw_wr_hdr *wr; - - if (unlikely(!is_imm(skb))) { - WARN_ON(1); - dev_kfree_skb(skb); - return NET_XMIT_DROP; - } - - ndesc = DIV_ROUND_UP(skb->len, sizeof(struct tx_desc)); - spin_lock(&q->sendq.lock); - - if (unlikely(q->full)) { - skb->priority = ndesc; /* save for restart */ - __skb_queue_tail(&q->sendq, skb); - spin_unlock(&q->sendq.lock); - return NET_XMIT_CN; - } - - wr = (struct fw_wr_hdr *)&q->q.desc[q->q.pidx]; - inline_tx_skb(skb, &q->q, wr); - - txq_advance(&q->q, ndesc); - if (unlikely(txq_avail(&q->q) < TXQ_STOP_THRES)) - ctrlq_check_stop(q, wr); - - ring_tx_db(q->adap, &q->q, ndesc); - spin_unlock(&q->sendq.lock); - - kfree_skb(skb); - return NET_XMIT_SUCCESS; -} - -/** - * restart_ctrlq - restart a suspended control queue - * @data: the control queue to restart - * - * Resumes transmission on a suspended Tx control queue. - */ -static void restart_ctrlq(unsigned long data) -{ - struct sk_buff *skb; - unsigned int written = 0; - struct sge_ctrl_txq *q = (struct sge_ctrl_txq *)data; - - spin_lock(&q->sendq.lock); - reclaim_completed_tx_imm(&q->q); - BUG_ON(txq_avail(&q->q) < TXQ_STOP_THRES); /* q should be empty */ - - while ((skb = __skb_dequeue(&q->sendq)) != NULL) { - struct fw_wr_hdr *wr; - unsigned int ndesc = skb->priority; /* previously saved */ - - /* - * Write descriptors and free skbs outside the lock to limit - * wait times. q->full is still set so new skbs will be queued. - */ - spin_unlock(&q->sendq.lock); - - wr = (struct fw_wr_hdr *)&q->q.desc[q->q.pidx]; - inline_tx_skb(skb, &q->q, wr); - kfree_skb(skb); - - written += ndesc; - txq_advance(&q->q, ndesc); - if (unlikely(txq_avail(&q->q) < TXQ_STOP_THRES)) { - unsigned long old = q->q.stops; - - ctrlq_check_stop(q, wr); - if (q->q.stops != old) { /* suspended anew */ - spin_lock(&q->sendq.lock); - goto ringdb; - } - } - if (written > 16) { - ring_tx_db(q->adap, &q->q, written); - written = 0; - } - spin_lock(&q->sendq.lock); - } - q->full = 0; -ringdb: if (written) - ring_tx_db(q->adap, &q->q, written); - spin_unlock(&q->sendq.lock); -} - -/** - * t4_mgmt_tx - send a management message - * @adap: the adapter - * @skb: the packet containing the management message - * - * Send a management message through control queue 0. - */ -int t4_mgmt_tx(struct adapter *adap, struct sk_buff *skb) -{ - int ret; - - local_bh_disable(); - ret = ctrl_xmit(&adap->sge.ctrlq[0], skb); - local_bh_enable(); - return ret; -} - -/** - * is_ofld_imm - check whether a packet can be sent as immediate data - * @skb: the packet - * - * Returns true if a packet can be sent as an offload WR with immediate - * data. We currently use the same limit as for Ethernet packets. - */ -static inline int is_ofld_imm(const struct sk_buff *skb) -{ - return skb->len <= MAX_IMM_TX_PKT_LEN; -} - -/** - * calc_tx_flits_ofld - calculate # of flits for an offload packet - * @skb: the packet - * - * Returns the number of flits needed for the given offload packet. - * These packets are already fully constructed and no additional headers - * will be added. - */ -static inline unsigned int calc_tx_flits_ofld(const struct sk_buff *skb) -{ - unsigned int flits, cnt; - - if (is_ofld_imm(skb)) - return DIV_ROUND_UP(skb->len, 8); - - flits = skb_transport_offset(skb) / 8U; /* headers */ - cnt = skb_shinfo(skb)->nr_frags; - if (skb->tail != skb->transport_header) - cnt++; - return flits + sgl_len(cnt); -} - -/** - * txq_stop_maperr - stop a Tx queue due to I/O MMU exhaustion - * @adap: the adapter - * @q: the queue to stop - * - * Mark a Tx queue stopped due to I/O MMU exhaustion and resulting - * inability to map packets. A periodic timer attempts to restart - * queues so marked. - */ -static void txq_stop_maperr(struct sge_ofld_txq *q) -{ - q->mapping_err++; - q->q.stops++; - set_bit(q->q.cntxt_id - q->adap->sge.egr_start, - q->adap->sge.txq_maperr); -} - -/** - * ofldtxq_stop - stop an offload Tx queue that has become full - * @q: the queue to stop - * @skb: the packet causing the queue to become full - * - * Stops an offload Tx queue that has become full and modifies the packet - * being written to request a wakeup. - */ -static void ofldtxq_stop(struct sge_ofld_txq *q, struct sk_buff *skb) -{ - struct fw_wr_hdr *wr = (struct fw_wr_hdr *)skb->data; - - wr->lo |= htonl(FW_WR_EQUEQ | FW_WR_EQUIQ); - q->q.stops++; - q->full = 1; -} - -/** - * service_ofldq - restart a suspended offload queue - * @q: the offload queue - * - * Services an offload Tx queue by moving packets from its packet queue - * to the HW Tx ring. The function starts and ends with the queue locked. - */ -static void service_ofldq(struct sge_ofld_txq *q) -{ - u64 *pos; - int credits; - struct sk_buff *skb; - unsigned int written = 0; - unsigned int flits, ndesc; - - while ((skb = skb_peek(&q->sendq)) != NULL && !q->full) { - /* - * We drop the lock but leave skb on sendq, thus retaining - * exclusive access to the state of the queue. - */ - spin_unlock(&q->sendq.lock); - - reclaim_completed_tx(q->adap, &q->q, false); - - flits = skb->priority; /* previously saved */ - ndesc = flits_to_desc(flits); - credits = txq_avail(&q->q) - ndesc; - BUG_ON(credits < 0); - if (unlikely(credits < TXQ_STOP_THRES)) - ofldtxq_stop(q, skb); - - pos = (u64 *)&q->q.desc[q->q.pidx]; - if (is_ofld_imm(skb)) - inline_tx_skb(skb, &q->q, pos); - else if (map_skb(q->adap->pdev_dev, skb, - (dma_addr_t *)skb->head)) { - txq_stop_maperr(q); - spin_lock(&q->sendq.lock); - break; - } else { - int last_desc, hdr_len = skb_transport_offset(skb); - - memcpy(pos, skb->data, hdr_len); - write_sgl(skb, &q->q, (void *)pos + hdr_len, - pos + flits, hdr_len, - (dma_addr_t *)skb->head); -#ifdef CONFIG_NEED_DMA_MAP_STATE - skb->dev = q->adap->port[0]; - skb->destructor = deferred_unmap_destructor; -#endif - last_desc = q->q.pidx + ndesc - 1; - if (last_desc >= q->q.size) - last_desc -= q->q.size; - q->q.sdesc[last_desc].skb = skb; - } - - txq_advance(&q->q, ndesc); - written += ndesc; - if (unlikely(written > 32)) { - ring_tx_db(q->adap, &q->q, written); - written = 0; - } - - spin_lock(&q->sendq.lock); - __skb_unlink(skb, &q->sendq); - if (is_ofld_imm(skb)) - kfree_skb(skb); - } - if (likely(written)) - ring_tx_db(q->adap, &q->q, written); -} - -/** - * ofld_xmit - send a packet through an offload queue - * @q: the Tx offload queue - * @skb: the packet - * - * Send an offload packet through an SGE offload queue. - */ -static int ofld_xmit(struct sge_ofld_txq *q, struct sk_buff *skb) -{ - skb->priority = calc_tx_flits_ofld(skb); /* save for restart */ - spin_lock(&q->sendq.lock); - __skb_queue_tail(&q->sendq, skb); - if (q->sendq.qlen == 1) - service_ofldq(q); - spin_unlock(&q->sendq.lock); - return NET_XMIT_SUCCESS; -} - -/** - * restart_ofldq - restart a suspended offload queue - * @data: the offload queue to restart - * - * Resumes transmission on a suspended Tx offload queue. - */ -static void restart_ofldq(unsigned long data) -{ - struct sge_ofld_txq *q = (struct sge_ofld_txq *)data; - - spin_lock(&q->sendq.lock); - q->full = 0; /* the queue actually is completely empty now */ - service_ofldq(q); - spin_unlock(&q->sendq.lock); -} - -/** - * skb_txq - return the Tx queue an offload packet should use - * @skb: the packet - * - * Returns the Tx queue an offload packet should use as indicated by bits - * 1-15 in the packet's queue_mapping. - */ -static inline unsigned int skb_txq(const struct sk_buff *skb) -{ - return skb->queue_mapping >> 1; -} - -/** - * is_ctrl_pkt - return whether an offload packet is a control packet - * @skb: the packet - * - * Returns whether an offload packet should use an OFLD or a CTRL - * Tx queue as indicated by bit 0 in the packet's queue_mapping. - */ -static inline unsigned int is_ctrl_pkt(const struct sk_buff *skb) -{ - return skb->queue_mapping & 1; -} - -static inline int ofld_send(struct adapter *adap, struct sk_buff *skb) -{ - unsigned int idx = skb_txq(skb); - - if (unlikely(is_ctrl_pkt(skb))) - return ctrl_xmit(&adap->sge.ctrlq[idx], skb); - return ofld_xmit(&adap->sge.ofldtxq[idx], skb); -} - -/** - * t4_ofld_send - send an offload packet - * @adap: the adapter - * @skb: the packet - * - * Sends an offload packet. We use the packet queue_mapping to select the - * appropriate Tx queue as follows: bit 0 indicates whether the packet - * should be sent as regular or control, bits 1-15 select the queue. - */ -int t4_ofld_send(struct adapter *adap, struct sk_buff *skb) -{ - int ret; - - local_bh_disable(); - ret = ofld_send(adap, skb); - local_bh_enable(); - return ret; -} - -/** - * cxgb4_ofld_send - send an offload packet - * @dev: the net device - * @skb: the packet - * - * Sends an offload packet. This is an exported version of @t4_ofld_send, - * intended for ULDs. - */ -int cxgb4_ofld_send(struct net_device *dev, struct sk_buff *skb) -{ - return t4_ofld_send(netdev2adap(dev), skb); -} -EXPORT_SYMBOL(cxgb4_ofld_send); - -static inline void copy_frags(struct skb_shared_info *ssi, - const struct pkt_gl *gl, unsigned int offset) -{ - unsigned int n; - - /* usually there's just one frag */ - ssi->frags[0].page = gl->frags[0].page; - ssi->frags[0].page_offset = gl->frags[0].page_offset + offset; - ssi->frags[0].size = gl->frags[0].size - offset; - ssi->nr_frags = gl->nfrags; - n = gl->nfrags - 1; - if (n) - memcpy(&ssi->frags[1], &gl->frags[1], n * sizeof(skb_frag_t)); - - /* get a reference to the last page, we don't own it */ - get_page(gl->frags[n].page); -} - -/** - * cxgb4_pktgl_to_skb - build an sk_buff from a packet gather list - * @gl: the gather list - * @skb_len: size of sk_buff main body if it carries fragments - * @pull_len: amount of data to move to the sk_buff's main body - * - * Builds an sk_buff from the given packet gather list. Returns the - * sk_buff or %NULL if sk_buff allocation failed. - */ -struct sk_buff *cxgb4_pktgl_to_skb(const struct pkt_gl *gl, - unsigned int skb_len, unsigned int pull_len) -{ - struct sk_buff *skb; - - /* - * Below we rely on RX_COPY_THRES being less than the smallest Rx buffer - * size, which is expected since buffers are at least PAGE_SIZEd. - * In this case packets up to RX_COPY_THRES have only one fragment. - */ - if (gl->tot_len <= RX_COPY_THRES) { - skb = dev_alloc_skb(gl->tot_len); - if (unlikely(!skb)) - goto out; - __skb_put(skb, gl->tot_len); - skb_copy_to_linear_data(skb, gl->va, gl->tot_len); - } else { - skb = dev_alloc_skb(skb_len); - if (unlikely(!skb)) - goto out; - __skb_put(skb, pull_len); - skb_copy_to_linear_data(skb, gl->va, pull_len); - - copy_frags(skb_shinfo(skb), gl, pull_len); - skb->len = gl->tot_len; - skb->data_len = skb->len - pull_len; - skb->truesize += skb->data_len; - } -out: return skb; -} -EXPORT_SYMBOL(cxgb4_pktgl_to_skb); - -/** - * t4_pktgl_free - free a packet gather list - * @gl: the gather list - * - * Releases the pages of a packet gather list. We do not own the last - * page on the list and do not free it. - */ -static void t4_pktgl_free(const struct pkt_gl *gl) -{ - int n; - const skb_frag_t *p; - - for (p = gl->frags, n = gl->nfrags - 1; n--; p++) - put_page(p->page); -} - -/* - * Process an MPS trace packet. Give it an unused protocol number so it won't - * be delivered to anyone and send it to the stack for capture. - */ -static noinline int handle_trace_pkt(struct adapter *adap, - const struct pkt_gl *gl) -{ - struct sk_buff *skb; - struct cpl_trace_pkt *p; - - skb = cxgb4_pktgl_to_skb(gl, RX_PULL_LEN, RX_PULL_LEN); - if (unlikely(!skb)) { - t4_pktgl_free(gl); - return 0; - } - - p = (struct cpl_trace_pkt *)skb->data; - __skb_pull(skb, sizeof(*p)); - skb_reset_mac_header(skb); - skb->protocol = htons(0xffff); - skb->dev = adap->port[0]; - netif_receive_skb(skb); - return 0; -} - -static void do_gro(struct sge_eth_rxq *rxq, const struct pkt_gl *gl, - const struct cpl_rx_pkt *pkt) -{ - int ret; - struct sk_buff *skb; - - skb = napi_get_frags(&rxq->rspq.napi); - if (unlikely(!skb)) { - t4_pktgl_free(gl); - rxq->stats.rx_drops++; - return; - } - - copy_frags(skb_shinfo(skb), gl, RX_PKT_PAD); - skb->len = gl->tot_len - RX_PKT_PAD; - skb->data_len = skb->len; - skb->truesize += skb->data_len; - skb->ip_summed = CHECKSUM_UNNECESSARY; - skb_record_rx_queue(skb, rxq->rspq.idx); - if (rxq->rspq.netdev->features & NETIF_F_RXHASH) - skb->rxhash = (__force u32)pkt->rsshdr.hash_val; - - if (unlikely(pkt->vlan_ex)) { - __vlan_hwaccel_put_tag(skb, ntohs(pkt->vlan)); - rxq->stats.vlan_ex++; - } - ret = napi_gro_frags(&rxq->rspq.napi); - if (ret == GRO_HELD) - rxq->stats.lro_pkts++; - else if (ret == GRO_MERGED || ret == GRO_MERGED_FREE) - rxq->stats.lro_merged++; - rxq->stats.pkts++; - rxq->stats.rx_cso++; -} - -/** - * t4_ethrx_handler - process an ingress ethernet packet - * @q: the response queue that received the packet - * @rsp: the response queue descriptor holding the RX_PKT message - * @si: the gather list of packet fragments - * - * Process an ingress ethernet packet and deliver it to the stack. - */ -int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, - const struct pkt_gl *si) -{ - bool csum_ok; - struct sk_buff *skb; - const struct cpl_rx_pkt *pkt; - struct sge_eth_rxq *rxq = container_of(q, struct sge_eth_rxq, rspq); - - if (unlikely(*(u8 *)rsp == CPL_TRACE_PKT)) - return handle_trace_pkt(q->adap, si); - - pkt = (const struct cpl_rx_pkt *)rsp; - csum_ok = pkt->csum_calc && !pkt->err_vec; - if ((pkt->l2info & htonl(RXF_TCP)) && - (q->netdev->features & NETIF_F_GRO) && csum_ok && !pkt->ip_frag) { - do_gro(rxq, si, pkt); - return 0; - } - - skb = cxgb4_pktgl_to_skb(si, RX_PKT_SKB_LEN, RX_PULL_LEN); - if (unlikely(!skb)) { - t4_pktgl_free(si); - rxq->stats.rx_drops++; - return 0; - } - - __skb_pull(skb, RX_PKT_PAD); /* remove ethernet header padding */ - skb->protocol = eth_type_trans(skb, q->netdev); - skb_record_rx_queue(skb, q->idx); - if (skb->dev->features & NETIF_F_RXHASH) - skb->rxhash = (__force u32)pkt->rsshdr.hash_val; - - rxq->stats.pkts++; - - if (csum_ok && (q->netdev->features & NETIF_F_RXCSUM) && - (pkt->l2info & htonl(RXF_UDP | RXF_TCP))) { - if (!pkt->ip_frag) { - skb->ip_summed = CHECKSUM_UNNECESSARY; - rxq->stats.rx_cso++; - } else if (pkt->l2info & htonl(RXF_IP)) { - __sum16 c = (__force __sum16)pkt->csum; - skb->csum = csum_unfold(c); - skb->ip_summed = CHECKSUM_COMPLETE; - rxq->stats.rx_cso++; - } - } else - skb_checksum_none_assert(skb); - - if (unlikely(pkt->vlan_ex)) { - __vlan_hwaccel_put_tag(skb, ntohs(pkt->vlan)); - rxq->stats.vlan_ex++; - } - netif_receive_skb(skb); - return 0; -} - -/** - * restore_rx_bufs - put back a packet's Rx buffers - * @si: the packet gather list - * @q: the SGE free list - * @frags: number of FL buffers to restore - * - * Puts back on an FL the Rx buffers associated with @si. The buffers - * have already been unmapped and are left unmapped, we mark them so to - * prevent further unmapping attempts. - * - * This function undoes a series of @unmap_rx_buf calls when we find out - * that the current packet can't be processed right away afterall and we - * need to come back to it later. This is a very rare event and there's - * no effort to make this particularly efficient. - */ -static void restore_rx_bufs(const struct pkt_gl *si, struct sge_fl *q, - int frags) -{ - struct rx_sw_desc *d; - - while (frags--) { - if (q->cidx == 0) - q->cidx = q->size - 1; - else - q->cidx--; - d = &q->sdesc[q->cidx]; - d->page = si->frags[frags].page; - d->dma_addr |= RX_UNMAPPED_BUF; - q->avail++; - } -} - -/** - * is_new_response - check if a response is newly written - * @r: the response descriptor - * @q: the response queue - * - * Returns true if a response descriptor contains a yet unprocessed - * response. - */ -static inline bool is_new_response(const struct rsp_ctrl *r, - const struct sge_rspq *q) -{ - return RSPD_GEN(r->type_gen) == q->gen; -} - -/** - * rspq_next - advance to the next entry in a response queue - * @q: the queue - * - * Updates the state of a response queue to advance it to the next entry. - */ -static inline void rspq_next(struct sge_rspq *q) -{ - q->cur_desc = (void *)q->cur_desc + q->iqe_len; - if (unlikely(++q->cidx == q->size)) { - q->cidx = 0; - q->gen ^= 1; - q->cur_desc = q->desc; - } -} - -/** - * process_responses - process responses from an SGE response queue - * @q: the ingress queue to process - * @budget: how many responses can be processed in this round - * - * Process responses from an SGE response queue up to the supplied budget. - * Responses include received packets as well as control messages from FW - * or HW. - * - * Additionally choose the interrupt holdoff time for the next interrupt - * on this queue. If the system is under memory shortage use a fairly - * long delay to help recovery. - */ -static int process_responses(struct sge_rspq *q, int budget) -{ - int ret, rsp_type; - int budget_left = budget; - const struct rsp_ctrl *rc; - struct sge_eth_rxq *rxq = container_of(q, struct sge_eth_rxq, rspq); - - while (likely(budget_left)) { - rc = (void *)q->cur_desc + (q->iqe_len - sizeof(*rc)); - if (!is_new_response(rc, q)) - break; - - rmb(); - rsp_type = RSPD_TYPE(rc->type_gen); - if (likely(rsp_type == RSP_TYPE_FLBUF)) { - skb_frag_t *fp; - struct pkt_gl si; - const struct rx_sw_desc *rsd; - u32 len = ntohl(rc->pldbuflen_qid), bufsz, frags; - - if (len & RSPD_NEWBUF) { - if (likely(q->offset > 0)) { - free_rx_bufs(q->adap, &rxq->fl, 1); - q->offset = 0; - } - len = RSPD_LEN(len); - } - si.tot_len = len; - - /* gather packet fragments */ - for (frags = 0, fp = si.frags; ; frags++, fp++) { - rsd = &rxq->fl.sdesc[rxq->fl.cidx]; - bufsz = get_buf_size(rsd); - fp->page = rsd->page; - fp->page_offset = q->offset; - fp->size = min(bufsz, len); - len -= fp->size; - if (!len) - break; - unmap_rx_buf(q->adap, &rxq->fl); - } - - /* - * Last buffer remains mapped so explicitly make it - * coherent for CPU access. - */ - dma_sync_single_for_cpu(q->adap->pdev_dev, - get_buf_addr(rsd), - fp->size, DMA_FROM_DEVICE); - - si.va = page_address(si.frags[0].page) + - si.frags[0].page_offset; - prefetch(si.va); - - si.nfrags = frags + 1; - ret = q->handler(q, q->cur_desc, &si); - if (likely(ret == 0)) - q->offset += ALIGN(fp->size, FL_ALIGN); - else - restore_rx_bufs(&si, &rxq->fl, frags); - } else if (likely(rsp_type == RSP_TYPE_CPL)) { - ret = q->handler(q, q->cur_desc, NULL); - } else { - ret = q->handler(q, (const __be64 *)rc, CXGB4_MSG_AN); - } - - if (unlikely(ret)) { - /* couldn't process descriptor, back off for recovery */ - q->next_intr_params = QINTR_TIMER_IDX(NOMEM_TMR_IDX); - break; - } - - rspq_next(q); - budget_left--; - } - - if (q->offset >= 0 && rxq->fl.size - rxq->fl.avail >= 16) - __refill_fl(q->adap, &rxq->fl); - return budget - budget_left; -} - -/** - * napi_rx_handler - the NAPI handler for Rx processing - * @napi: the napi instance - * @budget: how many packets we can process in this round - * - * Handler for new data events when using NAPI. This does not need any - * locking or protection from interrupts as data interrupts are off at - * this point and other adapter interrupts do not interfere (the latter - * in not a concern at all with MSI-X as non-data interrupts then have - * a separate handler). - */ -static int napi_rx_handler(struct napi_struct *napi, int budget) -{ - unsigned int params; - struct sge_rspq *q = container_of(napi, struct sge_rspq, napi); - int work_done = process_responses(q, budget); - - if (likely(work_done < budget)) { - napi_complete(napi); - params = q->next_intr_params; - q->next_intr_params = q->intr_params; - } else - params = QINTR_TIMER_IDX(7); - - t4_write_reg(q->adap, MYPF_REG(SGE_PF_GTS), CIDXINC(work_done) | - INGRESSQID((u32)q->cntxt_id) | SEINTARM(params)); - return work_done; -} - -/* - * The MSI-X interrupt handler for an SGE response queue. - */ -irqreturn_t t4_sge_intr_msix(int irq, void *cookie) -{ - struct sge_rspq *q = cookie; - - napi_schedule(&q->napi); - return IRQ_HANDLED; -} - -/* - * Process the indirect interrupt entries in the interrupt queue and kick off - * NAPI for each queue that has generated an entry. - */ -static unsigned int process_intrq(struct adapter *adap) -{ - unsigned int credits; - const struct rsp_ctrl *rc; - struct sge_rspq *q = &adap->sge.intrq; - - spin_lock(&adap->sge.intrq_lock); - for (credits = 0; ; credits++) { - rc = (void *)q->cur_desc + (q->iqe_len - sizeof(*rc)); - if (!is_new_response(rc, q)) - break; - - rmb(); - if (RSPD_TYPE(rc->type_gen) == RSP_TYPE_INTR) { - unsigned int qid = ntohl(rc->pldbuflen_qid); - - qid -= adap->sge.ingr_start; - napi_schedule(&adap->sge.ingr_map[qid]->napi); - } - - rspq_next(q); - } - - t4_write_reg(adap, MYPF_REG(SGE_PF_GTS), CIDXINC(credits) | - INGRESSQID(q->cntxt_id) | SEINTARM(q->intr_params)); - spin_unlock(&adap->sge.intrq_lock); - return credits; -} - -/* - * The MSI interrupt handler, which handles data events from SGE response queues - * as well as error and other async events as they all use the same MSI vector. - */ -static irqreturn_t t4_intr_msi(int irq, void *cookie) -{ - struct adapter *adap = cookie; - - t4_slow_intr_handler(adap); - process_intrq(adap); - return IRQ_HANDLED; -} - -/* - * Interrupt handler for legacy INTx interrupts. - * Handles data events from SGE response queues as well as error and other - * async events as they all use the same interrupt line. - */ -static irqreturn_t t4_intr_intx(int irq, void *cookie) -{ - struct adapter *adap = cookie; - - t4_write_reg(adap, MYPF_REG(PCIE_PF_CLI), 0); - if (t4_slow_intr_handler(adap) | process_intrq(adap)) - return IRQ_HANDLED; - return IRQ_NONE; /* probably shared interrupt */ -} - -/** - * t4_intr_handler - select the top-level interrupt handler - * @adap: the adapter - * - * Selects the top-level interrupt handler based on the type of interrupts - * (MSI-X, MSI, or INTx). - */ -irq_handler_t t4_intr_handler(struct adapter *adap) -{ - if (adap->flags & USING_MSIX) - return t4_sge_intr_msix; - if (adap->flags & USING_MSI) - return t4_intr_msi; - return t4_intr_intx; -} - -static void sge_rx_timer_cb(unsigned long data) -{ - unsigned long m; - unsigned int i, cnt[2]; - struct adapter *adap = (struct adapter *)data; - struct sge *s = &adap->sge; - - for (i = 0; i < ARRAY_SIZE(s->starving_fl); i++) - for (m = s->starving_fl[i]; m; m &= m - 1) { - struct sge_eth_rxq *rxq; - unsigned int id = __ffs(m) + i * BITS_PER_LONG; - struct sge_fl *fl = s->egr_map[id]; - - clear_bit(id, s->starving_fl); - smp_mb__after_clear_bit(); - - if (fl_starving(fl)) { - rxq = container_of(fl, struct sge_eth_rxq, fl); - if (napi_reschedule(&rxq->rspq.napi)) - fl->starving++; - else - set_bit(id, s->starving_fl); - } - } - - t4_write_reg(adap, SGE_DEBUG_INDEX, 13); - cnt[0] = t4_read_reg(adap, SGE_DEBUG_DATA_HIGH); - cnt[1] = t4_read_reg(adap, SGE_DEBUG_DATA_LOW); - - for (i = 0; i < 2; i++) - if (cnt[i] >= s->starve_thres) { - if (s->idma_state[i] || cnt[i] == 0xffffffff) - continue; - s->idma_state[i] = 1; - t4_write_reg(adap, SGE_DEBUG_INDEX, 11); - m = t4_read_reg(adap, SGE_DEBUG_DATA_LOW) >> (i * 16); - dev_warn(adap->pdev_dev, - "SGE idma%u starvation detected for " - "queue %lu\n", i, m & 0xffff); - } else if (s->idma_state[i]) - s->idma_state[i] = 0; - - mod_timer(&s->rx_timer, jiffies + RX_QCHECK_PERIOD); -} - -static void sge_tx_timer_cb(unsigned long data) -{ - unsigned long m; - unsigned int i, budget; - struct adapter *adap = (struct adapter *)data; - struct sge *s = &adap->sge; - - for (i = 0; i < ARRAY_SIZE(s->txq_maperr); i++) - for (m = s->txq_maperr[i]; m; m &= m - 1) { - unsigned long id = __ffs(m) + i * BITS_PER_LONG; - struct sge_ofld_txq *txq = s->egr_map[id]; - - clear_bit(id, s->txq_maperr); - tasklet_schedule(&txq->qresume_tsk); - } - - budget = MAX_TIMER_TX_RECLAIM; - i = s->ethtxq_rover; - do { - struct sge_eth_txq *q = &s->ethtxq[i]; - - if (q->q.in_use && - time_after_eq(jiffies, q->txq->trans_start + HZ / 100) && - __netif_tx_trylock(q->txq)) { - int avail = reclaimable(&q->q); - - if (avail) { - if (avail > budget) - avail = budget; - - free_tx_desc(adap, &q->q, avail, true); - q->q.in_use -= avail; - budget -= avail; - } - __netif_tx_unlock(q->txq); - } - - if (++i >= s->ethqsets) - i = 0; - } while (budget && i != s->ethtxq_rover); - s->ethtxq_rover = i; - mod_timer(&s->tx_timer, jiffies + (budget ? TX_QCHECK_PERIOD : 2)); -} - -int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq, - struct net_device *dev, int intr_idx, - struct sge_fl *fl, rspq_handler_t hnd) -{ - int ret, flsz = 0; - struct fw_iq_cmd c; - struct port_info *pi = netdev_priv(dev); - - /* Size needs to be multiple of 16, including status entry. */ - iq->size = roundup(iq->size, 16); - - iq->desc = alloc_ring(adap->pdev_dev, iq->size, iq->iqe_len, 0, - &iq->phys_addr, NULL, 0, NUMA_NO_NODE); - if (!iq->desc) - return -ENOMEM; - - memset(&c, 0, sizeof(c)); - c.op_to_vfn = htonl(FW_CMD_OP(FW_IQ_CMD) | FW_CMD_REQUEST | - FW_CMD_WRITE | FW_CMD_EXEC | - FW_IQ_CMD_PFN(adap->fn) | FW_IQ_CMD_VFN(0)); - c.alloc_to_len16 = htonl(FW_IQ_CMD_ALLOC | FW_IQ_CMD_IQSTART(1) | - FW_LEN16(c)); - c.type_to_iqandstindex = htonl(FW_IQ_CMD_TYPE(FW_IQ_TYPE_FL_INT_CAP) | - FW_IQ_CMD_IQASYNCH(fwevtq) | FW_IQ_CMD_VIID(pi->viid) | - FW_IQ_CMD_IQANDST(intr_idx < 0) | FW_IQ_CMD_IQANUD(1) | - FW_IQ_CMD_IQANDSTINDEX(intr_idx >= 0 ? intr_idx : - -intr_idx - 1)); - c.iqdroprss_to_iqesize = htons(FW_IQ_CMD_IQPCIECH(pi->tx_chan) | - FW_IQ_CMD_IQGTSMODE | - FW_IQ_CMD_IQINTCNTTHRESH(iq->pktcnt_idx) | - FW_IQ_CMD_IQESIZE(ilog2(iq->iqe_len) - 4)); - c.iqsize = htons(iq->size); - c.iqaddr = cpu_to_be64(iq->phys_addr); - - if (fl) { - fl->size = roundup(fl->size, 8); - fl->desc = alloc_ring(adap->pdev_dev, fl->size, sizeof(__be64), - sizeof(struct rx_sw_desc), &fl->addr, - &fl->sdesc, STAT_LEN, NUMA_NO_NODE); - if (!fl->desc) - goto fl_nomem; - - flsz = fl->size / 8 + STAT_LEN / sizeof(struct tx_desc); - c.iqns_to_fl0congen = htonl(FW_IQ_CMD_FL0PACKEN | - FW_IQ_CMD_FL0FETCHRO(1) | - FW_IQ_CMD_FL0DATARO(1) | - FW_IQ_CMD_FL0PADEN); - c.fl0dcaen_to_fl0cidxfthresh = htons(FW_IQ_CMD_FL0FBMIN(2) | - FW_IQ_CMD_FL0FBMAX(3)); - c.fl0size = htons(flsz); - c.fl0addr = cpu_to_be64(fl->addr); - } - - ret = t4_wr_mbox(adap, adap->fn, &c, sizeof(c), &c); - if (ret) - goto err; - - netif_napi_add(dev, &iq->napi, napi_rx_handler, 64); - iq->cur_desc = iq->desc; - iq->cidx = 0; - iq->gen = 1; - iq->next_intr_params = iq->intr_params; - iq->cntxt_id = ntohs(c.iqid); - iq->abs_id = ntohs(c.physiqid); - iq->size--; /* subtract status entry */ - iq->adap = adap; - iq->netdev = dev; - iq->handler = hnd; - - /* set offset to -1 to distinguish ingress queues without FL */ - iq->offset = fl ? 0 : -1; - - adap->sge.ingr_map[iq->cntxt_id - adap->sge.ingr_start] = iq; - - if (fl) { - fl->cntxt_id = ntohs(c.fl0id); - fl->avail = fl->pend_cred = 0; - fl->pidx = fl->cidx = 0; - fl->alloc_failed = fl->large_alloc_failed = fl->starving = 0; - adap->sge.egr_map[fl->cntxt_id - adap->sge.egr_start] = fl; - refill_fl(adap, fl, fl_cap(fl), GFP_KERNEL); - } - return 0; - -fl_nomem: - ret = -ENOMEM; -err: - if (iq->desc) { - dma_free_coherent(adap->pdev_dev, iq->size * iq->iqe_len, - iq->desc, iq->phys_addr); - iq->desc = NULL; - } - if (fl && fl->desc) { - kfree(fl->sdesc); - fl->sdesc = NULL; - dma_free_coherent(adap->pdev_dev, flsz * sizeof(struct tx_desc), - fl->desc, fl->addr); - fl->desc = NULL; - } - return ret; -} - -static void init_txq(struct adapter *adap, struct sge_txq *q, unsigned int id) -{ - q->in_use = 0; - q->cidx = q->pidx = 0; - q->stops = q->restarts = 0; - q->stat = (void *)&q->desc[q->size]; - q->cntxt_id = id; - adap->sge.egr_map[id - adap->sge.egr_start] = q; -} - -int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq, - struct net_device *dev, struct netdev_queue *netdevq, - unsigned int iqid) -{ - int ret, nentries; - struct fw_eq_eth_cmd c; - struct port_info *pi = netdev_priv(dev); - - /* Add status entries */ - nentries = txq->q.size + STAT_LEN / sizeof(struct tx_desc); - - txq->q.desc = alloc_ring(adap->pdev_dev, txq->q.size, - sizeof(struct tx_desc), sizeof(struct tx_sw_desc), - &txq->q.phys_addr, &txq->q.sdesc, STAT_LEN, - netdev_queue_numa_node_read(netdevq)); - if (!txq->q.desc) - return -ENOMEM; - - memset(&c, 0, sizeof(c)); - c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_ETH_CMD) | FW_CMD_REQUEST | - FW_CMD_WRITE | FW_CMD_EXEC | - FW_EQ_ETH_CMD_PFN(adap->fn) | FW_EQ_ETH_CMD_VFN(0)); - c.alloc_to_len16 = htonl(FW_EQ_ETH_CMD_ALLOC | - FW_EQ_ETH_CMD_EQSTART | FW_LEN16(c)); - c.viid_pkd = htonl(FW_EQ_ETH_CMD_VIID(pi->viid)); - c.fetchszm_to_iqid = htonl(FW_EQ_ETH_CMD_HOSTFCMODE(2) | - FW_EQ_ETH_CMD_PCIECHN(pi->tx_chan) | - FW_EQ_ETH_CMD_FETCHRO(1) | - FW_EQ_ETH_CMD_IQID(iqid)); - c.dcaen_to_eqsize = htonl(FW_EQ_ETH_CMD_FBMIN(2) | - FW_EQ_ETH_CMD_FBMAX(3) | - FW_EQ_ETH_CMD_CIDXFTHRESH(5) | - FW_EQ_ETH_CMD_EQSIZE(nentries)); - c.eqaddr = cpu_to_be64(txq->q.phys_addr); - - ret = t4_wr_mbox(adap, adap->fn, &c, sizeof(c), &c); - if (ret) { - kfree(txq->q.sdesc); - txq->q.sdesc = NULL; - dma_free_coherent(adap->pdev_dev, - nentries * sizeof(struct tx_desc), - txq->q.desc, txq->q.phys_addr); - txq->q.desc = NULL; - return ret; - } - - init_txq(adap, &txq->q, FW_EQ_ETH_CMD_EQID_GET(ntohl(c.eqid_pkd))); - txq->txq = netdevq; - txq->tso = txq->tx_cso = txq->vlan_ins = 0; - txq->mapping_err = 0; - return 0; -} - -int t4_sge_alloc_ctrl_txq(struct adapter *adap, struct sge_ctrl_txq *txq, - struct net_device *dev, unsigned int iqid, - unsigned int cmplqid) -{ - int ret, nentries; - struct fw_eq_ctrl_cmd c; - struct port_info *pi = netdev_priv(dev); - - /* Add status entries */ - nentries = txq->q.size + STAT_LEN / sizeof(struct tx_desc); - - txq->q.desc = alloc_ring(adap->pdev_dev, nentries, - sizeof(struct tx_desc), 0, &txq->q.phys_addr, - NULL, 0, NUMA_NO_NODE); - if (!txq->q.desc) - return -ENOMEM; - - c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_CTRL_CMD) | FW_CMD_REQUEST | - FW_CMD_WRITE | FW_CMD_EXEC | - FW_EQ_CTRL_CMD_PFN(adap->fn) | - FW_EQ_CTRL_CMD_VFN(0)); - c.alloc_to_len16 = htonl(FW_EQ_CTRL_CMD_ALLOC | - FW_EQ_CTRL_CMD_EQSTART | FW_LEN16(c)); - c.cmpliqid_eqid = htonl(FW_EQ_CTRL_CMD_CMPLIQID(cmplqid)); - c.physeqid_pkd = htonl(0); - c.fetchszm_to_iqid = htonl(FW_EQ_CTRL_CMD_HOSTFCMODE(2) | - FW_EQ_CTRL_CMD_PCIECHN(pi->tx_chan) | - FW_EQ_CTRL_CMD_FETCHRO | - FW_EQ_CTRL_CMD_IQID(iqid)); - c.dcaen_to_eqsize = htonl(FW_EQ_CTRL_CMD_FBMIN(2) | - FW_EQ_CTRL_CMD_FBMAX(3) | - FW_EQ_CTRL_CMD_CIDXFTHRESH(5) | - FW_EQ_CTRL_CMD_EQSIZE(nentries)); - c.eqaddr = cpu_to_be64(txq->q.phys_addr); - - ret = t4_wr_mbox(adap, adap->fn, &c, sizeof(c), &c); - if (ret) { - dma_free_coherent(adap->pdev_dev, - nentries * sizeof(struct tx_desc), - txq->q.desc, txq->q.phys_addr); - txq->q.desc = NULL; - return ret; - } - - init_txq(adap, &txq->q, FW_EQ_CTRL_CMD_EQID_GET(ntohl(c.cmpliqid_eqid))); - txq->adap = adap; - skb_queue_head_init(&txq->sendq); - tasklet_init(&txq->qresume_tsk, restart_ctrlq, (unsigned long)txq); - txq->full = 0; - return 0; -} - -int t4_sge_alloc_ofld_txq(struct adapter *adap, struct sge_ofld_txq *txq, - struct net_device *dev, unsigned int iqid) -{ - int ret, nentries; - struct fw_eq_ofld_cmd c; - struct port_info *pi = netdev_priv(dev); - - /* Add status entries */ - nentries = txq->q.size + STAT_LEN / sizeof(struct tx_desc); - - txq->q.desc = alloc_ring(adap->pdev_dev, txq->q.size, - sizeof(struct tx_desc), sizeof(struct tx_sw_desc), - &txq->q.phys_addr, &txq->q.sdesc, STAT_LEN, - NUMA_NO_NODE); - if (!txq->q.desc) - return -ENOMEM; - - memset(&c, 0, sizeof(c)); - c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_OFLD_CMD) | FW_CMD_REQUEST | - FW_CMD_WRITE | FW_CMD_EXEC | - FW_EQ_OFLD_CMD_PFN(adap->fn) | - FW_EQ_OFLD_CMD_VFN(0)); - c.alloc_to_len16 = htonl(FW_EQ_OFLD_CMD_ALLOC | - FW_EQ_OFLD_CMD_EQSTART | FW_LEN16(c)); - c.fetchszm_to_iqid = htonl(FW_EQ_OFLD_CMD_HOSTFCMODE(2) | - FW_EQ_OFLD_CMD_PCIECHN(pi->tx_chan) | - FW_EQ_OFLD_CMD_FETCHRO(1) | - FW_EQ_OFLD_CMD_IQID(iqid)); - c.dcaen_to_eqsize = htonl(FW_EQ_OFLD_CMD_FBMIN(2) | - FW_EQ_OFLD_CMD_FBMAX(3) | - FW_EQ_OFLD_CMD_CIDXFTHRESH(5) | - FW_EQ_OFLD_CMD_EQSIZE(nentries)); - c.eqaddr = cpu_to_be64(txq->q.phys_addr); - - ret = t4_wr_mbox(adap, adap->fn, &c, sizeof(c), &c); - if (ret) { - kfree(txq->q.sdesc); - txq->q.sdesc = NULL; - dma_free_coherent(adap->pdev_dev, - nentries * sizeof(struct tx_desc), - txq->q.desc, txq->q.phys_addr); - txq->q.desc = NULL; - return ret; - } - - init_txq(adap, &txq->q, FW_EQ_OFLD_CMD_EQID_GET(ntohl(c.eqid_pkd))); - txq->adap = adap; - skb_queue_head_init(&txq->sendq); - tasklet_init(&txq->qresume_tsk, restart_ofldq, (unsigned long)txq); - txq->full = 0; - txq->mapping_err = 0; - return 0; -} - -static void free_txq(struct adapter *adap, struct sge_txq *q) -{ - dma_free_coherent(adap->pdev_dev, - q->size * sizeof(struct tx_desc) + STAT_LEN, - q->desc, q->phys_addr); - q->cntxt_id = 0; - q->sdesc = NULL; - q->desc = NULL; -} - -static void free_rspq_fl(struct adapter *adap, struct sge_rspq *rq, - struct sge_fl *fl) -{ - unsigned int fl_id = fl ? fl->cntxt_id : 0xffff; - - adap->sge.ingr_map[rq->cntxt_id - adap->sge.ingr_start] = NULL; - t4_iq_free(adap, adap->fn, adap->fn, 0, FW_IQ_TYPE_FL_INT_CAP, - rq->cntxt_id, fl_id, 0xffff); - dma_free_coherent(adap->pdev_dev, (rq->size + 1) * rq->iqe_len, - rq->desc, rq->phys_addr); - netif_napi_del(&rq->napi); - rq->netdev = NULL; - rq->cntxt_id = rq->abs_id = 0; - rq->desc = NULL; - - if (fl) { - free_rx_bufs(adap, fl, fl->avail); - dma_free_coherent(adap->pdev_dev, fl->size * 8 + STAT_LEN, - fl->desc, fl->addr); - kfree(fl->sdesc); - fl->sdesc = NULL; - fl->cntxt_id = 0; - fl->desc = NULL; - } -} - -/** - * t4_free_sge_resources - free SGE resources - * @adap: the adapter - * - * Frees resources used by the SGE queue sets. - */ -void t4_free_sge_resources(struct adapter *adap) -{ - int i; - struct sge_eth_rxq *eq = adap->sge.ethrxq; - struct sge_eth_txq *etq = adap->sge.ethtxq; - struct sge_ofld_rxq *oq = adap->sge.ofldrxq; - - /* clean up Ethernet Tx/Rx queues */ - for (i = 0; i < adap->sge.ethqsets; i++, eq++, etq++) { - if (eq->rspq.desc) - free_rspq_fl(adap, &eq->rspq, &eq->fl); - if (etq->q.desc) { - t4_eth_eq_free(adap, adap->fn, adap->fn, 0, - etq->q.cntxt_id); - free_tx_desc(adap, &etq->q, etq->q.in_use, true); - kfree(etq->q.sdesc); - free_txq(adap, &etq->q); - } - } - - /* clean up RDMA and iSCSI Rx queues */ - for (i = 0; i < adap->sge.ofldqsets; i++, oq++) { - if (oq->rspq.desc) - free_rspq_fl(adap, &oq->rspq, &oq->fl); - } - for (i = 0, oq = adap->sge.rdmarxq; i < adap->sge.rdmaqs; i++, oq++) { - if (oq->rspq.desc) - free_rspq_fl(adap, &oq->rspq, &oq->fl); - } - - /* clean up offload Tx queues */ - for (i = 0; i < ARRAY_SIZE(adap->sge.ofldtxq); i++) { - struct sge_ofld_txq *q = &adap->sge.ofldtxq[i]; - - if (q->q.desc) { - tasklet_kill(&q->qresume_tsk); - t4_ofld_eq_free(adap, adap->fn, adap->fn, 0, - q->q.cntxt_id); - free_tx_desc(adap, &q->q, q->q.in_use, false); - kfree(q->q.sdesc); - __skb_queue_purge(&q->sendq); - free_txq(adap, &q->q); - } - } - - /* clean up control Tx queues */ - for (i = 0; i < ARRAY_SIZE(adap->sge.ctrlq); i++) { - struct sge_ctrl_txq *cq = &adap->sge.ctrlq[i]; - - if (cq->q.desc) { - tasklet_kill(&cq->qresume_tsk); - t4_ctrl_eq_free(adap, adap->fn, adap->fn, 0, - cq->q.cntxt_id); - __skb_queue_purge(&cq->sendq); - free_txq(adap, &cq->q); - } - } - - if (adap->sge.fw_evtq.desc) - free_rspq_fl(adap, &adap->sge.fw_evtq, NULL); - - if (adap->sge.intrq.desc) - free_rspq_fl(adap, &adap->sge.intrq, NULL); - - /* clear the reverse egress queue map */ - memset(adap->sge.egr_map, 0, sizeof(adap->sge.egr_map)); -} - -void t4_sge_start(struct adapter *adap) -{ - adap->sge.ethtxq_rover = 0; - mod_timer(&adap->sge.rx_timer, jiffies + RX_QCHECK_PERIOD); - mod_timer(&adap->sge.tx_timer, jiffies + TX_QCHECK_PERIOD); -} - -/** - * t4_sge_stop - disable SGE operation - * @adap: the adapter - * - * Stop tasklets and timers associated with the DMA engine. Note that - * this is effective only if measures have been taken to disable any HW - * events that may restart them. - */ -void t4_sge_stop(struct adapter *adap) -{ - int i; - struct sge *s = &adap->sge; - - if (in_interrupt()) /* actions below require waiting */ - return; - - if (s->rx_timer.function) - del_timer_sync(&s->rx_timer); - if (s->tx_timer.function) - del_timer_sync(&s->tx_timer); - - for (i = 0; i < ARRAY_SIZE(s->ofldtxq); i++) { - struct sge_ofld_txq *q = &s->ofldtxq[i]; - - if (q->q.desc) - tasklet_kill(&q->qresume_tsk); - } - for (i = 0; i < ARRAY_SIZE(s->ctrlq); i++) { - struct sge_ctrl_txq *cq = &s->ctrlq[i]; - - if (cq->q.desc) - tasklet_kill(&cq->qresume_tsk); - } -} - -/** - * t4_sge_init - initialize SGE - * @adap: the adapter - * - * Performs SGE initialization needed every time after a chip reset. - * We do not initialize any of the queues here, instead the driver - * top-level must request them individually. - */ -void t4_sge_init(struct adapter *adap) -{ - unsigned int i, v; - struct sge *s = &adap->sge; - unsigned int fl_align_log = ilog2(FL_ALIGN); - - t4_set_reg_field(adap, SGE_CONTROL, PKTSHIFT_MASK | - INGPADBOUNDARY_MASK | EGRSTATUSPAGESIZE, - INGPADBOUNDARY(fl_align_log - 5) | PKTSHIFT(2) | - RXPKTCPLMODE | - (STAT_LEN == 128 ? EGRSTATUSPAGESIZE : 0)); - - for (i = v = 0; i < 32; i += 4) - v |= (PAGE_SHIFT - 10) << i; - t4_write_reg(adap, SGE_HOST_PAGE_SIZE, v); - t4_write_reg(adap, SGE_FL_BUFFER_SIZE0, PAGE_SIZE); -#if FL_PG_ORDER > 0 - t4_write_reg(adap, SGE_FL_BUFFER_SIZE1, PAGE_SIZE << FL_PG_ORDER); -#endif - t4_write_reg(adap, SGE_INGRESS_RX_THRESHOLD, - THRESHOLD_0(s->counter_val[0]) | - THRESHOLD_1(s->counter_val[1]) | - THRESHOLD_2(s->counter_val[2]) | - THRESHOLD_3(s->counter_val[3])); - t4_write_reg(adap, SGE_TIMER_VALUE_0_AND_1, - TIMERVALUE0(us_to_core_ticks(adap, s->timer_val[0])) | - TIMERVALUE1(us_to_core_ticks(adap, s->timer_val[1]))); - t4_write_reg(adap, SGE_TIMER_VALUE_2_AND_3, - TIMERVALUE0(us_to_core_ticks(adap, s->timer_val[2])) | - TIMERVALUE1(us_to_core_ticks(adap, s->timer_val[3]))); - t4_write_reg(adap, SGE_TIMER_VALUE_4_AND_5, - TIMERVALUE0(us_to_core_ticks(adap, s->timer_val[4])) | - TIMERVALUE1(us_to_core_ticks(adap, s->timer_val[5]))); - setup_timer(&s->rx_timer, sge_rx_timer_cb, (unsigned long)adap); - setup_timer(&s->tx_timer, sge_tx_timer_cb, (unsigned long)adap); - s->starve_thres = core_ticks_per_usec(adap) * 1000000; /* 1 s */ - s->idma_state[0] = s->idma_state[1] = 0; - spin_lock_init(&s->intrq_lock); -} diff --git a/drivers/net/cxgb4/t4_hw.c b/drivers/net/cxgb4/t4_hw.c deleted file mode 100644 index d1ec111aebd8..000000000000 --- a/drivers/net/cxgb4/t4_hw.c +++ /dev/null @@ -1,2856 +0,0 @@ -/* - * This file is part of the Chelsio T4 Ethernet driver for Linux. - * - * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include "cxgb4.h" -#include "t4_regs.h" -#include "t4fw_api.h" - -/** - * t4_wait_op_done_val - wait until an operation is completed - * @adapter: the adapter performing the operation - * @reg: the register to check for completion - * @mask: a single-bit field within @reg that indicates completion - * @polarity: the value of the field when the operation is completed - * @attempts: number of check iterations - * @delay: delay in usecs between iterations - * @valp: where to store the value of the register at completion time - * - * Wait until an operation is completed by checking a bit in a register - * up to @attempts times. If @valp is not NULL the value of the register - * at the time it indicated completion is stored there. Returns 0 if the - * operation completes and -EAGAIN otherwise. - */ -static int t4_wait_op_done_val(struct adapter *adapter, int reg, u32 mask, - int polarity, int attempts, int delay, u32 *valp) -{ - while (1) { - u32 val = t4_read_reg(adapter, reg); - - if (!!(val & mask) == polarity) { - if (valp) - *valp = val; - return 0; - } - if (--attempts == 0) - return -EAGAIN; - if (delay) - udelay(delay); - } -} - -static inline int t4_wait_op_done(struct adapter *adapter, int reg, u32 mask, - int polarity, int attempts, int delay) -{ - return t4_wait_op_done_val(adapter, reg, mask, polarity, attempts, - delay, NULL); -} - -/** - * t4_set_reg_field - set a register field to a value - * @adapter: the adapter to program - * @addr: the register address - * @mask: specifies the portion of the register to modify - * @val: the new value for the register field - * - * Sets a register field specified by the supplied mask to the - * given value. - */ -void t4_set_reg_field(struct adapter *adapter, unsigned int addr, u32 mask, - u32 val) -{ - u32 v = t4_read_reg(adapter, addr) & ~mask; - - t4_write_reg(adapter, addr, v | val); - (void) t4_read_reg(adapter, addr); /* flush */ -} - -/** - * t4_read_indirect - read indirectly addressed registers - * @adap: the adapter - * @addr_reg: register holding the indirect address - * @data_reg: register holding the value of the indirect register - * @vals: where the read register values are stored - * @nregs: how many indirect registers to read - * @start_idx: index of first indirect register to read - * - * Reads registers that are accessed indirectly through an address/data - * register pair. - */ -static void t4_read_indirect(struct adapter *adap, unsigned int addr_reg, - unsigned int data_reg, u32 *vals, - unsigned int nregs, unsigned int start_idx) -{ - while (nregs--) { - t4_write_reg(adap, addr_reg, start_idx); - *vals++ = t4_read_reg(adap, data_reg); - start_idx++; - } -} - -/* - * Get the reply to a mailbox command and store it in @rpl in big-endian order. - */ -static void get_mbox_rpl(struct adapter *adap, __be64 *rpl, int nflit, - u32 mbox_addr) -{ - for ( ; nflit; nflit--, mbox_addr += 8) - *rpl++ = cpu_to_be64(t4_read_reg64(adap, mbox_addr)); -} - -/* - * Handle a FW assertion reported in a mailbox. - */ -static void fw_asrt(struct adapter *adap, u32 mbox_addr) -{ - struct fw_debug_cmd asrt; - - get_mbox_rpl(adap, (__be64 *)&asrt, sizeof(asrt) / 8, mbox_addr); - dev_alert(adap->pdev_dev, - "FW assertion at %.16s:%u, val0 %#x, val1 %#x\n", - asrt.u.assert.filename_0_7, ntohl(asrt.u.assert.line), - ntohl(asrt.u.assert.x), ntohl(asrt.u.assert.y)); -} - -static void dump_mbox(struct adapter *adap, int mbox, u32 data_reg) -{ - dev_err(adap->pdev_dev, - "mbox %d: %llx %llx %llx %llx %llx %llx %llx %llx\n", mbox, - (unsigned long long)t4_read_reg64(adap, data_reg), - (unsigned long long)t4_read_reg64(adap, data_reg + 8), - (unsigned long long)t4_read_reg64(adap, data_reg + 16), - (unsigned long long)t4_read_reg64(adap, data_reg + 24), - (unsigned long long)t4_read_reg64(adap, data_reg + 32), - (unsigned long long)t4_read_reg64(adap, data_reg + 40), - (unsigned long long)t4_read_reg64(adap, data_reg + 48), - (unsigned long long)t4_read_reg64(adap, data_reg + 56)); -} - -/** - * t4_wr_mbox_meat - send a command to FW through the given mailbox - * @adap: the adapter - * @mbox: index of the mailbox to use - * @cmd: the command to write - * @size: command length in bytes - * @rpl: where to optionally store the reply - * @sleep_ok: if true we may sleep while awaiting command completion - * - * Sends the given command to FW through the selected mailbox and waits - * for the FW to execute the command. If @rpl is not %NULL it is used to - * store the FW's reply to the command. The command and its optional - * reply are of the same length. FW can take up to %FW_CMD_MAX_TIMEOUT ms - * to respond. @sleep_ok determines whether we may sleep while awaiting - * the response. If sleeping is allowed we use progressive backoff - * otherwise we spin. - * - * The return value is 0 on success or a negative errno on failure. A - * failure can happen either because we are not able to execute the - * command or FW executes it but signals an error. In the latter case - * the return value is the error code indicated by FW (negated). - */ -int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size, - void *rpl, bool sleep_ok) -{ - static const int delay[] = { - 1, 1, 3, 5, 10, 10, 20, 50, 100, 200 - }; - - u32 v; - u64 res; - int i, ms, delay_idx; - const __be64 *p = cmd; - u32 data_reg = PF_REG(mbox, CIM_PF_MAILBOX_DATA); - u32 ctl_reg = PF_REG(mbox, CIM_PF_MAILBOX_CTRL); - - if ((size & 15) || size > MBOX_LEN) - return -EINVAL; - - /* - * If the device is off-line, as in EEH, commands will time out. - * Fail them early so we don't waste time waiting. - */ - if (adap->pdev->error_state != pci_channel_io_normal) - return -EIO; - - v = MBOWNER_GET(t4_read_reg(adap, ctl_reg)); - for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++) - v = MBOWNER_GET(t4_read_reg(adap, ctl_reg)); - - if (v != MBOX_OWNER_DRV) - return v ? -EBUSY : -ETIMEDOUT; - - for (i = 0; i < size; i += 8) - t4_write_reg64(adap, data_reg + i, be64_to_cpu(*p++)); - - t4_write_reg(adap, ctl_reg, MBMSGVALID | MBOWNER(MBOX_OWNER_FW)); - t4_read_reg(adap, ctl_reg); /* flush write */ - - delay_idx = 0; - ms = delay[0]; - - for (i = 0; i < FW_CMD_MAX_TIMEOUT; i += ms) { - if (sleep_ok) { - ms = delay[delay_idx]; /* last element may repeat */ - if (delay_idx < ARRAY_SIZE(delay) - 1) - delay_idx++; - msleep(ms); - } else - mdelay(ms); - - v = t4_read_reg(adap, ctl_reg); - if (MBOWNER_GET(v) == MBOX_OWNER_DRV) { - if (!(v & MBMSGVALID)) { - t4_write_reg(adap, ctl_reg, 0); - continue; - } - - res = t4_read_reg64(adap, data_reg); - if (FW_CMD_OP_GET(res >> 32) == FW_DEBUG_CMD) { - fw_asrt(adap, data_reg); - res = FW_CMD_RETVAL(EIO); - } else if (rpl) - get_mbox_rpl(adap, rpl, size / 8, data_reg); - - if (FW_CMD_RETVAL_GET((int)res)) - dump_mbox(adap, mbox, data_reg); - t4_write_reg(adap, ctl_reg, 0); - return -FW_CMD_RETVAL_GET((int)res); - } - } - - dump_mbox(adap, mbox, data_reg); - dev_err(adap->pdev_dev, "command %#x in mailbox %d timed out\n", - *(const u8 *)cmd, mbox); - return -ETIMEDOUT; -} - -/** - * t4_mc_read - read from MC through backdoor accesses - * @adap: the adapter - * @addr: address of first byte requested - * @data: 64 bytes of data containing the requested address - * @ecc: where to store the corresponding 64-bit ECC word - * - * Read 64 bytes of data from MC starting at a 64-byte-aligned address - * that covers the requested address @addr. If @parity is not %NULL it - * is assigned the 64-bit ECC word for the read data. - */ -int t4_mc_read(struct adapter *adap, u32 addr, __be32 *data, u64 *ecc) -{ - int i; - - if (t4_read_reg(adap, MC_BIST_CMD) & START_BIST) - return -EBUSY; - t4_write_reg(adap, MC_BIST_CMD_ADDR, addr & ~0x3fU); - t4_write_reg(adap, MC_BIST_CMD_LEN, 64); - t4_write_reg(adap, MC_BIST_DATA_PATTERN, 0xc); - t4_write_reg(adap, MC_BIST_CMD, BIST_OPCODE(1) | START_BIST | - BIST_CMD_GAP(1)); - i = t4_wait_op_done(adap, MC_BIST_CMD, START_BIST, 0, 10, 1); - if (i) - return i; - -#define MC_DATA(i) MC_BIST_STATUS_REG(MC_BIST_STATUS_RDATA, i) - - for (i = 15; i >= 0; i--) - *data++ = htonl(t4_read_reg(adap, MC_DATA(i))); - if (ecc) - *ecc = t4_read_reg64(adap, MC_DATA(16)); -#undef MC_DATA - return 0; -} - -/** - * t4_edc_read - read from EDC through backdoor accesses - * @adap: the adapter - * @idx: which EDC to access - * @addr: address of first byte requested - * @data: 64 bytes of data containing the requested address - * @ecc: where to store the corresponding 64-bit ECC word - * - * Read 64 bytes of data from EDC starting at a 64-byte-aligned address - * that covers the requested address @addr. If @parity is not %NULL it - * is assigned the 64-bit ECC word for the read data. - */ -int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc) -{ - int i; - - idx *= EDC_STRIDE; - if (t4_read_reg(adap, EDC_BIST_CMD + idx) & START_BIST) - return -EBUSY; - t4_write_reg(adap, EDC_BIST_CMD_ADDR + idx, addr & ~0x3fU); - t4_write_reg(adap, EDC_BIST_CMD_LEN + idx, 64); - t4_write_reg(adap, EDC_BIST_DATA_PATTERN + idx, 0xc); - t4_write_reg(adap, EDC_BIST_CMD + idx, - BIST_OPCODE(1) | BIST_CMD_GAP(1) | START_BIST); - i = t4_wait_op_done(adap, EDC_BIST_CMD + idx, START_BIST, 0, 10, 1); - if (i) - return i; - -#define EDC_DATA(i) (EDC_BIST_STATUS_REG(EDC_BIST_STATUS_RDATA, i) + idx) - - for (i = 15; i >= 0; i--) - *data++ = htonl(t4_read_reg(adap, EDC_DATA(i))); - if (ecc) - *ecc = t4_read_reg64(adap, EDC_DATA(16)); -#undef EDC_DATA - return 0; -} - -#define EEPROM_STAT_ADDR 0x7bfc -#define VPD_BASE 0 -#define VPD_LEN 512 - -/** - * t4_seeprom_wp - enable/disable EEPROM write protection - * @adapter: the adapter - * @enable: whether to enable or disable write protection - * - * Enables or disables write protection on the serial EEPROM. - */ -int t4_seeprom_wp(struct adapter *adapter, bool enable) -{ - unsigned int v = enable ? 0xc : 0; - int ret = pci_write_vpd(adapter->pdev, EEPROM_STAT_ADDR, 4, &v); - return ret < 0 ? ret : 0; -} - -/** - * get_vpd_params - read VPD parameters from VPD EEPROM - * @adapter: adapter to read - * @p: where to store the parameters - * - * Reads card parameters stored in VPD EEPROM. - */ -static int get_vpd_params(struct adapter *adapter, struct vpd_params *p) -{ - int i, ret; - int ec, sn; - u8 vpd[VPD_LEN], csum; - unsigned int vpdr_len, kw_offset, id_len; - - ret = pci_read_vpd(adapter->pdev, VPD_BASE, sizeof(vpd), vpd); - if (ret < 0) - return ret; - - if (vpd[0] != PCI_VPD_LRDT_ID_STRING) { - dev_err(adapter->pdev_dev, "missing VPD ID string\n"); - return -EINVAL; - } - - id_len = pci_vpd_lrdt_size(vpd); - if (id_len > ID_LEN) - id_len = ID_LEN; - - i = pci_vpd_find_tag(vpd, 0, VPD_LEN, PCI_VPD_LRDT_RO_DATA); - if (i < 0) { - dev_err(adapter->pdev_dev, "missing VPD-R section\n"); - return -EINVAL; - } - - vpdr_len = pci_vpd_lrdt_size(&vpd[i]); - kw_offset = i + PCI_VPD_LRDT_TAG_SIZE; - if (vpdr_len + kw_offset > VPD_LEN) { - dev_err(adapter->pdev_dev, "bad VPD-R length %u\n", vpdr_len); - return -EINVAL; - } - -#define FIND_VPD_KW(var, name) do { \ - var = pci_vpd_find_info_keyword(vpd, kw_offset, vpdr_len, name); \ - if (var < 0) { \ - dev_err(adapter->pdev_dev, "missing VPD keyword " name "\n"); \ - return -EINVAL; \ - } \ - var += PCI_VPD_INFO_FLD_HDR_SIZE; \ -} while (0) - - FIND_VPD_KW(i, "RV"); - for (csum = 0; i >= 0; i--) - csum += vpd[i]; - - if (csum) { - dev_err(adapter->pdev_dev, - "corrupted VPD EEPROM, actual csum %u\n", csum); - return -EINVAL; - } - - FIND_VPD_KW(ec, "EC"); - FIND_VPD_KW(sn, "SN"); -#undef FIND_VPD_KW - - memcpy(p->id, vpd + PCI_VPD_LRDT_TAG_SIZE, id_len); - strim(p->id); - memcpy(p->ec, vpd + ec, EC_LEN); - strim(p->ec); - i = pci_vpd_info_field_size(vpd + sn - PCI_VPD_INFO_FLD_HDR_SIZE); - memcpy(p->sn, vpd + sn, min(i, SERNUM_LEN)); - strim(p->sn); - return 0; -} - -/* serial flash and firmware constants */ -enum { - SF_ATTEMPTS = 10, /* max retries for SF operations */ - - /* flash command opcodes */ - SF_PROG_PAGE = 2, /* program page */ - SF_WR_DISABLE = 4, /* disable writes */ - SF_RD_STATUS = 5, /* read status register */ - SF_WR_ENABLE = 6, /* enable writes */ - SF_RD_DATA_FAST = 0xb, /* read flash */ - SF_RD_ID = 0x9f, /* read ID */ - SF_ERASE_SECTOR = 0xd8, /* erase sector */ - - FW_MAX_SIZE = 512 * 1024, -}; - -/** - * sf1_read - read data from the serial flash - * @adapter: the adapter - * @byte_cnt: number of bytes to read - * @cont: whether another operation will be chained - * @lock: whether to lock SF for PL access only - * @valp: where to store the read data - * - * Reads up to 4 bytes of data from the serial flash. The location of - * the read needs to be specified prior to calling this by issuing the - * appropriate commands to the serial flash. - */ -static int sf1_read(struct adapter *adapter, unsigned int byte_cnt, int cont, - int lock, u32 *valp) -{ - int ret; - - if (!byte_cnt || byte_cnt > 4) - return -EINVAL; - if (t4_read_reg(adapter, SF_OP) & BUSY) - return -EBUSY; - cont = cont ? SF_CONT : 0; - lock = lock ? SF_LOCK : 0; - t4_write_reg(adapter, SF_OP, lock | cont | BYTECNT(byte_cnt - 1)); - ret = t4_wait_op_done(adapter, SF_OP, BUSY, 0, SF_ATTEMPTS, 5); - if (!ret) - *valp = t4_read_reg(adapter, SF_DATA); - return ret; -} - -/** - * sf1_write - write data to the serial flash - * @adapter: the adapter - * @byte_cnt: number of bytes to write - * @cont: whether another operation will be chained - * @lock: whether to lock SF for PL access only - * @val: value to write - * - * Writes up to 4 bytes of data to the serial flash. The location of - * the write needs to be specified prior to calling this by issuing the - * appropriate commands to the serial flash. - */ -static int sf1_write(struct adapter *adapter, unsigned int byte_cnt, int cont, - int lock, u32 val) -{ - if (!byte_cnt || byte_cnt > 4) - return -EINVAL; - if (t4_read_reg(adapter, SF_OP) & BUSY) - return -EBUSY; - cont = cont ? SF_CONT : 0; - lock = lock ? SF_LOCK : 0; - t4_write_reg(adapter, SF_DATA, val); - t4_write_reg(adapter, SF_OP, lock | - cont | BYTECNT(byte_cnt - 1) | OP_WR); - return t4_wait_op_done(adapter, SF_OP, BUSY, 0, SF_ATTEMPTS, 5); -} - -/** - * flash_wait_op - wait for a flash operation to complete - * @adapter: the adapter - * @attempts: max number of polls of the status register - * @delay: delay between polls in ms - * - * Wait for a flash operation to complete by polling the status register. - */ -static int flash_wait_op(struct adapter *adapter, int attempts, int delay) -{ - int ret; - u32 status; - - while (1) { - if ((ret = sf1_write(adapter, 1, 1, 1, SF_RD_STATUS)) != 0 || - (ret = sf1_read(adapter, 1, 0, 1, &status)) != 0) - return ret; - if (!(status & 1)) - return 0; - if (--attempts == 0) - return -EAGAIN; - if (delay) - msleep(delay); - } -} - -/** - * t4_read_flash - read words from serial flash - * @adapter: the adapter - * @addr: the start address for the read - * @nwords: how many 32-bit words to read - * @data: where to store the read data - * @byte_oriented: whether to store data as bytes or as words - * - * Read the specified number of 32-bit words from the serial flash. - * If @byte_oriented is set the read data is stored as a byte array - * (i.e., big-endian), otherwise as 32-bit words in the platform's - * natural endianess. - */ -static int t4_read_flash(struct adapter *adapter, unsigned int addr, - unsigned int nwords, u32 *data, int byte_oriented) -{ - int ret; - - if (addr + nwords * sizeof(u32) > adapter->params.sf_size || (addr & 3)) - return -EINVAL; - - addr = swab32(addr) | SF_RD_DATA_FAST; - - if ((ret = sf1_write(adapter, 4, 1, 0, addr)) != 0 || - (ret = sf1_read(adapter, 1, 1, 0, data)) != 0) - return ret; - - for ( ; nwords; nwords--, data++) { - ret = sf1_read(adapter, 4, nwords > 1, nwords == 1, data); - if (nwords == 1) - t4_write_reg(adapter, SF_OP, 0); /* unlock SF */ - if (ret) - return ret; - if (byte_oriented) - *data = htonl(*data); - } - return 0; -} - -/** - * t4_write_flash - write up to a page of data to the serial flash - * @adapter: the adapter - * @addr: the start address to write - * @n: length of data to write in bytes - * @data: the data to write - * - * Writes up to a page of data (256 bytes) to the serial flash starting - * at the given address. All the data must be written to the same page. - */ -static int t4_write_flash(struct adapter *adapter, unsigned int addr, - unsigned int n, const u8 *data) -{ - int ret; - u32 buf[64]; - unsigned int i, c, left, val, offset = addr & 0xff; - - if (addr >= adapter->params.sf_size || offset + n > SF_PAGE_SIZE) - return -EINVAL; - - val = swab32(addr) | SF_PROG_PAGE; - - if ((ret = sf1_write(adapter, 1, 0, 1, SF_WR_ENABLE)) != 0 || - (ret = sf1_write(adapter, 4, 1, 1, val)) != 0) - goto unlock; - - for (left = n; left; left -= c) { - c = min(left, 4U); - for (val = 0, i = 0; i < c; ++i) - val = (val << 8) + *data++; - - ret = sf1_write(adapter, c, c != left, 1, val); - if (ret) - goto unlock; - } - ret = flash_wait_op(adapter, 8, 1); - if (ret) - goto unlock; - - t4_write_reg(adapter, SF_OP, 0); /* unlock SF */ - - /* Read the page to verify the write succeeded */ - ret = t4_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf, 1); - if (ret) - return ret; - - if (memcmp(data - n, (u8 *)buf + offset, n)) { - dev_err(adapter->pdev_dev, - "failed to correctly write the flash page at %#x\n", - addr); - return -EIO; - } - return 0; - -unlock: - t4_write_reg(adapter, SF_OP, 0); /* unlock SF */ - return ret; -} - -/** - * get_fw_version - read the firmware version - * @adapter: the adapter - * @vers: where to place the version - * - * Reads the FW version from flash. - */ -static int get_fw_version(struct adapter *adapter, u32 *vers) -{ - return t4_read_flash(adapter, adapter->params.sf_fw_start + - offsetof(struct fw_hdr, fw_ver), 1, vers, 0); -} - -/** - * get_tp_version - read the TP microcode version - * @adapter: the adapter - * @vers: where to place the version - * - * Reads the TP microcode version from flash. - */ -static int get_tp_version(struct adapter *adapter, u32 *vers) -{ - return t4_read_flash(adapter, adapter->params.sf_fw_start + - offsetof(struct fw_hdr, tp_microcode_ver), - 1, vers, 0); -} - -/** - * t4_check_fw_version - check if the FW is compatible with this driver - * @adapter: the adapter - * - * Checks if an adapter's FW is compatible with the driver. Returns 0 - * if there's exact match, a negative error if the version could not be - * read or there's a major version mismatch, and a positive value if the - * expected major version is found but there's a minor version mismatch. - */ -int t4_check_fw_version(struct adapter *adapter) -{ - u32 api_vers[2]; - int ret, major, minor, micro; - - ret = get_fw_version(adapter, &adapter->params.fw_vers); - if (!ret) - ret = get_tp_version(adapter, &adapter->params.tp_vers); - if (!ret) - ret = t4_read_flash(adapter, adapter->params.sf_fw_start + - offsetof(struct fw_hdr, intfver_nic), - 2, api_vers, 1); - if (ret) - return ret; - - major = FW_HDR_FW_VER_MAJOR_GET(adapter->params.fw_vers); - minor = FW_HDR_FW_VER_MINOR_GET(adapter->params.fw_vers); - micro = FW_HDR_FW_VER_MICRO_GET(adapter->params.fw_vers); - memcpy(adapter->params.api_vers, api_vers, - sizeof(adapter->params.api_vers)); - - if (major != FW_VERSION_MAJOR) { /* major mismatch - fail */ - dev_err(adapter->pdev_dev, - "card FW has major version %u, driver wants %u\n", - major, FW_VERSION_MAJOR); - return -EINVAL; - } - - if (minor == FW_VERSION_MINOR && micro == FW_VERSION_MICRO) - return 0; /* perfect match */ - - /* Minor/micro version mismatch. Report it but often it's OK. */ - return 1; -} - -/** - * t4_flash_erase_sectors - erase a range of flash sectors - * @adapter: the adapter - * @start: the first sector to erase - * @end: the last sector to erase - * - * Erases the sectors in the given inclusive range. - */ -static int t4_flash_erase_sectors(struct adapter *adapter, int start, int end) -{ - int ret = 0; - - while (start <= end) { - if ((ret = sf1_write(adapter, 1, 0, 1, SF_WR_ENABLE)) != 0 || - (ret = sf1_write(adapter, 4, 0, 1, - SF_ERASE_SECTOR | (start << 8))) != 0 || - (ret = flash_wait_op(adapter, 14, 500)) != 0) { - dev_err(adapter->pdev_dev, - "erase of flash sector %d failed, error %d\n", - start, ret); - break; - } - start++; - } - t4_write_reg(adapter, SF_OP, 0); /* unlock SF */ - return ret; -} - -/** - * t4_load_fw - download firmware - * @adap: the adapter - * @fw_data: the firmware image to write - * @size: image size - * - * Write the supplied firmware image to the card's serial flash. - */ -int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size) -{ - u32 csum; - int ret, addr; - unsigned int i; - u8 first_page[SF_PAGE_SIZE]; - const u32 *p = (const u32 *)fw_data; - const struct fw_hdr *hdr = (const struct fw_hdr *)fw_data; - unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec; - unsigned int fw_img_start = adap->params.sf_fw_start; - unsigned int fw_start_sec = fw_img_start / sf_sec_size; - - if (!size) { - dev_err(adap->pdev_dev, "FW image has no data\n"); - return -EINVAL; - } - if (size & 511) { - dev_err(adap->pdev_dev, - "FW image size not multiple of 512 bytes\n"); - return -EINVAL; - } - if (ntohs(hdr->len512) * 512 != size) { - dev_err(adap->pdev_dev, - "FW image size differs from size in FW header\n"); - return -EINVAL; - } - if (size > FW_MAX_SIZE) { - dev_err(adap->pdev_dev, "FW image too large, max is %u bytes\n", - FW_MAX_SIZE); - return -EFBIG; - } - - for (csum = 0, i = 0; i < size / sizeof(csum); i++) - csum += ntohl(p[i]); - - if (csum != 0xffffffff) { - dev_err(adap->pdev_dev, - "corrupted firmware image, checksum %#x\n", csum); - return -EINVAL; - } - - i = DIV_ROUND_UP(size, sf_sec_size); /* # of sectors spanned */ - ret = t4_flash_erase_sectors(adap, fw_start_sec, fw_start_sec + i - 1); - if (ret) - goto out; - - /* - * We write the correct version at the end so the driver can see a bad - * version if the FW write fails. Start by writing a copy of the - * first page with a bad version. - */ - memcpy(first_page, fw_data, SF_PAGE_SIZE); - ((struct fw_hdr *)first_page)->fw_ver = htonl(0xffffffff); - ret = t4_write_flash(adap, fw_img_start, SF_PAGE_SIZE, first_page); - if (ret) - goto out; - - addr = fw_img_start; - for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) { - addr += SF_PAGE_SIZE; - fw_data += SF_PAGE_SIZE; - ret = t4_write_flash(adap, addr, SF_PAGE_SIZE, fw_data); - if (ret) - goto out; - } - - ret = t4_write_flash(adap, - fw_img_start + offsetof(struct fw_hdr, fw_ver), - sizeof(hdr->fw_ver), (const u8 *)&hdr->fw_ver); -out: - if (ret) - dev_err(adap->pdev_dev, "firmware download failed, error %d\n", - ret); - return ret; -} - -#define ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\ - FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_ANEG) - -/** - * t4_link_start - apply link configuration to MAC/PHY - * @phy: the PHY to setup - * @mac: the MAC to setup - * @lc: the requested link configuration - * - * Set up a port's MAC and PHY according to a desired link configuration. - * - If the PHY can auto-negotiate first decide what to advertise, then - * enable/disable auto-negotiation as desired, and reset. - * - If the PHY does not auto-negotiate just reset it. - * - If auto-negotiation is off set the MAC to the proper speed/duplex/FC, - * otherwise do it later based on the outcome of auto-negotiation. - */ -int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port, - struct link_config *lc) -{ - struct fw_port_cmd c; - unsigned int fc = 0, mdi = FW_PORT_MDI(FW_PORT_MDI_AUTO); - - lc->link_ok = 0; - if (lc->requested_fc & PAUSE_RX) - fc |= FW_PORT_CAP_FC_RX; - if (lc->requested_fc & PAUSE_TX) - fc |= FW_PORT_CAP_FC_TX; - - memset(&c, 0, sizeof(c)); - c.op_to_portid = htonl(FW_CMD_OP(FW_PORT_CMD) | FW_CMD_REQUEST | - FW_CMD_EXEC | FW_PORT_CMD_PORTID(port)); - c.action_to_len16 = htonl(FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) | - FW_LEN16(c)); - - if (!(lc->supported & FW_PORT_CAP_ANEG)) { - c.u.l1cfg.rcap = htonl((lc->supported & ADVERT_MASK) | fc); - lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); - } else if (lc->autoneg == AUTONEG_DISABLE) { - c.u.l1cfg.rcap = htonl(lc->requested_speed | fc | mdi); - lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); - } else - c.u.l1cfg.rcap = htonl(lc->advertising | fc | mdi); - - return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); -} - -/** - * t4_restart_aneg - restart autonegotiation - * @adap: the adapter - * @mbox: mbox to use for the FW command - * @port: the port id - * - * Restarts autonegotiation for the selected port. - */ -int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port) -{ - struct fw_port_cmd c; - - memset(&c, 0, sizeof(c)); - c.op_to_portid = htonl(FW_CMD_OP(FW_PORT_CMD) | FW_CMD_REQUEST | - FW_CMD_EXEC | FW_PORT_CMD_PORTID(port)); - c.action_to_len16 = htonl(FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) | - FW_LEN16(c)); - c.u.l1cfg.rcap = htonl(FW_PORT_CAP_ANEG); - return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); -} - -struct intr_info { - unsigned int mask; /* bits to check in interrupt status */ - const char *msg; /* message to print or NULL */ - short stat_idx; /* stat counter to increment or -1 */ - unsigned short fatal; /* whether the condition reported is fatal */ -}; - -/** - * t4_handle_intr_status - table driven interrupt handler - * @adapter: the adapter that generated the interrupt - * @reg: the interrupt status register to process - * @acts: table of interrupt actions - * - * A table driven interrupt handler that applies a set of masks to an - * interrupt status word and performs the corresponding actions if the - * interrupts described by the mask have occurred. The actions include - * optionally emitting a warning or alert message. The table is terminated - * by an entry specifying mask 0. Returns the number of fatal interrupt - * conditions. - */ -static int t4_handle_intr_status(struct adapter *adapter, unsigned int reg, - const struct intr_info *acts) -{ - int fatal = 0; - unsigned int mask = 0; - unsigned int status = t4_read_reg(adapter, reg); - - for ( ; acts->mask; ++acts) { - if (!(status & acts->mask)) - continue; - if (acts->fatal) { - fatal++; - dev_alert(adapter->pdev_dev, "%s (0x%x)\n", acts->msg, - status & acts->mask); - } else if (acts->msg && printk_ratelimit()) - dev_warn(adapter->pdev_dev, "%s (0x%x)\n", acts->msg, - status & acts->mask); - mask |= acts->mask; - } - status &= mask; - if (status) /* clear processed interrupts */ - t4_write_reg(adapter, reg, status); - return fatal; -} - -/* - * Interrupt handler for the PCIE module. - */ -static void pcie_intr_handler(struct adapter *adapter) -{ - static const struct intr_info sysbus_intr_info[] = { - { RNPP, "RXNP array parity error", -1, 1 }, - { RPCP, "RXPC array parity error", -1, 1 }, - { RCIP, "RXCIF array parity error", -1, 1 }, - { RCCP, "Rx completions control array parity error", -1, 1 }, - { RFTP, "RXFT array parity error", -1, 1 }, - { 0 } - }; - static const struct intr_info pcie_port_intr_info[] = { - { TPCP, "TXPC array parity error", -1, 1 }, - { TNPP, "TXNP array parity error", -1, 1 }, - { TFTP, "TXFT array parity error", -1, 1 }, - { TCAP, "TXCA array parity error", -1, 1 }, - { TCIP, "TXCIF array parity error", -1, 1 }, - { RCAP, "RXCA array parity error", -1, 1 }, - { OTDD, "outbound request TLP discarded", -1, 1 }, - { RDPE, "Rx data parity error", -1, 1 }, - { TDUE, "Tx uncorrectable data error", -1, 1 }, - { 0 } - }; - static const struct intr_info pcie_intr_info[] = { - { MSIADDRLPERR, "MSI AddrL parity error", -1, 1 }, - { MSIADDRHPERR, "MSI AddrH parity error", -1, 1 }, - { MSIDATAPERR, "MSI data parity error", -1, 1 }, - { MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 }, - { MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 }, - { MSIXDATAPERR, "MSI-X data parity error", -1, 1 }, - { MSIXDIPERR, "MSI-X DI parity error", -1, 1 }, - { PIOCPLPERR, "PCI PIO completion FIFO parity error", -1, 1 }, - { PIOREQPERR, "PCI PIO request FIFO parity error", -1, 1 }, - { TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 }, - { CCNTPERR, "PCI CMD channel count parity error", -1, 1 }, - { CREQPERR, "PCI CMD channel request parity error", -1, 1 }, - { CRSPPERR, "PCI CMD channel response parity error", -1, 1 }, - { DCNTPERR, "PCI DMA channel count parity error", -1, 1 }, - { DREQPERR, "PCI DMA channel request parity error", -1, 1 }, - { DRSPPERR, "PCI DMA channel response parity error", -1, 1 }, - { HCNTPERR, "PCI HMA channel count parity error", -1, 1 }, - { HREQPERR, "PCI HMA channel request parity error", -1, 1 }, - { HRSPPERR, "PCI HMA channel response parity error", -1, 1 }, - { CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 }, - { FIDPERR, "PCI FID parity error", -1, 1 }, - { INTXCLRPERR, "PCI INTx clear parity error", -1, 1 }, - { MATAGPERR, "PCI MA tag parity error", -1, 1 }, - { PIOTAGPERR, "PCI PIO tag parity error", -1, 1 }, - { RXCPLPERR, "PCI Rx completion parity error", -1, 1 }, - { RXWRPERR, "PCI Rx write parity error", -1, 1 }, - { RPLPERR, "PCI replay buffer parity error", -1, 1 }, - { PCIESINT, "PCI core secondary fault", -1, 1 }, - { PCIEPINT, "PCI core primary fault", -1, 1 }, - { UNXSPLCPLERR, "PCI unexpected split completion error", -1, 0 }, - { 0 } - }; - - int fat; - - fat = t4_handle_intr_status(adapter, - PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS, - sysbus_intr_info) + - t4_handle_intr_status(adapter, - PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS, - pcie_port_intr_info) + - t4_handle_intr_status(adapter, PCIE_INT_CAUSE, pcie_intr_info); - if (fat) - t4_fatal_err(adapter); -} - -/* - * TP interrupt handler. - */ -static void tp_intr_handler(struct adapter *adapter) -{ - static const struct intr_info tp_intr_info[] = { - { 0x3fffffff, "TP parity error", -1, 1 }, - { FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1 }, - { 0 } - }; - - if (t4_handle_intr_status(adapter, TP_INT_CAUSE, tp_intr_info)) - t4_fatal_err(adapter); -} - -/* - * SGE interrupt handler. - */ -static void sge_intr_handler(struct adapter *adapter) -{ - u64 v; - - static const struct intr_info sge_intr_info[] = { - { ERR_CPL_EXCEED_IQE_SIZE, - "SGE received CPL exceeding IQE size", -1, 1 }, - { ERR_INVALID_CIDX_INC, - "SGE GTS CIDX increment too large", -1, 0 }, - { ERR_CPL_OPCODE_0, "SGE received 0-length CPL", -1, 0 }, - { ERR_DROPPED_DB, "SGE doorbell dropped", -1, 0 }, - { ERR_DATA_CPL_ON_HIGH_QID1 | ERR_DATA_CPL_ON_HIGH_QID0, - "SGE IQID > 1023 received CPL for FL", -1, 0 }, - { ERR_BAD_DB_PIDX3, "SGE DBP 3 pidx increment too large", -1, - 0 }, - { ERR_BAD_DB_PIDX2, "SGE DBP 2 pidx increment too large", -1, - 0 }, - { ERR_BAD_DB_PIDX1, "SGE DBP 1 pidx increment too large", -1, - 0 }, - { ERR_BAD_DB_PIDX0, "SGE DBP 0 pidx increment too large", -1, - 0 }, - { ERR_ING_CTXT_PRIO, - "SGE too many priority ingress contexts", -1, 0 }, - { ERR_EGR_CTXT_PRIO, - "SGE too many priority egress contexts", -1, 0 }, - { INGRESS_SIZE_ERR, "SGE illegal ingress QID", -1, 0 }, - { EGRESS_SIZE_ERR, "SGE illegal egress QID", -1, 0 }, - { 0 } - }; - - v = (u64)t4_read_reg(adapter, SGE_INT_CAUSE1) | - ((u64)t4_read_reg(adapter, SGE_INT_CAUSE2) << 32); - if (v) { - dev_alert(adapter->pdev_dev, "SGE parity error (%#llx)\n", - (unsigned long long)v); - t4_write_reg(adapter, SGE_INT_CAUSE1, v); - t4_write_reg(adapter, SGE_INT_CAUSE2, v >> 32); - } - - if (t4_handle_intr_status(adapter, SGE_INT_CAUSE3, sge_intr_info) || - v != 0) - t4_fatal_err(adapter); -} - -/* - * CIM interrupt handler. - */ -static void cim_intr_handler(struct adapter *adapter) -{ - static const struct intr_info cim_intr_info[] = { - { PREFDROPINT, "CIM control register prefetch drop", -1, 1 }, - { OBQPARERR, "CIM OBQ parity error", -1, 1 }, - { IBQPARERR, "CIM IBQ parity error", -1, 1 }, - { MBUPPARERR, "CIM mailbox uP parity error", -1, 1 }, - { MBHOSTPARERR, "CIM mailbox host parity error", -1, 1 }, - { TIEQINPARERRINT, "CIM TIEQ outgoing parity error", -1, 1 }, - { TIEQOUTPARERRINT, "CIM TIEQ incoming parity error", -1, 1 }, - { 0 } - }; - static const struct intr_info cim_upintr_info[] = { - { RSVDSPACEINT, "CIM reserved space access", -1, 1 }, - { ILLTRANSINT, "CIM illegal transaction", -1, 1 }, - { ILLWRINT, "CIM illegal write", -1, 1 }, - { ILLRDINT, "CIM illegal read", -1, 1 }, - { ILLRDBEINT, "CIM illegal read BE", -1, 1 }, - { ILLWRBEINT, "CIM illegal write BE", -1, 1 }, - { SGLRDBOOTINT, "CIM single read from boot space", -1, 1 }, - { SGLWRBOOTINT, "CIM single write to boot space", -1, 1 }, - { BLKWRBOOTINT, "CIM block write to boot space", -1, 1 }, - { SGLRDFLASHINT, "CIM single read from flash space", -1, 1 }, - { SGLWRFLASHINT, "CIM single write to flash space", -1, 1 }, - { BLKWRFLASHINT, "CIM block write to flash space", -1, 1 }, - { SGLRDEEPROMINT, "CIM single EEPROM read", -1, 1 }, - { SGLWREEPROMINT, "CIM single EEPROM write", -1, 1 }, - { BLKRDEEPROMINT, "CIM block EEPROM read", -1, 1 }, - { BLKWREEPROMINT, "CIM block EEPROM write", -1, 1 }, - { SGLRDCTLINT , "CIM single read from CTL space", -1, 1 }, - { SGLWRCTLINT , "CIM single write to CTL space", -1, 1 }, - { BLKRDCTLINT , "CIM block read from CTL space", -1, 1 }, - { BLKWRCTLINT , "CIM block write to CTL space", -1, 1 }, - { SGLRDPLINT , "CIM single read from PL space", -1, 1 }, - { SGLWRPLINT , "CIM single write to PL space", -1, 1 }, - { BLKRDPLINT , "CIM block read from PL space", -1, 1 }, - { BLKWRPLINT , "CIM block write to PL space", -1, 1 }, - { REQOVRLOOKUPINT , "CIM request FIFO overwrite", -1, 1 }, - { RSPOVRLOOKUPINT , "CIM response FIFO overwrite", -1, 1 }, - { TIMEOUTINT , "CIM PIF timeout", -1, 1 }, - { TIMEOUTMAINT , "CIM PIF MA timeout", -1, 1 }, - { 0 } - }; - - int fat; - - fat = t4_handle_intr_status(adapter, CIM_HOST_INT_CAUSE, - cim_intr_info) + - t4_handle_intr_status(adapter, CIM_HOST_UPACC_INT_CAUSE, - cim_upintr_info); - if (fat) - t4_fatal_err(adapter); -} - -/* - * ULP RX interrupt handler. - */ -static void ulprx_intr_handler(struct adapter *adapter) -{ - static const struct intr_info ulprx_intr_info[] = { - { 0x1800000, "ULPRX context error", -1, 1 }, - { 0x7fffff, "ULPRX parity error", -1, 1 }, - { 0 } - }; - - if (t4_handle_intr_status(adapter, ULP_RX_INT_CAUSE, ulprx_intr_info)) - t4_fatal_err(adapter); -} - -/* - * ULP TX interrupt handler. - */ -static void ulptx_intr_handler(struct adapter *adapter) -{ - static const struct intr_info ulptx_intr_info[] = { - { PBL_BOUND_ERR_CH3, "ULPTX channel 3 PBL out of bounds", -1, - 0 }, - { PBL_BOUND_ERR_CH2, "ULPTX channel 2 PBL out of bounds", -1, - 0 }, - { PBL_BOUND_ERR_CH1, "ULPTX channel 1 PBL out of bounds", -1, - 0 }, - { PBL_BOUND_ERR_CH0, "ULPTX channel 0 PBL out of bounds", -1, - 0 }, - { 0xfffffff, "ULPTX parity error", -1, 1 }, - { 0 } - }; - - if (t4_handle_intr_status(adapter, ULP_TX_INT_CAUSE, ulptx_intr_info)) - t4_fatal_err(adapter); -} - -/* - * PM TX interrupt handler. - */ -static void pmtx_intr_handler(struct adapter *adapter) -{ - static const struct intr_info pmtx_intr_info[] = { - { PCMD_LEN_OVFL0, "PMTX channel 0 pcmd too large", -1, 1 }, - { PCMD_LEN_OVFL1, "PMTX channel 1 pcmd too large", -1, 1 }, - { PCMD_LEN_OVFL2, "PMTX channel 2 pcmd too large", -1, 1 }, - { ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1 }, - { PMTX_FRAMING_ERROR, "PMTX framing error", -1, 1 }, - { OESPI_PAR_ERROR, "PMTX oespi parity error", -1, 1 }, - { DB_OPTIONS_PAR_ERROR, "PMTX db_options parity error", -1, 1 }, - { ICSPI_PAR_ERROR, "PMTX icspi parity error", -1, 1 }, - { C_PCMD_PAR_ERROR, "PMTX c_pcmd parity error", -1, 1}, - { 0 } - }; - - if (t4_handle_intr_status(adapter, PM_TX_INT_CAUSE, pmtx_intr_info)) - t4_fatal_err(adapter); -} - -/* - * PM RX interrupt handler. - */ -static void pmrx_intr_handler(struct adapter *adapter) -{ - static const struct intr_info pmrx_intr_info[] = { - { ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1 }, - { PMRX_FRAMING_ERROR, "PMRX framing error", -1, 1 }, - { OCSPI_PAR_ERROR, "PMRX ocspi parity error", -1, 1 }, - { DB_OPTIONS_PAR_ERROR, "PMRX db_options parity error", -1, 1 }, - { IESPI_PAR_ERROR, "PMRX iespi parity error", -1, 1 }, - { E_PCMD_PAR_ERROR, "PMRX e_pcmd parity error", -1, 1}, - { 0 } - }; - - if (t4_handle_intr_status(adapter, PM_RX_INT_CAUSE, pmrx_intr_info)) - t4_fatal_err(adapter); -} - -/* - * CPL switch interrupt handler. - */ -static void cplsw_intr_handler(struct adapter *adapter) -{ - static const struct intr_info cplsw_intr_info[] = { - { CIM_OP_MAP_PERR, "CPLSW CIM op_map parity error", -1, 1 }, - { CIM_OVFL_ERROR, "CPLSW CIM overflow", -1, 1 }, - { TP_FRAMING_ERROR, "CPLSW TP framing error", -1, 1 }, - { SGE_FRAMING_ERROR, "CPLSW SGE framing error", -1, 1 }, - { CIM_FRAMING_ERROR, "CPLSW CIM framing error", -1, 1 }, - { ZERO_SWITCH_ERROR, "CPLSW no-switch error", -1, 1 }, - { 0 } - }; - - if (t4_handle_intr_status(adapter, CPL_INTR_CAUSE, cplsw_intr_info)) - t4_fatal_err(adapter); -} - -/* - * LE interrupt handler. - */ -static void le_intr_handler(struct adapter *adap) -{ - static const struct intr_info le_intr_info[] = { - { LIPMISS, "LE LIP miss", -1, 0 }, - { LIP0, "LE 0 LIP error", -1, 0 }, - { PARITYERR, "LE parity error", -1, 1 }, - { UNKNOWNCMD, "LE unknown command", -1, 1 }, - { REQQPARERR, "LE request queue parity error", -1, 1 }, - { 0 } - }; - - if (t4_handle_intr_status(adap, LE_DB_INT_CAUSE, le_intr_info)) - t4_fatal_err(adap); -} - -/* - * MPS interrupt handler. - */ -static void mps_intr_handler(struct adapter *adapter) -{ - static const struct intr_info mps_rx_intr_info[] = { - { 0xffffff, "MPS Rx parity error", -1, 1 }, - { 0 } - }; - static const struct intr_info mps_tx_intr_info[] = { - { TPFIFO, "MPS Tx TP FIFO parity error", -1, 1 }, - { NCSIFIFO, "MPS Tx NC-SI FIFO parity error", -1, 1 }, - { TXDATAFIFO, "MPS Tx data FIFO parity error", -1, 1 }, - { TXDESCFIFO, "MPS Tx desc FIFO parity error", -1, 1 }, - { BUBBLE, "MPS Tx underflow", -1, 1 }, - { SECNTERR, "MPS Tx SOP/EOP error", -1, 1 }, - { FRMERR, "MPS Tx framing error", -1, 1 }, - { 0 } - }; - static const struct intr_info mps_trc_intr_info[] = { - { FILTMEM, "MPS TRC filter parity error", -1, 1 }, - { PKTFIFO, "MPS TRC packet FIFO parity error", -1, 1 }, - { MISCPERR, "MPS TRC misc parity error", -1, 1 }, - { 0 } - }; - static const struct intr_info mps_stat_sram_intr_info[] = { - { 0x1fffff, "MPS statistics SRAM parity error", -1, 1 }, - { 0 } - }; - static const struct intr_info mps_stat_tx_intr_info[] = { - { 0xfffff, "MPS statistics Tx FIFO parity error", -1, 1 }, - { 0 } - }; - static const struct intr_info mps_stat_rx_intr_info[] = { - { 0xffffff, "MPS statistics Rx FIFO parity error", -1, 1 }, - { 0 } - }; - static const struct intr_info mps_cls_intr_info[] = { - { MATCHSRAM, "MPS match SRAM parity error", -1, 1 }, - { MATCHTCAM, "MPS match TCAM parity error", -1, 1 }, - { HASHSRAM, "MPS hash SRAM parity error", -1, 1 }, - { 0 } - }; - - int fat; - - fat = t4_handle_intr_status(adapter, MPS_RX_PERR_INT_CAUSE, - mps_rx_intr_info) + - t4_handle_intr_status(adapter, MPS_TX_INT_CAUSE, - mps_tx_intr_info) + - t4_handle_intr_status(adapter, MPS_TRC_INT_CAUSE, - mps_trc_intr_info) + - t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_SRAM, - mps_stat_sram_intr_info) + - t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_TX_FIFO, - mps_stat_tx_intr_info) + - t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_RX_FIFO, - mps_stat_rx_intr_info) + - t4_handle_intr_status(adapter, MPS_CLS_INT_CAUSE, - mps_cls_intr_info); - - t4_write_reg(adapter, MPS_INT_CAUSE, CLSINT | TRCINT | - RXINT | TXINT | STATINT); - t4_read_reg(adapter, MPS_INT_CAUSE); /* flush */ - if (fat) - t4_fatal_err(adapter); -} - -#define MEM_INT_MASK (PERR_INT_CAUSE | ECC_CE_INT_CAUSE | ECC_UE_INT_CAUSE) - -/* - * EDC/MC interrupt handler. - */ -static void mem_intr_handler(struct adapter *adapter, int idx) -{ - static const char name[3][5] = { "EDC0", "EDC1", "MC" }; - - unsigned int addr, cnt_addr, v; - - if (idx <= MEM_EDC1) { - addr = EDC_REG(EDC_INT_CAUSE, idx); - cnt_addr = EDC_REG(EDC_ECC_STATUS, idx); - } else { - addr = MC_INT_CAUSE; - cnt_addr = MC_ECC_STATUS; - } - - v = t4_read_reg(adapter, addr) & MEM_INT_MASK; - if (v & PERR_INT_CAUSE) - dev_alert(adapter->pdev_dev, "%s FIFO parity error\n", - name[idx]); - if (v & ECC_CE_INT_CAUSE) { - u32 cnt = ECC_CECNT_GET(t4_read_reg(adapter, cnt_addr)); - - t4_write_reg(adapter, cnt_addr, ECC_CECNT_MASK); - if (printk_ratelimit()) - dev_warn(adapter->pdev_dev, - "%u %s correctable ECC data error%s\n", - cnt, name[idx], cnt > 1 ? "s" : ""); - } - if (v & ECC_UE_INT_CAUSE) - dev_alert(adapter->pdev_dev, - "%s uncorrectable ECC data error\n", name[idx]); - - t4_write_reg(adapter, addr, v); - if (v & (PERR_INT_CAUSE | ECC_UE_INT_CAUSE)) - t4_fatal_err(adapter); -} - -/* - * MA interrupt handler. - */ -static void ma_intr_handler(struct adapter *adap) -{ - u32 v, status = t4_read_reg(adap, MA_INT_CAUSE); - - if (status & MEM_PERR_INT_CAUSE) - dev_alert(adap->pdev_dev, - "MA parity error, parity status %#x\n", - t4_read_reg(adap, MA_PARITY_ERROR_STATUS)); - if (status & MEM_WRAP_INT_CAUSE) { - v = t4_read_reg(adap, MA_INT_WRAP_STATUS); - dev_alert(adap->pdev_dev, "MA address wrap-around error by " - "client %u to address %#x\n", - MEM_WRAP_CLIENT_NUM_GET(v), - MEM_WRAP_ADDRESS_GET(v) << 4); - } - t4_write_reg(adap, MA_INT_CAUSE, status); - t4_fatal_err(adap); -} - -/* - * SMB interrupt handler. - */ -static void smb_intr_handler(struct adapter *adap) -{ - static const struct intr_info smb_intr_info[] = { - { MSTTXFIFOPARINT, "SMB master Tx FIFO parity error", -1, 1 }, - { MSTRXFIFOPARINT, "SMB master Rx FIFO parity error", -1, 1 }, - { SLVFIFOPARINT, "SMB slave FIFO parity error", -1, 1 }, - { 0 } - }; - - if (t4_handle_intr_status(adap, SMB_INT_CAUSE, smb_intr_info)) - t4_fatal_err(adap); -} - -/* - * NC-SI interrupt handler. - */ -static void ncsi_intr_handler(struct adapter *adap) -{ - static const struct intr_info ncsi_intr_info[] = { - { CIM_DM_PRTY_ERR, "NC-SI CIM parity error", -1, 1 }, - { MPS_DM_PRTY_ERR, "NC-SI MPS parity error", -1, 1 }, - { TXFIFO_PRTY_ERR, "NC-SI Tx FIFO parity error", -1, 1 }, - { RXFIFO_PRTY_ERR, "NC-SI Rx FIFO parity error", -1, 1 }, - { 0 } - }; - - if (t4_handle_intr_status(adap, NCSI_INT_CAUSE, ncsi_intr_info)) - t4_fatal_err(adap); -} - -/* - * XGMAC interrupt handler. - */ -static void xgmac_intr_handler(struct adapter *adap, int port) -{ - u32 v = t4_read_reg(adap, PORT_REG(port, XGMAC_PORT_INT_CAUSE)); - - v &= TXFIFO_PRTY_ERR | RXFIFO_PRTY_ERR; - if (!v) - return; - - if (v & TXFIFO_PRTY_ERR) - dev_alert(adap->pdev_dev, "XGMAC %d Tx FIFO parity error\n", - port); - if (v & RXFIFO_PRTY_ERR) - dev_alert(adap->pdev_dev, "XGMAC %d Rx FIFO parity error\n", - port); - t4_write_reg(adap, PORT_REG(port, XGMAC_PORT_INT_CAUSE), v); - t4_fatal_err(adap); -} - -/* - * PL interrupt handler. - */ -static void pl_intr_handler(struct adapter *adap) -{ - static const struct intr_info pl_intr_info[] = { - { FATALPERR, "T4 fatal parity error", -1, 1 }, - { PERRVFID, "PL VFID_MAP parity error", -1, 1 }, - { 0 } - }; - - if (t4_handle_intr_status(adap, PL_PL_INT_CAUSE, pl_intr_info)) - t4_fatal_err(adap); -} - -#define PF_INTR_MASK (PFSW) -#define GLBL_INTR_MASK (CIM | MPS | PL | PCIE | MC | EDC0 | \ - EDC1 | LE | TP | MA | PM_TX | PM_RX | ULP_RX | \ - CPL_SWITCH | SGE | ULP_TX) - -/** - * t4_slow_intr_handler - control path interrupt handler - * @adapter: the adapter - * - * T4 interrupt handler for non-data global interrupt events, e.g., errors. - * The designation 'slow' is because it involves register reads, while - * data interrupts typically don't involve any MMIOs. - */ -int t4_slow_intr_handler(struct adapter *adapter) -{ - u32 cause = t4_read_reg(adapter, PL_INT_CAUSE); - - if (!(cause & GLBL_INTR_MASK)) - return 0; - if (cause & CIM) - cim_intr_handler(adapter); - if (cause & MPS) - mps_intr_handler(adapter); - if (cause & NCSI) - ncsi_intr_handler(adapter); - if (cause & PL) - pl_intr_handler(adapter); - if (cause & SMB) - smb_intr_handler(adapter); - if (cause & XGMAC0) - xgmac_intr_handler(adapter, 0); - if (cause & XGMAC1) - xgmac_intr_handler(adapter, 1); - if (cause & XGMAC_KR0) - xgmac_intr_handler(adapter, 2); - if (cause & XGMAC_KR1) - xgmac_intr_handler(adapter, 3); - if (cause & PCIE) - pcie_intr_handler(adapter); - if (cause & MC) - mem_intr_handler(adapter, MEM_MC); - if (cause & EDC0) - mem_intr_handler(adapter, MEM_EDC0); - if (cause & EDC1) - mem_intr_handler(adapter, MEM_EDC1); - if (cause & LE) - le_intr_handler(adapter); - if (cause & TP) - tp_intr_handler(adapter); - if (cause & MA) - ma_intr_handler(adapter); - if (cause & PM_TX) - pmtx_intr_handler(adapter); - if (cause & PM_RX) - pmrx_intr_handler(adapter); - if (cause & ULP_RX) - ulprx_intr_handler(adapter); - if (cause & CPL_SWITCH) - cplsw_intr_handler(adapter); - if (cause & SGE) - sge_intr_handler(adapter); - if (cause & ULP_TX) - ulptx_intr_handler(adapter); - - /* Clear the interrupts just processed for which we are the master. */ - t4_write_reg(adapter, PL_INT_CAUSE, cause & GLBL_INTR_MASK); - (void) t4_read_reg(adapter, PL_INT_CAUSE); /* flush */ - return 1; -} - -/** - * t4_intr_enable - enable interrupts - * @adapter: the adapter whose interrupts should be enabled - * - * Enable PF-specific interrupts for the calling function and the top-level - * interrupt concentrator for global interrupts. Interrupts are already - * enabled at each module, here we just enable the roots of the interrupt - * hierarchies. - * - * Note: this function should be called only when the driver manages - * non PF-specific interrupts from the various HW modules. Only one PCI - * function at a time should be doing this. - */ -void t4_intr_enable(struct adapter *adapter) -{ - u32 pf = SOURCEPF_GET(t4_read_reg(adapter, PL_WHOAMI)); - - t4_write_reg(adapter, SGE_INT_ENABLE3, ERR_CPL_EXCEED_IQE_SIZE | - ERR_INVALID_CIDX_INC | ERR_CPL_OPCODE_0 | - ERR_DROPPED_DB | ERR_DATA_CPL_ON_HIGH_QID1 | - ERR_DATA_CPL_ON_HIGH_QID0 | ERR_BAD_DB_PIDX3 | - ERR_BAD_DB_PIDX2 | ERR_BAD_DB_PIDX1 | - ERR_BAD_DB_PIDX0 | ERR_ING_CTXT_PRIO | - ERR_EGR_CTXT_PRIO | INGRESS_SIZE_ERR | - EGRESS_SIZE_ERR); - t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE), PF_INTR_MASK); - t4_set_reg_field(adapter, PL_INT_MAP0, 0, 1 << pf); -} - -/** - * t4_intr_disable - disable interrupts - * @adapter: the adapter whose interrupts should be disabled - * - * Disable interrupts. We only disable the top-level interrupt - * concentrators. The caller must be a PCI function managing global - * interrupts. - */ -void t4_intr_disable(struct adapter *adapter) -{ - u32 pf = SOURCEPF_GET(t4_read_reg(adapter, PL_WHOAMI)); - - t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE), 0); - t4_set_reg_field(adapter, PL_INT_MAP0, 1 << pf, 0); -} - -/** - * hash_mac_addr - return the hash value of a MAC address - * @addr: the 48-bit Ethernet MAC address - * - * Hashes a MAC address according to the hash function used by HW inexact - * (hash) address matching. - */ -static int hash_mac_addr(const u8 *addr) -{ - u32 a = ((u32)addr[0] << 16) | ((u32)addr[1] << 8) | addr[2]; - u32 b = ((u32)addr[3] << 16) | ((u32)addr[4] << 8) | addr[5]; - a ^= b; - a ^= (a >> 12); - a ^= (a >> 6); - return a & 0x3f; -} - -/** - * t4_config_rss_range - configure a portion of the RSS mapping table - * @adapter: the adapter - * @mbox: mbox to use for the FW command - * @viid: virtual interface whose RSS subtable is to be written - * @start: start entry in the table to write - * @n: how many table entries to write - * @rspq: values for the response queue lookup table - * @nrspq: number of values in @rspq - * - * Programs the selected part of the VI's RSS mapping table with the - * provided values. If @nrspq < @n the supplied values are used repeatedly - * until the full table range is populated. - * - * The caller must ensure the values in @rspq are in the range allowed for - * @viid. - */ -int t4_config_rss_range(struct adapter *adapter, int mbox, unsigned int viid, - int start, int n, const u16 *rspq, unsigned int nrspq) -{ - int ret; - const u16 *rsp = rspq; - const u16 *rsp_end = rspq + nrspq; - struct fw_rss_ind_tbl_cmd cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.op_to_viid = htonl(FW_CMD_OP(FW_RSS_IND_TBL_CMD) | - FW_CMD_REQUEST | FW_CMD_WRITE | - FW_RSS_IND_TBL_CMD_VIID(viid)); - cmd.retval_len16 = htonl(FW_LEN16(cmd)); - - /* each fw_rss_ind_tbl_cmd takes up to 32 entries */ - while (n > 0) { - int nq = min(n, 32); - __be32 *qp = &cmd.iq0_to_iq2; - - cmd.niqid = htons(nq); - cmd.startidx = htons(start); - - start += nq; - n -= nq; - - while (nq > 0) { - unsigned int v; - - v = FW_RSS_IND_TBL_CMD_IQ0(*rsp); - if (++rsp >= rsp_end) - rsp = rspq; - v |= FW_RSS_IND_TBL_CMD_IQ1(*rsp); - if (++rsp >= rsp_end) - rsp = rspq; - v |= FW_RSS_IND_TBL_CMD_IQ2(*rsp); - if (++rsp >= rsp_end) - rsp = rspq; - - *qp++ = htonl(v); - nq -= 3; - } - - ret = t4_wr_mbox(adapter, mbox, &cmd, sizeof(cmd), NULL); - if (ret) - return ret; - } - return 0; -} - -/** - * t4_config_glbl_rss - configure the global RSS mode - * @adapter: the adapter - * @mbox: mbox to use for the FW command - * @mode: global RSS mode - * @flags: mode-specific flags - * - * Sets the global RSS mode. - */ -int t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode, - unsigned int flags) -{ - struct fw_rss_glb_config_cmd c; - - memset(&c, 0, sizeof(c)); - c.op_to_write = htonl(FW_CMD_OP(FW_RSS_GLB_CONFIG_CMD) | - FW_CMD_REQUEST | FW_CMD_WRITE); - c.retval_len16 = htonl(FW_LEN16(c)); - if (mode == FW_RSS_GLB_CONFIG_CMD_MODE_MANUAL) { - c.u.manual.mode_pkd = htonl(FW_RSS_GLB_CONFIG_CMD_MODE(mode)); - } else if (mode == FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL) { - c.u.basicvirtual.mode_pkd = - htonl(FW_RSS_GLB_CONFIG_CMD_MODE(mode)); - c.u.basicvirtual.synmapen_to_hashtoeplitz = htonl(flags); - } else - return -EINVAL; - return t4_wr_mbox(adapter, mbox, &c, sizeof(c), NULL); -} - -/** - * t4_tp_get_tcp_stats - read TP's TCP MIB counters - * @adap: the adapter - * @v4: holds the TCP/IP counter values - * @v6: holds the TCP/IPv6 counter values - * - * Returns the values of TP's TCP/IP and TCP/IPv6 MIB counters. - * Either @v4 or @v6 may be %NULL to skip the corresponding stats. - */ -void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4, - struct tp_tcp_stats *v6) -{ - u32 val[TP_MIB_TCP_RXT_SEG_LO - TP_MIB_TCP_OUT_RST + 1]; - -#define STAT_IDX(x) ((TP_MIB_TCP_##x) - TP_MIB_TCP_OUT_RST) -#define STAT(x) val[STAT_IDX(x)] -#define STAT64(x) (((u64)STAT(x##_HI) << 32) | STAT(x##_LO)) - - if (v4) { - t4_read_indirect(adap, TP_MIB_INDEX, TP_MIB_DATA, val, - ARRAY_SIZE(val), TP_MIB_TCP_OUT_RST); - v4->tcpOutRsts = STAT(OUT_RST); - v4->tcpInSegs = STAT64(IN_SEG); - v4->tcpOutSegs = STAT64(OUT_SEG); - v4->tcpRetransSegs = STAT64(RXT_SEG); - } - if (v6) { - t4_read_indirect(adap, TP_MIB_INDEX, TP_MIB_DATA, val, - ARRAY_SIZE(val), TP_MIB_TCP_V6OUT_RST); - v6->tcpOutRsts = STAT(OUT_RST); - v6->tcpInSegs = STAT64(IN_SEG); - v6->tcpOutSegs = STAT64(OUT_SEG); - v6->tcpRetransSegs = STAT64(RXT_SEG); - } -#undef STAT64 -#undef STAT -#undef STAT_IDX -} - -/** - * t4_read_mtu_tbl - returns the values in the HW path MTU table - * @adap: the adapter - * @mtus: where to store the MTU values - * @mtu_log: where to store the MTU base-2 log (may be %NULL) - * - * Reads the HW path MTU table. - */ -void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log) -{ - u32 v; - int i; - - for (i = 0; i < NMTUS; ++i) { - t4_write_reg(adap, TP_MTU_TABLE, - MTUINDEX(0xff) | MTUVALUE(i)); - v = t4_read_reg(adap, TP_MTU_TABLE); - mtus[i] = MTUVALUE_GET(v); - if (mtu_log) - mtu_log[i] = MTUWIDTH_GET(v); - } -} - -/** - * init_cong_ctrl - initialize congestion control parameters - * @a: the alpha values for congestion control - * @b: the beta values for congestion control - * - * Initialize the congestion control parameters. - */ -static void __devinit init_cong_ctrl(unsigned short *a, unsigned short *b) -{ - a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1; - a[9] = 2; - a[10] = 3; - a[11] = 4; - a[12] = 5; - a[13] = 6; - a[14] = 7; - a[15] = 8; - a[16] = 9; - a[17] = 10; - a[18] = 14; - a[19] = 17; - a[20] = 21; - a[21] = 25; - a[22] = 30; - a[23] = 35; - a[24] = 45; - a[25] = 60; - a[26] = 80; - a[27] = 100; - a[28] = 200; - a[29] = 300; - a[30] = 400; - a[31] = 500; - - b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0; - b[9] = b[10] = 1; - b[11] = b[12] = 2; - b[13] = b[14] = b[15] = b[16] = 3; - b[17] = b[18] = b[19] = b[20] = b[21] = 4; - b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5; - b[28] = b[29] = 6; - b[30] = b[31] = 7; -} - -/* The minimum additive increment value for the congestion control table */ -#define CC_MIN_INCR 2U - -/** - * t4_load_mtus - write the MTU and congestion control HW tables - * @adap: the adapter - * @mtus: the values for the MTU table - * @alpha: the values for the congestion control alpha parameter - * @beta: the values for the congestion control beta parameter - * - * Write the HW MTU table with the supplied MTUs and the high-speed - * congestion control table with the supplied alpha, beta, and MTUs. - * We write the two tables together because the additive increments - * depend on the MTUs. - */ -void t4_load_mtus(struct adapter *adap, const unsigned short *mtus, - const unsigned short *alpha, const unsigned short *beta) -{ - static const unsigned int avg_pkts[NCCTRL_WIN] = { - 2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640, - 896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480, - 28672, 40960, 57344, 81920, 114688, 163840, 229376 - }; - - unsigned int i, w; - - for (i = 0; i < NMTUS; ++i) { - unsigned int mtu = mtus[i]; - unsigned int log2 = fls(mtu); - - if (!(mtu & ((1 << log2) >> 2))) /* round */ - log2--; - t4_write_reg(adap, TP_MTU_TABLE, MTUINDEX(i) | - MTUWIDTH(log2) | MTUVALUE(mtu)); - - for (w = 0; w < NCCTRL_WIN; ++w) { - unsigned int inc; - - inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w], - CC_MIN_INCR); - - t4_write_reg(adap, TP_CCTRL_TABLE, (i << 21) | - (w << 16) | (beta[w] << 13) | inc); - } - } -} - -/** - * get_mps_bg_map - return the buffer groups associated with a port - * @adap: the adapter - * @idx: the port index - * - * Returns a bitmap indicating which MPS buffer groups are associated - * with the given port. Bit i is set if buffer group i is used by the - * port. - */ -static unsigned int get_mps_bg_map(struct adapter *adap, int idx) -{ - u32 n = NUMPORTS_GET(t4_read_reg(adap, MPS_CMN_CTL)); - - if (n == 0) - return idx == 0 ? 0xf : 0; - if (n == 1) - return idx < 2 ? (3 << (2 * idx)) : 0; - return 1 << idx; -} - -/** - * t4_get_port_stats - collect port statistics - * @adap: the adapter - * @idx: the port index - * @p: the stats structure to fill - * - * Collect statistics related to the given port from HW. - */ -void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p) -{ - u32 bgmap = get_mps_bg_map(adap, idx); - -#define GET_STAT(name) \ - t4_read_reg64(adap, PORT_REG(idx, MPS_PORT_STAT_##name##_L)) -#define GET_STAT_COM(name) t4_read_reg64(adap, MPS_STAT_##name##_L) - - p->tx_octets = GET_STAT(TX_PORT_BYTES); - p->tx_frames = GET_STAT(TX_PORT_FRAMES); - p->tx_bcast_frames = GET_STAT(TX_PORT_BCAST); - p->tx_mcast_frames = GET_STAT(TX_PORT_MCAST); - p->tx_ucast_frames = GET_STAT(TX_PORT_UCAST); - p->tx_error_frames = GET_STAT(TX_PORT_ERROR); - p->tx_frames_64 = GET_STAT(TX_PORT_64B); - p->tx_frames_65_127 = GET_STAT(TX_PORT_65B_127B); - p->tx_frames_128_255 = GET_STAT(TX_PORT_128B_255B); - p->tx_frames_256_511 = GET_STAT(TX_PORT_256B_511B); - p->tx_frames_512_1023 = GET_STAT(TX_PORT_512B_1023B); - p->tx_frames_1024_1518 = GET_STAT(TX_PORT_1024B_1518B); - p->tx_frames_1519_max = GET_STAT(TX_PORT_1519B_MAX); - p->tx_drop = GET_STAT(TX_PORT_DROP); - p->tx_pause = GET_STAT(TX_PORT_PAUSE); - p->tx_ppp0 = GET_STAT(TX_PORT_PPP0); - p->tx_ppp1 = GET_STAT(TX_PORT_PPP1); - p->tx_ppp2 = GET_STAT(TX_PORT_PPP2); - p->tx_ppp3 = GET_STAT(TX_PORT_PPP3); - p->tx_ppp4 = GET_STAT(TX_PORT_PPP4); - p->tx_ppp5 = GET_STAT(TX_PORT_PPP5); - p->tx_ppp6 = GET_STAT(TX_PORT_PPP6); - p->tx_ppp7 = GET_STAT(TX_PORT_PPP7); - - p->rx_octets = GET_STAT(RX_PORT_BYTES); - p->rx_frames = GET_STAT(RX_PORT_FRAMES); - p->rx_bcast_frames = GET_STAT(RX_PORT_BCAST); - p->rx_mcast_frames = GET_STAT(RX_PORT_MCAST); - p->rx_ucast_frames = GET_STAT(RX_PORT_UCAST); - p->rx_too_long = GET_STAT(RX_PORT_MTU_ERROR); - p->rx_jabber = GET_STAT(RX_PORT_MTU_CRC_ERROR); - p->rx_fcs_err = GET_STAT(RX_PORT_CRC_ERROR); - p->rx_len_err = GET_STAT(RX_PORT_LEN_ERROR); - p->rx_symbol_err = GET_STAT(RX_PORT_SYM_ERROR); - p->rx_runt = GET_STAT(RX_PORT_LESS_64B); - p->rx_frames_64 = GET_STAT(RX_PORT_64B); - p->rx_frames_65_127 = GET_STAT(RX_PORT_65B_127B); - p->rx_frames_128_255 = GET_STAT(RX_PORT_128B_255B); - p->rx_frames_256_511 = GET_STAT(RX_PORT_256B_511B); - p->rx_frames_512_1023 = GET_STAT(RX_PORT_512B_1023B); - p->rx_frames_1024_1518 = GET_STAT(RX_PORT_1024B_1518B); - p->rx_frames_1519_max = GET_STAT(RX_PORT_1519B_MAX); - p->rx_pause = GET_STAT(RX_PORT_PAUSE); - p->rx_ppp0 = GET_STAT(RX_PORT_PPP0); - p->rx_ppp1 = GET_STAT(RX_PORT_PPP1); - p->rx_ppp2 = GET_STAT(RX_PORT_PPP2); - p->rx_ppp3 = GET_STAT(RX_PORT_PPP3); - p->rx_ppp4 = GET_STAT(RX_PORT_PPP4); - p->rx_ppp5 = GET_STAT(RX_PORT_PPP5); - p->rx_ppp6 = GET_STAT(RX_PORT_PPP6); - p->rx_ppp7 = GET_STAT(RX_PORT_PPP7); - - p->rx_ovflow0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_MAC_DROP_FRAME) : 0; - p->rx_ovflow1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_MAC_DROP_FRAME) : 0; - p->rx_ovflow2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_MAC_DROP_FRAME) : 0; - p->rx_ovflow3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_MAC_DROP_FRAME) : 0; - p->rx_trunc0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_MAC_TRUNC_FRAME) : 0; - p->rx_trunc1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_MAC_TRUNC_FRAME) : 0; - p->rx_trunc2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_MAC_TRUNC_FRAME) : 0; - p->rx_trunc3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_MAC_TRUNC_FRAME) : 0; - -#undef GET_STAT -#undef GET_STAT_COM -} - -/** - * t4_wol_magic_enable - enable/disable magic packet WoL - * @adap: the adapter - * @port: the physical port index - * @addr: MAC address expected in magic packets, %NULL to disable - * - * Enables/disables magic packet wake-on-LAN for the selected port. - */ -void t4_wol_magic_enable(struct adapter *adap, unsigned int port, - const u8 *addr) -{ - if (addr) { - t4_write_reg(adap, PORT_REG(port, XGMAC_PORT_MAGIC_MACID_LO), - (addr[2] << 24) | (addr[3] << 16) | - (addr[4] << 8) | addr[5]); - t4_write_reg(adap, PORT_REG(port, XGMAC_PORT_MAGIC_MACID_HI), - (addr[0] << 8) | addr[1]); - } - t4_set_reg_field(adap, PORT_REG(port, XGMAC_PORT_CFG2), MAGICEN, - addr ? MAGICEN : 0); -} - -/** - * t4_wol_pat_enable - enable/disable pattern-based WoL - * @adap: the adapter - * @port: the physical port index - * @map: bitmap of which HW pattern filters to set - * @mask0: byte mask for bytes 0-63 of a packet - * @mask1: byte mask for bytes 64-127 of a packet - * @crc: Ethernet CRC for selected bytes - * @enable: enable/disable switch - * - * Sets the pattern filters indicated in @map to mask out the bytes - * specified in @mask0/@mask1 in received packets and compare the CRC of - * the resulting packet against @crc. If @enable is %true pattern-based - * WoL is enabled, otherwise disabled. - */ -int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map, - u64 mask0, u64 mask1, unsigned int crc, bool enable) -{ - int i; - - if (!enable) { - t4_set_reg_field(adap, PORT_REG(port, XGMAC_PORT_CFG2), - PATEN, 0); - return 0; - } - if (map > 0xff) - return -EINVAL; - -#define EPIO_REG(name) PORT_REG(port, XGMAC_PORT_EPIO_##name) - - t4_write_reg(adap, EPIO_REG(DATA1), mask0 >> 32); - t4_write_reg(adap, EPIO_REG(DATA2), mask1); - t4_write_reg(adap, EPIO_REG(DATA3), mask1 >> 32); - - for (i = 0; i < NWOL_PAT; i++, map >>= 1) { - if (!(map & 1)) - continue; - - /* write byte masks */ - t4_write_reg(adap, EPIO_REG(DATA0), mask0); - t4_write_reg(adap, EPIO_REG(OP), ADDRESS(i) | EPIOWR); - t4_read_reg(adap, EPIO_REG(OP)); /* flush */ - if (t4_read_reg(adap, EPIO_REG(OP)) & BUSY) - return -ETIMEDOUT; - - /* write CRC */ - t4_write_reg(adap, EPIO_REG(DATA0), crc); - t4_write_reg(adap, EPIO_REG(OP), ADDRESS(i + 32) | EPIOWR); - t4_read_reg(adap, EPIO_REG(OP)); /* flush */ - if (t4_read_reg(adap, EPIO_REG(OP)) & BUSY) - return -ETIMEDOUT; - } -#undef EPIO_REG - - t4_set_reg_field(adap, PORT_REG(port, XGMAC_PORT_CFG2), 0, PATEN); - return 0; -} - -#define INIT_CMD(var, cmd, rd_wr) do { \ - (var).op_to_write = htonl(FW_CMD_OP(FW_##cmd##_CMD) | \ - FW_CMD_REQUEST | FW_CMD_##rd_wr); \ - (var).retval_len16 = htonl(FW_LEN16(var)); \ -} while (0) - -/** - * t4_mdio_rd - read a PHY register through MDIO - * @adap: the adapter - * @mbox: mailbox to use for the FW command - * @phy_addr: the PHY address - * @mmd: the PHY MMD to access (0 for clause 22 PHYs) - * @reg: the register to read - * @valp: where to store the value - * - * Issues a FW command through the given mailbox to read a PHY register. - */ -int t4_mdio_rd(struct adapter *adap, unsigned int mbox, unsigned int phy_addr, - unsigned int mmd, unsigned int reg, u16 *valp) -{ - int ret; - struct fw_ldst_cmd c; - - memset(&c, 0, sizeof(c)); - c.op_to_addrspace = htonl(FW_CMD_OP(FW_LDST_CMD) | FW_CMD_REQUEST | - FW_CMD_READ | FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO)); - c.cycles_to_len16 = htonl(FW_LEN16(c)); - c.u.mdio.paddr_mmd = htons(FW_LDST_CMD_PADDR(phy_addr) | - FW_LDST_CMD_MMD(mmd)); - c.u.mdio.raddr = htons(reg); - - ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); - if (ret == 0) - *valp = ntohs(c.u.mdio.rval); - return ret; -} - -/** - * t4_mdio_wr - write a PHY register through MDIO - * @adap: the adapter - * @mbox: mailbox to use for the FW command - * @phy_addr: the PHY address - * @mmd: the PHY MMD to access (0 for clause 22 PHYs) - * @reg: the register to write - * @valp: value to write - * - * Issues a FW command through the given mailbox to write a PHY register. - */ -int t4_mdio_wr(struct adapter *adap, unsigned int mbox, unsigned int phy_addr, - unsigned int mmd, unsigned int reg, u16 val) -{ - struct fw_ldst_cmd c; - - memset(&c, 0, sizeof(c)); - c.op_to_addrspace = htonl(FW_CMD_OP(FW_LDST_CMD) | FW_CMD_REQUEST | - FW_CMD_WRITE | FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO)); - c.cycles_to_len16 = htonl(FW_LEN16(c)); - c.u.mdio.paddr_mmd = htons(FW_LDST_CMD_PADDR(phy_addr) | - FW_LDST_CMD_MMD(mmd)); - c.u.mdio.raddr = htons(reg); - c.u.mdio.rval = htons(val); - - return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); -} - -/** - * t4_fw_hello - establish communication with FW - * @adap: the adapter - * @mbox: mailbox to use for the FW command - * @evt_mbox: mailbox to receive async FW events - * @master: specifies the caller's willingness to be the device master - * @state: returns the current device state - * - * Issues a command to establish communication with FW. - */ -int t4_fw_hello(struct adapter *adap, unsigned int mbox, unsigned int evt_mbox, - enum dev_master master, enum dev_state *state) -{ - int ret; - struct fw_hello_cmd c; - - INIT_CMD(c, HELLO, WRITE); - c.err_to_mbasyncnot = htonl( - FW_HELLO_CMD_MASTERDIS(master == MASTER_CANT) | - FW_HELLO_CMD_MASTERFORCE(master == MASTER_MUST) | - FW_HELLO_CMD_MBMASTER(master == MASTER_MUST ? mbox : 0xff) | - FW_HELLO_CMD_MBASYNCNOT(evt_mbox)); - - ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); - if (ret == 0 && state) { - u32 v = ntohl(c.err_to_mbasyncnot); - if (v & FW_HELLO_CMD_INIT) - *state = DEV_STATE_INIT; - else if (v & FW_HELLO_CMD_ERR) - *state = DEV_STATE_ERR; - else - *state = DEV_STATE_UNINIT; - } - return ret; -} - -/** - * t4_fw_bye - end communication with FW - * @adap: the adapter - * @mbox: mailbox to use for the FW command - * - * Issues a command to terminate communication with FW. - */ -int t4_fw_bye(struct adapter *adap, unsigned int mbox) -{ - struct fw_bye_cmd c; - - INIT_CMD(c, BYE, WRITE); - return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); -} - -/** - * t4_init_cmd - ask FW to initialize the device - * @adap: the adapter - * @mbox: mailbox to use for the FW command - * - * Issues a command to FW to partially initialize the device. This - * performs initialization that generally doesn't depend on user input. - */ -int t4_early_init(struct adapter *adap, unsigned int mbox) -{ - struct fw_initialize_cmd c; - - INIT_CMD(c, INITIALIZE, WRITE); - return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); -} - -/** - * t4_fw_reset - issue a reset to FW - * @adap: the adapter - * @mbox: mailbox to use for the FW command - * @reset: specifies the type of reset to perform - * - * Issues a reset command of the specified type to FW. - */ -int t4_fw_reset(struct adapter *adap, unsigned int mbox, int reset) -{ - struct fw_reset_cmd c; - - INIT_CMD(c, RESET, WRITE); - c.val = htonl(reset); - return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); -} - -/** - * t4_query_params - query FW or device parameters - * @adap: the adapter - * @mbox: mailbox to use for the FW command - * @pf: the PF - * @vf: the VF - * @nparams: the number of parameters - * @params: the parameter names - * @val: the parameter values - * - * Reads the value of FW or device parameters. Up to 7 parameters can be - * queried at once. - */ -int t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf, - unsigned int vf, unsigned int nparams, const u32 *params, - u32 *val) -{ - int i, ret; - struct fw_params_cmd c; - __be32 *p = &c.param[0].mnem; - - if (nparams > 7) - return -EINVAL; - - memset(&c, 0, sizeof(c)); - c.op_to_vfn = htonl(FW_CMD_OP(FW_PARAMS_CMD) | FW_CMD_REQUEST | - FW_CMD_READ | FW_PARAMS_CMD_PFN(pf) | - FW_PARAMS_CMD_VFN(vf)); - c.retval_len16 = htonl(FW_LEN16(c)); - for (i = 0; i < nparams; i++, p += 2) - *p = htonl(*params++); - - ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); - if (ret == 0) - for (i = 0, p = &c.param[0].val; i < nparams; i++, p += 2) - *val++ = ntohl(*p); - return ret; -} - -/** - * t4_set_params - sets FW or device parameters - * @adap: the adapter - * @mbox: mailbox to use for the FW command - * @pf: the PF - * @vf: the VF - * @nparams: the number of parameters - * @params: the parameter names - * @val: the parameter values - * - * Sets the value of FW or device parameters. Up to 7 parameters can be - * specified at once. - */ -int t4_set_params(struct adapter *adap, unsigned int mbox, unsigned int pf, - unsigned int vf, unsigned int nparams, const u32 *params, - const u32 *val) -{ - struct fw_params_cmd c; - __be32 *p = &c.param[0].mnem; - - if (nparams > 7) - return -EINVAL; - - memset(&c, 0, sizeof(c)); - c.op_to_vfn = htonl(FW_CMD_OP(FW_PARAMS_CMD) | FW_CMD_REQUEST | - FW_CMD_WRITE | FW_PARAMS_CMD_PFN(pf) | - FW_PARAMS_CMD_VFN(vf)); - c.retval_len16 = htonl(FW_LEN16(c)); - while (nparams--) { - *p++ = htonl(*params++); - *p++ = htonl(*val++); - } - - return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); -} - -/** - * t4_cfg_pfvf - configure PF/VF resource limits - * @adap: the adapter - * @mbox: mailbox to use for the FW command - * @pf: the PF being configured - * @vf: the VF being configured - * @txq: the max number of egress queues - * @txq_eth_ctrl: the max number of egress Ethernet or control queues - * @rxqi: the max number of interrupt-capable ingress queues - * @rxq: the max number of interruptless ingress queues - * @tc: the PCI traffic class - * @vi: the max number of virtual interfaces - * @cmask: the channel access rights mask for the PF/VF - * @pmask: the port access rights mask for the PF/VF - * @nexact: the maximum number of exact MPS filters - * @rcaps: read capabilities - * @wxcaps: write/execute capabilities - * - * Configures resource limits and capabilities for a physical or virtual - * function. - */ -int t4_cfg_pfvf(struct adapter *adap, unsigned int mbox, unsigned int pf, - unsigned int vf, unsigned int txq, unsigned int txq_eth_ctrl, - unsigned int rxqi, unsigned int rxq, unsigned int tc, - unsigned int vi, unsigned int cmask, unsigned int pmask, - unsigned int nexact, unsigned int rcaps, unsigned int wxcaps) -{ - struct fw_pfvf_cmd c; - - memset(&c, 0, sizeof(c)); - c.op_to_vfn = htonl(FW_CMD_OP(FW_PFVF_CMD) | FW_CMD_REQUEST | - FW_CMD_WRITE | FW_PFVF_CMD_PFN(pf) | - FW_PFVF_CMD_VFN(vf)); - c.retval_len16 = htonl(FW_LEN16(c)); - c.niqflint_niq = htonl(FW_PFVF_CMD_NIQFLINT(rxqi) | - FW_PFVF_CMD_NIQ(rxq)); - c.type_to_neq = htonl(FW_PFVF_CMD_CMASK(cmask) | - FW_PFVF_CMD_PMASK(pmask) | - FW_PFVF_CMD_NEQ(txq)); - c.tc_to_nexactf = htonl(FW_PFVF_CMD_TC(tc) | FW_PFVF_CMD_NVI(vi) | - FW_PFVF_CMD_NEXACTF(nexact)); - c.r_caps_to_nethctrl = htonl(FW_PFVF_CMD_R_CAPS(rcaps) | - FW_PFVF_CMD_WX_CAPS(wxcaps) | - FW_PFVF_CMD_NETHCTRL(txq_eth_ctrl)); - return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); -} - -/** - * t4_alloc_vi - allocate a virtual interface - * @adap: the adapter - * @mbox: mailbox to use for the FW command - * @port: physical port associated with the VI - * @pf: the PF owning the VI - * @vf: the VF owning the VI - * @nmac: number of MAC addresses needed (1 to 5) - * @mac: the MAC addresses of the VI - * @rss_size: size of RSS table slice associated with this VI - * - * Allocates a virtual interface for the given physical port. If @mac is - * not %NULL it contains the MAC addresses of the VI as assigned by FW. - * @mac should be large enough to hold @nmac Ethernet addresses, they are - * stored consecutively so the space needed is @nmac * 6 bytes. - * Returns a negative error number or the non-negative VI id. - */ -int t4_alloc_vi(struct adapter *adap, unsigned int mbox, unsigned int port, - unsigned int pf, unsigned int vf, unsigned int nmac, u8 *mac, - unsigned int *rss_size) -{ - int ret; - struct fw_vi_cmd c; - - memset(&c, 0, sizeof(c)); - c.op_to_vfn = htonl(FW_CMD_OP(FW_VI_CMD) | FW_CMD_REQUEST | - FW_CMD_WRITE | FW_CMD_EXEC | - FW_VI_CMD_PFN(pf) | FW_VI_CMD_VFN(vf)); - c.alloc_to_len16 = htonl(FW_VI_CMD_ALLOC | FW_LEN16(c)); - c.portid_pkd = FW_VI_CMD_PORTID(port); - c.nmac = nmac - 1; - - ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); - if (ret) - return ret; - - if (mac) { - memcpy(mac, c.mac, sizeof(c.mac)); - switch (nmac) { - case 5: - memcpy(mac + 24, c.nmac3, sizeof(c.nmac3)); - case 4: - memcpy(mac + 18, c.nmac2, sizeof(c.nmac2)); - case 3: - memcpy(mac + 12, c.nmac1, sizeof(c.nmac1)); - case 2: - memcpy(mac + 6, c.nmac0, sizeof(c.nmac0)); - } - } - if (rss_size) - *rss_size = FW_VI_CMD_RSSSIZE_GET(ntohs(c.rsssize_pkd)); - return FW_VI_CMD_VIID_GET(ntohs(c.type_viid)); -} - -/** - * t4_set_rxmode - set Rx properties of a virtual interface - * @adap: the adapter - * @mbox: mailbox to use for the FW command - * @viid: the VI id - * @mtu: the new MTU or -1 - * @promisc: 1 to enable promiscuous mode, 0 to disable it, -1 no change - * @all_multi: 1 to enable all-multi mode, 0 to disable it, -1 no change - * @bcast: 1 to enable broadcast Rx, 0 to disable it, -1 no change - * @vlanex: 1 to enable HW VLAN extraction, 0 to disable it, -1 no change - * @sleep_ok: if true we may sleep while awaiting command completion - * - * Sets Rx properties of a virtual interface. - */ -int t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid, - int mtu, int promisc, int all_multi, int bcast, int vlanex, - bool sleep_ok) -{ - struct fw_vi_rxmode_cmd c; - - /* convert to FW values */ - if (mtu < 0) - mtu = FW_RXMODE_MTU_NO_CHG; - if (promisc < 0) - promisc = FW_VI_RXMODE_CMD_PROMISCEN_MASK; - if (all_multi < 0) - all_multi = FW_VI_RXMODE_CMD_ALLMULTIEN_MASK; - if (bcast < 0) - bcast = FW_VI_RXMODE_CMD_BROADCASTEN_MASK; - if (vlanex < 0) - vlanex = FW_VI_RXMODE_CMD_VLANEXEN_MASK; - - memset(&c, 0, sizeof(c)); - c.op_to_viid = htonl(FW_CMD_OP(FW_VI_RXMODE_CMD) | FW_CMD_REQUEST | - FW_CMD_WRITE | FW_VI_RXMODE_CMD_VIID(viid)); - c.retval_len16 = htonl(FW_LEN16(c)); - c.mtu_to_vlanexen = htonl(FW_VI_RXMODE_CMD_MTU(mtu) | - FW_VI_RXMODE_CMD_PROMISCEN(promisc) | - FW_VI_RXMODE_CMD_ALLMULTIEN(all_multi) | - FW_VI_RXMODE_CMD_BROADCASTEN(bcast) | - FW_VI_RXMODE_CMD_VLANEXEN(vlanex)); - return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok); -} - -/** - * t4_alloc_mac_filt - allocates exact-match filters for MAC addresses - * @adap: the adapter - * @mbox: mailbox to use for the FW command - * @viid: the VI id - * @free: if true any existing filters for this VI id are first removed - * @naddr: the number of MAC addresses to allocate filters for (up to 7) - * @addr: the MAC address(es) - * @idx: where to store the index of each allocated filter - * @hash: pointer to hash address filter bitmap - * @sleep_ok: call is allowed to sleep - * - * Allocates an exact-match filter for each of the supplied addresses and - * sets it to the corresponding address. If @idx is not %NULL it should - * have at least @naddr entries, each of which will be set to the index of - * the filter allocated for the corresponding MAC address. If a filter - * could not be allocated for an address its index is set to 0xffff. - * If @hash is not %NULL addresses that fail to allocate an exact filter - * are hashed and update the hash filter bitmap pointed at by @hash. - * - * Returns a negative error number or the number of filters allocated. - */ -int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox, - unsigned int viid, bool free, unsigned int naddr, - const u8 **addr, u16 *idx, u64 *hash, bool sleep_ok) -{ - int i, ret; - struct fw_vi_mac_cmd c; - struct fw_vi_mac_exact *p; - - if (naddr > 7) - return -EINVAL; - - memset(&c, 0, sizeof(c)); - c.op_to_viid = htonl(FW_CMD_OP(FW_VI_MAC_CMD) | FW_CMD_REQUEST | - FW_CMD_WRITE | (free ? FW_CMD_EXEC : 0) | - FW_VI_MAC_CMD_VIID(viid)); - c.freemacs_to_len16 = htonl(FW_VI_MAC_CMD_FREEMACS(free) | - FW_CMD_LEN16((naddr + 2) / 2)); - - for (i = 0, p = c.u.exact; i < naddr; i++, p++) { - p->valid_to_idx = htons(FW_VI_MAC_CMD_VALID | - FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC)); - memcpy(p->macaddr, addr[i], sizeof(p->macaddr)); - } - - ret = t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), &c, sleep_ok); - if (ret) - return ret; - - for (i = 0, p = c.u.exact; i < naddr; i++, p++) { - u16 index = FW_VI_MAC_CMD_IDX_GET(ntohs(p->valid_to_idx)); - - if (idx) - idx[i] = index >= NEXACT_MAC ? 0xffff : index; - if (index < NEXACT_MAC) - ret++; - else if (hash) - *hash |= (1ULL << hash_mac_addr(addr[i])); - } - return ret; -} - -/** - * t4_change_mac - modifies the exact-match filter for a MAC address - * @adap: the adapter - * @mbox: mailbox to use for the FW command - * @viid: the VI id - * @idx: index of existing filter for old value of MAC address, or -1 - * @addr: the new MAC address value - * @persist: whether a new MAC allocation should be persistent - * @add_smt: if true also add the address to the HW SMT - * - * Modifies an exact-match filter and sets it to the new MAC address. - * Note that in general it is not possible to modify the value of a given - * filter so the generic way to modify an address filter is to free the one - * being used by the old address value and allocate a new filter for the - * new address value. @idx can be -1 if the address is a new addition. - * - * Returns a negative error number or the index of the filter with the new - * MAC value. - */ -int t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid, - int idx, const u8 *addr, bool persist, bool add_smt) -{ - int ret, mode; - struct fw_vi_mac_cmd c; - struct fw_vi_mac_exact *p = c.u.exact; - - if (idx < 0) /* new allocation */ - idx = persist ? FW_VI_MAC_ADD_PERSIST_MAC : FW_VI_MAC_ADD_MAC; - mode = add_smt ? FW_VI_MAC_SMT_AND_MPSTCAM : FW_VI_MAC_MPS_TCAM_ENTRY; - - memset(&c, 0, sizeof(c)); - c.op_to_viid = htonl(FW_CMD_OP(FW_VI_MAC_CMD) | FW_CMD_REQUEST | - FW_CMD_WRITE | FW_VI_MAC_CMD_VIID(viid)); - c.freemacs_to_len16 = htonl(FW_CMD_LEN16(1)); - p->valid_to_idx = htons(FW_VI_MAC_CMD_VALID | - FW_VI_MAC_CMD_SMAC_RESULT(mode) | - FW_VI_MAC_CMD_IDX(idx)); - memcpy(p->macaddr, addr, sizeof(p->macaddr)); - - ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); - if (ret == 0) { - ret = FW_VI_MAC_CMD_IDX_GET(ntohs(p->valid_to_idx)); - if (ret >= NEXACT_MAC) - ret = -ENOMEM; - } - return ret; -} - -/** - * t4_set_addr_hash - program the MAC inexact-match hash filter - * @adap: the adapter - * @mbox: mailbox to use for the FW command - * @viid: the VI id - * @ucast: whether the hash filter should also match unicast addresses - * @vec: the value to be written to the hash filter - * @sleep_ok: call is allowed to sleep - * - * Sets the 64-bit inexact-match hash filter for a virtual interface. - */ -int t4_set_addr_hash(struct adapter *adap, unsigned int mbox, unsigned int viid, - bool ucast, u64 vec, bool sleep_ok) -{ - struct fw_vi_mac_cmd c; - - memset(&c, 0, sizeof(c)); - c.op_to_viid = htonl(FW_CMD_OP(FW_VI_MAC_CMD) | FW_CMD_REQUEST | - FW_CMD_WRITE | FW_VI_ENABLE_CMD_VIID(viid)); - c.freemacs_to_len16 = htonl(FW_VI_MAC_CMD_HASHVECEN | - FW_VI_MAC_CMD_HASHUNIEN(ucast) | - FW_CMD_LEN16(1)); - c.u.hash.hashvec = cpu_to_be64(vec); - return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok); -} - -/** - * t4_enable_vi - enable/disable a virtual interface - * @adap: the adapter - * @mbox: mailbox to use for the FW command - * @viid: the VI id - * @rx_en: 1=enable Rx, 0=disable Rx - * @tx_en: 1=enable Tx, 0=disable Tx - * - * Enables/disables a virtual interface. - */ -int t4_enable_vi(struct adapter *adap, unsigned int mbox, unsigned int viid, - bool rx_en, bool tx_en) -{ - struct fw_vi_enable_cmd c; - - memset(&c, 0, sizeof(c)); - c.op_to_viid = htonl(FW_CMD_OP(FW_VI_ENABLE_CMD) | FW_CMD_REQUEST | - FW_CMD_EXEC | FW_VI_ENABLE_CMD_VIID(viid)); - c.ien_to_len16 = htonl(FW_VI_ENABLE_CMD_IEN(rx_en) | - FW_VI_ENABLE_CMD_EEN(tx_en) | FW_LEN16(c)); - return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); -} - -/** - * t4_identify_port - identify a VI's port by blinking its LED - * @adap: the adapter - * @mbox: mailbox to use for the FW command - * @viid: the VI id - * @nblinks: how many times to blink LED at 2.5 Hz - * - * Identifies a VI's port by blinking its LED. - */ -int t4_identify_port(struct adapter *adap, unsigned int mbox, unsigned int viid, - unsigned int nblinks) -{ - struct fw_vi_enable_cmd c; - - c.op_to_viid = htonl(FW_CMD_OP(FW_VI_ENABLE_CMD) | FW_CMD_REQUEST | - FW_CMD_EXEC | FW_VI_ENABLE_CMD_VIID(viid)); - c.ien_to_len16 = htonl(FW_VI_ENABLE_CMD_LED | FW_LEN16(c)); - c.blinkdur = htons(nblinks); - return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); -} - -/** - * t4_iq_free - free an ingress queue and its FLs - * @adap: the adapter - * @mbox: mailbox to use for the FW command - * @pf: the PF owning the queues - * @vf: the VF owning the queues - * @iqtype: the ingress queue type - * @iqid: ingress queue id - * @fl0id: FL0 queue id or 0xffff if no attached FL0 - * @fl1id: FL1 queue id or 0xffff if no attached FL1 - * - * Frees an ingress queue and its associated FLs, if any. - */ -int t4_iq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, - unsigned int vf, unsigned int iqtype, unsigned int iqid, - unsigned int fl0id, unsigned int fl1id) -{ - struct fw_iq_cmd c; - - memset(&c, 0, sizeof(c)); - c.op_to_vfn = htonl(FW_CMD_OP(FW_IQ_CMD) | FW_CMD_REQUEST | - FW_CMD_EXEC | FW_IQ_CMD_PFN(pf) | - FW_IQ_CMD_VFN(vf)); - c.alloc_to_len16 = htonl(FW_IQ_CMD_FREE | FW_LEN16(c)); - c.type_to_iqandstindex = htonl(FW_IQ_CMD_TYPE(iqtype)); - c.iqid = htons(iqid); - c.fl0id = htons(fl0id); - c.fl1id = htons(fl1id); - return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); -} - -/** - * t4_eth_eq_free - free an Ethernet egress queue - * @adap: the adapter - * @mbox: mailbox to use for the FW command - * @pf: the PF owning the queue - * @vf: the VF owning the queue - * @eqid: egress queue id - * - * Frees an Ethernet egress queue. - */ -int t4_eth_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, - unsigned int vf, unsigned int eqid) -{ - struct fw_eq_eth_cmd c; - - memset(&c, 0, sizeof(c)); - c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_ETH_CMD) | FW_CMD_REQUEST | - FW_CMD_EXEC | FW_EQ_ETH_CMD_PFN(pf) | - FW_EQ_ETH_CMD_VFN(vf)); - c.alloc_to_len16 = htonl(FW_EQ_ETH_CMD_FREE | FW_LEN16(c)); - c.eqid_pkd = htonl(FW_EQ_ETH_CMD_EQID(eqid)); - return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); -} - -/** - * t4_ctrl_eq_free - free a control egress queue - * @adap: the adapter - * @mbox: mailbox to use for the FW command - * @pf: the PF owning the queue - * @vf: the VF owning the queue - * @eqid: egress queue id - * - * Frees a control egress queue. - */ -int t4_ctrl_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, - unsigned int vf, unsigned int eqid) -{ - struct fw_eq_ctrl_cmd c; - - memset(&c, 0, sizeof(c)); - c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_CTRL_CMD) | FW_CMD_REQUEST | - FW_CMD_EXEC | FW_EQ_CTRL_CMD_PFN(pf) | - FW_EQ_CTRL_CMD_VFN(vf)); - c.alloc_to_len16 = htonl(FW_EQ_CTRL_CMD_FREE | FW_LEN16(c)); - c.cmpliqid_eqid = htonl(FW_EQ_CTRL_CMD_EQID(eqid)); - return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); -} - -/** - * t4_ofld_eq_free - free an offload egress queue - * @adap: the adapter - * @mbox: mailbox to use for the FW command - * @pf: the PF owning the queue - * @vf: the VF owning the queue - * @eqid: egress queue id - * - * Frees a control egress queue. - */ -int t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, - unsigned int vf, unsigned int eqid) -{ - struct fw_eq_ofld_cmd c; - - memset(&c, 0, sizeof(c)); - c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_OFLD_CMD) | FW_CMD_REQUEST | - FW_CMD_EXEC | FW_EQ_OFLD_CMD_PFN(pf) | - FW_EQ_OFLD_CMD_VFN(vf)); - c.alloc_to_len16 = htonl(FW_EQ_OFLD_CMD_FREE | FW_LEN16(c)); - c.eqid_pkd = htonl(FW_EQ_OFLD_CMD_EQID(eqid)); - return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); -} - -/** - * t4_handle_fw_rpl - process a FW reply message - * @adap: the adapter - * @rpl: start of the FW message - * - * Processes a FW message, such as link state change messages. - */ -int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl) -{ - u8 opcode = *(const u8 *)rpl; - - if (opcode == FW_PORT_CMD) { /* link/module state change message */ - int speed = 0, fc = 0; - const struct fw_port_cmd *p = (void *)rpl; - int chan = FW_PORT_CMD_PORTID_GET(ntohl(p->op_to_portid)); - int port = adap->chan_map[chan]; - struct port_info *pi = adap2pinfo(adap, port); - struct link_config *lc = &pi->link_cfg; - u32 stat = ntohl(p->u.info.lstatus_to_modtype); - int link_ok = (stat & FW_PORT_CMD_LSTATUS) != 0; - u32 mod = FW_PORT_CMD_MODTYPE_GET(stat); - - if (stat & FW_PORT_CMD_RXPAUSE) - fc |= PAUSE_RX; - if (stat & FW_PORT_CMD_TXPAUSE) - fc |= PAUSE_TX; - if (stat & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100M)) - speed = SPEED_100; - else if (stat & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_1G)) - speed = SPEED_1000; - else if (stat & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_10G)) - speed = SPEED_10000; - - if (link_ok != lc->link_ok || speed != lc->speed || - fc != lc->fc) { /* something changed */ - lc->link_ok = link_ok; - lc->speed = speed; - lc->fc = fc; - t4_os_link_changed(adap, port, link_ok); - } - if (mod != pi->mod_type) { - pi->mod_type = mod; - t4_os_portmod_changed(adap, port); - } - } - return 0; -} - -static void __devinit get_pci_mode(struct adapter *adapter, - struct pci_params *p) -{ - u16 val; - u32 pcie_cap = pci_pcie_cap(adapter->pdev); - - if (pcie_cap) { - pci_read_config_word(adapter->pdev, pcie_cap + PCI_EXP_LNKSTA, - &val); - p->speed = val & PCI_EXP_LNKSTA_CLS; - p->width = (val & PCI_EXP_LNKSTA_NLW) >> 4; - } -} - -/** - * init_link_config - initialize a link's SW state - * @lc: structure holding the link state - * @caps: link capabilities - * - * Initializes the SW state maintained for each link, including the link's - * capabilities and default speed/flow-control/autonegotiation settings. - */ -static void __devinit init_link_config(struct link_config *lc, - unsigned int caps) -{ - lc->supported = caps; - lc->requested_speed = 0; - lc->speed = 0; - lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX; - if (lc->supported & FW_PORT_CAP_ANEG) { - lc->advertising = lc->supported & ADVERT_MASK; - lc->autoneg = AUTONEG_ENABLE; - lc->requested_fc |= PAUSE_AUTONEG; - } else { - lc->advertising = 0; - lc->autoneg = AUTONEG_DISABLE; - } -} - -int t4_wait_dev_ready(struct adapter *adap) -{ - if (t4_read_reg(adap, PL_WHOAMI) != 0xffffffff) - return 0; - msleep(500); - return t4_read_reg(adap, PL_WHOAMI) != 0xffffffff ? 0 : -EIO; -} - -static int __devinit get_flash_params(struct adapter *adap) -{ - int ret; - u32 info; - - ret = sf1_write(adap, 1, 1, 0, SF_RD_ID); - if (!ret) - ret = sf1_read(adap, 3, 0, 1, &info); - t4_write_reg(adap, SF_OP, 0); /* unlock SF */ - if (ret) - return ret; - - if ((info & 0xff) != 0x20) /* not a Numonix flash */ - return -EINVAL; - info >>= 16; /* log2 of size */ - if (info >= 0x14 && info < 0x18) - adap->params.sf_nsec = 1 << (info - 16); - else if (info == 0x18) - adap->params.sf_nsec = 64; - else - return -EINVAL; - adap->params.sf_size = 1 << info; - adap->params.sf_fw_start = - t4_read_reg(adap, CIM_BOOT_CFG) & BOOTADDR_MASK; - return 0; -} - -/** - * t4_prep_adapter - prepare SW and HW for operation - * @adapter: the adapter - * @reset: if true perform a HW reset - * - * Initialize adapter SW state for the various HW modules, set initial - * values for some adapter tunables, take PHYs out of reset, and - * initialize the MDIO interface. - */ -int __devinit t4_prep_adapter(struct adapter *adapter) -{ - int ret; - - ret = t4_wait_dev_ready(adapter); - if (ret < 0) - return ret; - - get_pci_mode(adapter, &adapter->params.pci); - adapter->params.rev = t4_read_reg(adapter, PL_REV); - - ret = get_flash_params(adapter); - if (ret < 0) { - dev_err(adapter->pdev_dev, "error %d identifying flash\n", ret); - return ret; - } - - ret = get_vpd_params(adapter, &adapter->params.vpd); - if (ret < 0) - return ret; - - init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd); - - /* - * Default port for debugging in case we can't reach FW. - */ - adapter->params.nports = 1; - adapter->params.portvec = 1; - return 0; -} - -int __devinit t4_port_init(struct adapter *adap, int mbox, int pf, int vf) -{ - u8 addr[6]; - int ret, i, j = 0; - struct fw_port_cmd c; - struct fw_rss_vi_config_cmd rvc; - - memset(&c, 0, sizeof(c)); - memset(&rvc, 0, sizeof(rvc)); - - for_each_port(adap, i) { - unsigned int rss_size; - struct port_info *p = adap2pinfo(adap, i); - - while ((adap->params.portvec & (1 << j)) == 0) - j++; - - c.op_to_portid = htonl(FW_CMD_OP(FW_PORT_CMD) | - FW_CMD_REQUEST | FW_CMD_READ | - FW_PORT_CMD_PORTID(j)); - c.action_to_len16 = htonl( - FW_PORT_CMD_ACTION(FW_PORT_ACTION_GET_PORT_INFO) | - FW_LEN16(c)); - ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); - if (ret) - return ret; - - ret = t4_alloc_vi(adap, mbox, j, pf, vf, 1, addr, &rss_size); - if (ret < 0) - return ret; - - p->viid = ret; - p->tx_chan = j; - p->lport = j; - p->rss_size = rss_size; - memcpy(adap->port[i]->dev_addr, addr, ETH_ALEN); - memcpy(adap->port[i]->perm_addr, addr, ETH_ALEN); - adap->port[i]->dev_id = j; - - ret = ntohl(c.u.info.lstatus_to_modtype); - p->mdio_addr = (ret & FW_PORT_CMD_MDIOCAP) ? - FW_PORT_CMD_MDIOADDR_GET(ret) : -1; - p->port_type = FW_PORT_CMD_PTYPE_GET(ret); - p->mod_type = FW_PORT_MOD_TYPE_NA; - - rvc.op_to_viid = htonl(FW_CMD_OP(FW_RSS_VI_CONFIG_CMD) | - FW_CMD_REQUEST | FW_CMD_READ | - FW_RSS_VI_CONFIG_CMD_VIID(p->viid)); - rvc.retval_len16 = htonl(FW_LEN16(rvc)); - ret = t4_wr_mbox(adap, mbox, &rvc, sizeof(rvc), &rvc); - if (ret) - return ret; - p->rss_mode = ntohl(rvc.u.basicvirtual.defaultq_to_udpen); - - init_link_config(&p->link_cfg, ntohs(c.u.info.pcap)); - j++; - } - return 0; -} diff --git a/drivers/net/cxgb4/t4_hw.h b/drivers/net/cxgb4/t4_hw.h deleted file mode 100644 index c26b455f37de..000000000000 --- a/drivers/net/cxgb4/t4_hw.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * This file is part of the Chelsio T4 Ethernet driver for Linux. - * - * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef __T4_HW_H -#define __T4_HW_H - -#include - -enum { - NCHAN = 4, /* # of HW channels */ - MAX_MTU = 9600, /* max MAC MTU, excluding header + FCS */ - EEPROMSIZE = 17408, /* Serial EEPROM physical size */ - EEPROMVSIZE = 32768, /* Serial EEPROM virtual address space size */ - EEPROMPFSIZE = 1024, /* EEPROM writable area size for PFn, n>0 */ - RSS_NENTRIES = 2048, /* # of entries in RSS mapping table */ - TCB_SIZE = 128, /* TCB size */ - NMTUS = 16, /* size of MTU table */ - NCCTRL_WIN = 32, /* # of congestion control windows */ - NEXACT_MAC = 336, /* # of exact MAC address filters */ - L2T_SIZE = 4096, /* # of L2T entries */ - MBOX_LEN = 64, /* mailbox size in bytes */ - TRACE_LEN = 112, /* length of trace data and mask */ - FILTER_OPT_LEN = 36, /* filter tuple width for optional components */ - NWOL_PAT = 8, /* # of WoL patterns */ - WOL_PAT_LEN = 128, /* length of WoL patterns */ -}; - -enum { - SF_PAGE_SIZE = 256, /* serial flash page size */ -}; - -enum { RSP_TYPE_FLBUF, RSP_TYPE_CPL, RSP_TYPE_INTR }; /* response entry types */ - -enum { MBOX_OWNER_NONE, MBOX_OWNER_FW, MBOX_OWNER_DRV }; /* mailbox owners */ - -enum { - SGE_MAX_WR_LEN = 512, /* max WR size in bytes */ - SGE_NTIMERS = 6, /* # of interrupt holdoff timer values */ - SGE_NCOUNTERS = 4, /* # of interrupt packet counter values */ - - SGE_TIMER_RSTRT_CNTR = 6, /* restart RX packet threshold counter */ - SGE_TIMER_UPD_CIDX = 7, /* update cidx only */ - - SGE_EQ_IDXSIZE = 64, /* egress queue pidx/cidx unit size */ - - SGE_INTRDST_PCI = 0, /* interrupt destination is PCI-E */ - SGE_INTRDST_IQ = 1, /* destination is an ingress queue */ - - SGE_UPDATEDEL_NONE = 0, /* ingress queue pidx update delivery */ - SGE_UPDATEDEL_INTR = 1, /* interrupt */ - SGE_UPDATEDEL_STPG = 2, /* status page */ - SGE_UPDATEDEL_BOTH = 3, /* interrupt and status page */ - - SGE_HOSTFCMODE_NONE = 0, /* egress queue cidx updates */ - SGE_HOSTFCMODE_IQ = 1, /* sent to ingress queue */ - SGE_HOSTFCMODE_STPG = 2, /* sent to status page */ - SGE_HOSTFCMODE_BOTH = 3, /* ingress queue and status page */ - - SGE_FETCHBURSTMIN_16B = 0,/* egress queue descriptor fetch minimum */ - SGE_FETCHBURSTMIN_32B = 1, - SGE_FETCHBURSTMIN_64B = 2, - SGE_FETCHBURSTMIN_128B = 3, - - SGE_FETCHBURSTMAX_64B = 0,/* egress queue descriptor fetch maximum */ - SGE_FETCHBURSTMAX_128B = 1, - SGE_FETCHBURSTMAX_256B = 2, - SGE_FETCHBURSTMAX_512B = 3, - - SGE_CIDXFLUSHTHRESH_1 = 0,/* egress queue cidx flush threshold */ - SGE_CIDXFLUSHTHRESH_2 = 1, - SGE_CIDXFLUSHTHRESH_4 = 2, - SGE_CIDXFLUSHTHRESH_8 = 3, - SGE_CIDXFLUSHTHRESH_16 = 4, - SGE_CIDXFLUSHTHRESH_32 = 5, - SGE_CIDXFLUSHTHRESH_64 = 6, - SGE_CIDXFLUSHTHRESH_128 = 7, - - SGE_INGPADBOUNDARY_SHIFT = 5,/* ingress queue pad boundary */ -}; - -struct sge_qstat { /* data written to SGE queue status entries */ - __be32 qid; - __be16 cidx; - __be16 pidx; -}; - -/* - * Structure for last 128 bits of response descriptors - */ -struct rsp_ctrl { - __be32 hdrbuflen_pidx; - __be32 pldbuflen_qid; - union { - u8 type_gen; - __be64 last_flit; - }; -}; - -#define RSPD_NEWBUF 0x80000000U -#define RSPD_LEN(x) (((x) >> 0) & 0x7fffffffU) -#define RSPD_QID(x) RSPD_LEN(x) - -#define RSPD_GEN(x) ((x) >> 7) -#define RSPD_TYPE(x) (((x) >> 4) & 3) - -#define QINTR_CNT_EN 0x1 -#define QINTR_TIMER_IDX(x) ((x) << 1) -#define QINTR_TIMER_IDX_GET(x) (((x) >> 1) & 0x7) -#endif /* __T4_HW_H */ diff --git a/drivers/net/cxgb4/t4_msg.h b/drivers/net/cxgb4/t4_msg.h deleted file mode 100644 index eb71b8250b91..000000000000 --- a/drivers/net/cxgb4/t4_msg.h +++ /dev/null @@ -1,678 +0,0 @@ -/* - * This file is part of the Chelsio T4 Ethernet driver for Linux. - * - * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef __T4_MSG_H -#define __T4_MSG_H - -#include - -enum { - CPL_PASS_OPEN_REQ = 0x1, - CPL_PASS_ACCEPT_RPL = 0x2, - CPL_ACT_OPEN_REQ = 0x3, - CPL_SET_TCB_FIELD = 0x5, - CPL_GET_TCB = 0x6, - CPL_CLOSE_CON_REQ = 0x8, - CPL_CLOSE_LISTSRV_REQ = 0x9, - CPL_ABORT_REQ = 0xA, - CPL_ABORT_RPL = 0xB, - CPL_RX_DATA_ACK = 0xD, - CPL_TX_PKT = 0xE, - CPL_L2T_WRITE_REQ = 0x12, - CPL_TID_RELEASE = 0x1A, - - CPL_CLOSE_LISTSRV_RPL = 0x20, - CPL_L2T_WRITE_RPL = 0x23, - CPL_PASS_OPEN_RPL = 0x24, - CPL_ACT_OPEN_RPL = 0x25, - CPL_PEER_CLOSE = 0x26, - CPL_ABORT_REQ_RSS = 0x2B, - CPL_ABORT_RPL_RSS = 0x2D, - - CPL_CLOSE_CON_RPL = 0x32, - CPL_ISCSI_HDR = 0x33, - CPL_RDMA_CQE = 0x35, - CPL_RDMA_CQE_READ_RSP = 0x36, - CPL_RDMA_CQE_ERR = 0x37, - CPL_RX_DATA = 0x39, - CPL_SET_TCB_RPL = 0x3A, - CPL_RX_PKT = 0x3B, - CPL_RX_DDP_COMPLETE = 0x3F, - - CPL_ACT_ESTABLISH = 0x40, - CPL_PASS_ESTABLISH = 0x41, - CPL_RX_DATA_DDP = 0x42, - CPL_PASS_ACCEPT_REQ = 0x44, - - CPL_RDMA_READ_REQ = 0x60, - - CPL_PASS_OPEN_REQ6 = 0x81, - CPL_ACT_OPEN_REQ6 = 0x83, - - CPL_RDMA_TERMINATE = 0xA2, - CPL_RDMA_WRITE = 0xA4, - CPL_SGE_EGR_UPDATE = 0xA5, - - CPL_TRACE_PKT = 0xB0, - - CPL_FW4_MSG = 0xC0, - CPL_FW4_PLD = 0xC1, - CPL_FW4_ACK = 0xC3, - - CPL_FW6_MSG = 0xE0, - CPL_FW6_PLD = 0xE1, - CPL_TX_PKT_LSO = 0xED, - CPL_TX_PKT_XT = 0xEE, - - NUM_CPL_CMDS -}; - -enum CPL_error { - CPL_ERR_NONE = 0, - CPL_ERR_TCAM_FULL = 3, - CPL_ERR_BAD_LENGTH = 15, - CPL_ERR_BAD_ROUTE = 18, - CPL_ERR_CONN_RESET = 20, - CPL_ERR_CONN_EXIST_SYNRECV = 21, - CPL_ERR_CONN_EXIST = 22, - CPL_ERR_ARP_MISS = 23, - CPL_ERR_BAD_SYN = 24, - CPL_ERR_CONN_TIMEDOUT = 30, - CPL_ERR_XMIT_TIMEDOUT = 31, - CPL_ERR_PERSIST_TIMEDOUT = 32, - CPL_ERR_FINWAIT2_TIMEDOUT = 33, - CPL_ERR_KEEPALIVE_TIMEDOUT = 34, - CPL_ERR_RTX_NEG_ADVICE = 35, - CPL_ERR_PERSIST_NEG_ADVICE = 36, - CPL_ERR_ABORT_FAILED = 42, - CPL_ERR_IWARP_FLM = 50, -}; - -enum { - ULP_MODE_NONE = 0, - ULP_MODE_ISCSI = 2, - ULP_MODE_RDMA = 4, - ULP_MODE_TCPDDP = 5, - ULP_MODE_FCOE = 6, -}; - -enum { - ULP_CRC_HEADER = 1 << 0, - ULP_CRC_DATA = 1 << 1 -}; - -enum { - CPL_ABORT_SEND_RST = 0, - CPL_ABORT_NO_RST, -}; - -enum { /* TX_PKT_XT checksum types */ - TX_CSUM_TCP = 0, - TX_CSUM_UDP = 1, - TX_CSUM_CRC16 = 4, - TX_CSUM_CRC32 = 5, - TX_CSUM_CRC32C = 6, - TX_CSUM_FCOE = 7, - TX_CSUM_TCPIP = 8, - TX_CSUM_UDPIP = 9, - TX_CSUM_TCPIP6 = 10, - TX_CSUM_UDPIP6 = 11, - TX_CSUM_IP = 12, -}; - -union opcode_tid { - __be32 opcode_tid; - u8 opcode; -}; - -#define CPL_OPCODE(x) ((x) << 24) -#define MK_OPCODE_TID(opcode, tid) (CPL_OPCODE(opcode) | (tid)) -#define OPCODE_TID(cmd) ((cmd)->ot.opcode_tid) -#define GET_TID(cmd) (ntohl(OPCODE_TID(cmd)) & 0xFFFFFF) - -/* partitioning of TID fields that also carry a queue id */ -#define GET_TID_TID(x) ((x) & 0x3fff) -#define GET_TID_QID(x) (((x) >> 14) & 0x3ff) -#define TID_QID(x) ((x) << 14) - -struct rss_header { - u8 opcode; -#if defined(__LITTLE_ENDIAN_BITFIELD) - u8 channel:2; - u8 filter_hit:1; - u8 filter_tid:1; - u8 hash_type:2; - u8 ipv6:1; - u8 send2fw:1; -#else - u8 send2fw:1; - u8 ipv6:1; - u8 hash_type:2; - u8 filter_tid:1; - u8 filter_hit:1; - u8 channel:2; -#endif - __be16 qid; - __be32 hash_val; -}; - -struct work_request_hdr { - __be32 wr_hi; - __be32 wr_mid; - __be64 wr_lo; -}; - -#define WR_HDR struct work_request_hdr wr - -struct cpl_pass_open_req { - WR_HDR; - union opcode_tid ot; - __be16 local_port; - __be16 peer_port; - __be32 local_ip; - __be32 peer_ip; - __be64 opt0; -#define TX_CHAN(x) ((x) << 2) -#define DELACK(x) ((x) << 5) -#define ULP_MODE(x) ((x) << 8) -#define RCV_BUFSIZ(x) ((x) << 12) -#define DSCP(x) ((x) << 22) -#define SMAC_SEL(x) ((u64)(x) << 28) -#define L2T_IDX(x) ((u64)(x) << 36) -#define NAGLE(x) ((u64)(x) << 49) -#define WND_SCALE(x) ((u64)(x) << 50) -#define KEEP_ALIVE(x) ((u64)(x) << 54) -#define MSS_IDX(x) ((u64)(x) << 60) - __be64 opt1; -#define SYN_RSS_ENABLE (1 << 0) -#define SYN_RSS_QUEUE(x) ((x) << 2) -#define CONN_POLICY_ASK (1 << 22) -}; - -struct cpl_pass_open_req6 { - WR_HDR; - union opcode_tid ot; - __be16 local_port; - __be16 peer_port; - __be64 local_ip_hi; - __be64 local_ip_lo; - __be64 peer_ip_hi; - __be64 peer_ip_lo; - __be64 opt0; - __be64 opt1; -}; - -struct cpl_pass_open_rpl { - union opcode_tid ot; - u8 rsvd[3]; - u8 status; -}; - -struct cpl_pass_accept_rpl { - WR_HDR; - union opcode_tid ot; - __be32 opt2; -#define RSS_QUEUE(x) ((x) << 0) -#define RSS_QUEUE_VALID (1 << 10) -#define RX_COALESCE_VALID(x) ((x) << 11) -#define RX_COALESCE(x) ((x) << 12) -#define TX_QUEUE(x) ((x) << 23) -#define RX_CHANNEL(x) ((x) << 26) -#define WND_SCALE_EN(x) ((x) << 28) -#define TSTAMPS_EN(x) ((x) << 29) -#define SACK_EN(x) ((x) << 30) - __be64 opt0; -}; - -struct cpl_act_open_req { - WR_HDR; - union opcode_tid ot; - __be16 local_port; - __be16 peer_port; - __be32 local_ip; - __be32 peer_ip; - __be64 opt0; - __be32 params; - __be32 opt2; -}; - -struct cpl_act_open_req6 { - WR_HDR; - union opcode_tid ot; - __be16 local_port; - __be16 peer_port; - __be64 local_ip_hi; - __be64 local_ip_lo; - __be64 peer_ip_hi; - __be64 peer_ip_lo; - __be64 opt0; - __be32 params; - __be32 opt2; -}; - -struct cpl_act_open_rpl { - union opcode_tid ot; - __be32 atid_status; -#define GET_AOPEN_STATUS(x) ((x) & 0xff) -#define GET_AOPEN_ATID(x) (((x) >> 8) & 0xffffff) -}; - -struct cpl_pass_establish { - union opcode_tid ot; - __be32 rsvd; - __be32 tos_stid; -#define GET_POPEN_TID(x) ((x) & 0xffffff) -#define GET_POPEN_TOS(x) (((x) >> 24) & 0xff) - __be16 mac_idx; - __be16 tcp_opt; -#define GET_TCPOPT_WSCALE_OK(x) (((x) >> 5) & 1) -#define GET_TCPOPT_SACK(x) (((x) >> 6) & 1) -#define GET_TCPOPT_TSTAMP(x) (((x) >> 7) & 1) -#define GET_TCPOPT_SND_WSCALE(x) (((x) >> 8) & 0xf) -#define GET_TCPOPT_MSS(x) (((x) >> 12) & 0xf) - __be32 snd_isn; - __be32 rcv_isn; -}; - -struct cpl_act_establish { - union opcode_tid ot; - __be32 rsvd; - __be32 tos_atid; - __be16 mac_idx; - __be16 tcp_opt; - __be32 snd_isn; - __be32 rcv_isn; -}; - -struct cpl_get_tcb { - WR_HDR; - union opcode_tid ot; - __be16 reply_ctrl; -#define QUEUENO(x) ((x) << 0) -#define REPLY_CHAN(x) ((x) << 14) -#define NO_REPLY(x) ((x) << 15) - __be16 cookie; -}; - -struct cpl_set_tcb_field { - WR_HDR; - union opcode_tid ot; - __be16 reply_ctrl; - __be16 word_cookie; -#define TCB_WORD(x) ((x) << 0) -#define TCB_COOKIE(x) ((x) << 5) - __be64 mask; - __be64 val; -}; - -struct cpl_set_tcb_rpl { - union opcode_tid ot; - __be16 rsvd; - u8 cookie; - u8 status; - __be64 oldval; -}; - -struct cpl_close_con_req { - WR_HDR; - union opcode_tid ot; - __be32 rsvd; -}; - -struct cpl_close_con_rpl { - union opcode_tid ot; - u8 rsvd[3]; - u8 status; - __be32 snd_nxt; - __be32 rcv_nxt; -}; - -struct cpl_close_listsvr_req { - WR_HDR; - union opcode_tid ot; - __be16 reply_ctrl; -#define LISTSVR_IPV6 (1 << 14) - __be16 rsvd; -}; - -struct cpl_close_listsvr_rpl { - union opcode_tid ot; - u8 rsvd[3]; - u8 status; -}; - -struct cpl_abort_req_rss { - union opcode_tid ot; - u8 rsvd[3]; - u8 status; -}; - -struct cpl_abort_req { - WR_HDR; - union opcode_tid ot; - __be32 rsvd0; - u8 rsvd1; - u8 cmd; - u8 rsvd2[6]; -}; - -struct cpl_abort_rpl_rss { - union opcode_tid ot; - u8 rsvd[3]; - u8 status; -}; - -struct cpl_abort_rpl { - WR_HDR; - union opcode_tid ot; - __be32 rsvd0; - u8 rsvd1; - u8 cmd; - u8 rsvd2[6]; -}; - -struct cpl_peer_close { - union opcode_tid ot; - __be32 rcv_nxt; -}; - -struct cpl_tid_release { - WR_HDR; - union opcode_tid ot; - __be32 rsvd; -}; - -struct cpl_tx_pkt_core { - __be32 ctrl0; -#define TXPKT_VF(x) ((x) << 0) -#define TXPKT_PF(x) ((x) << 8) -#define TXPKT_VF_VLD (1 << 11) -#define TXPKT_OVLAN_IDX(x) ((x) << 12) -#define TXPKT_INTF(x) ((x) << 16) -#define TXPKT_INS_OVLAN (1 << 21) -#define TXPKT_OPCODE(x) ((x) << 24) - __be16 pack; - __be16 len; - __be64 ctrl1; -#define TXPKT_CSUM_END(x) ((x) << 12) -#define TXPKT_CSUM_START(x) ((x) << 20) -#define TXPKT_IPHDR_LEN(x) ((u64)(x) << 20) -#define TXPKT_CSUM_LOC(x) ((u64)(x) << 30) -#define TXPKT_ETHHDR_LEN(x) ((u64)(x) << 34) -#define TXPKT_CSUM_TYPE(x) ((u64)(x) << 40) -#define TXPKT_VLAN(x) ((u64)(x) << 44) -#define TXPKT_VLAN_VLD (1ULL << 60) -#define TXPKT_IPCSUM_DIS (1ULL << 62) -#define TXPKT_L4CSUM_DIS (1ULL << 63) -}; - -struct cpl_tx_pkt { - WR_HDR; - struct cpl_tx_pkt_core c; -}; - -#define cpl_tx_pkt_xt cpl_tx_pkt - -struct cpl_tx_pkt_lso_core { - __be32 lso_ctrl; -#define LSO_TCPHDR_LEN(x) ((x) << 0) -#define LSO_IPHDR_LEN(x) ((x) << 4) -#define LSO_ETHHDR_LEN(x) ((x) << 16) -#define LSO_IPV6(x) ((x) << 20) -#define LSO_LAST_SLICE (1 << 22) -#define LSO_FIRST_SLICE (1 << 23) -#define LSO_OPCODE(x) ((x) << 24) - __be16 ipid_ofst; - __be16 mss; - __be32 seqno_offset; - __be32 len; - /* encapsulated CPL (TX_PKT, TX_PKT_XT or TX_DATA) follows here */ -}; - -struct cpl_tx_pkt_lso { - WR_HDR; - struct cpl_tx_pkt_lso_core c; - /* encapsulated CPL (TX_PKT, TX_PKT_XT or TX_DATA) follows here */ -}; - -struct cpl_iscsi_hdr { - union opcode_tid ot; - __be16 pdu_len_ddp; -#define ISCSI_PDU_LEN(x) ((x) & 0x7FFF) -#define ISCSI_DDP (1 << 15) - __be16 len; - __be32 seq; - __be16 urg; - u8 rsvd; - u8 status; -}; - -struct cpl_rx_data { - union opcode_tid ot; - __be16 rsvd; - __be16 len; - __be32 seq; - __be16 urg; -#if defined(__LITTLE_ENDIAN_BITFIELD) - u8 dack_mode:2; - u8 psh:1; - u8 heartbeat:1; - u8 ddp_off:1; - u8 :3; -#else - u8 :3; - u8 ddp_off:1; - u8 heartbeat:1; - u8 psh:1; - u8 dack_mode:2; -#endif - u8 status; -}; - -struct cpl_rx_data_ack { - WR_HDR; - union opcode_tid ot; - __be32 credit_dack; -#define RX_CREDITS(x) ((x) << 0) -#define RX_FORCE_ACK(x) ((x) << 28) -}; - -struct cpl_rx_pkt { - struct rss_header rsshdr; - u8 opcode; -#if defined(__LITTLE_ENDIAN_BITFIELD) - u8 iff:4; - u8 csum_calc:1; - u8 ipmi_pkt:1; - u8 vlan_ex:1; - u8 ip_frag:1; -#else - u8 ip_frag:1; - u8 vlan_ex:1; - u8 ipmi_pkt:1; - u8 csum_calc:1; - u8 iff:4; -#endif - __be16 csum; - __be16 vlan; - __be16 len; - __be32 l2info; -#define RXF_UDP (1 << 22) -#define RXF_TCP (1 << 23) -#define RXF_IP (1 << 24) -#define RXF_IP6 (1 << 25) - __be16 hdr_len; - __be16 err_vec; -}; - -struct cpl_trace_pkt { - u8 opcode; - u8 intf; -#if defined(__LITTLE_ENDIAN_BITFIELD) - u8 runt:4; - u8 filter_hit:4; - u8 :6; - u8 err:1; - u8 trunc:1; -#else - u8 filter_hit:4; - u8 runt:4; - u8 trunc:1; - u8 err:1; - u8 :6; -#endif - __be16 rsvd; - __be16 len; - __be64 tstamp; -}; - -struct cpl_l2t_write_req { - WR_HDR; - union opcode_tid ot; - __be16 params; -#define L2T_W_INFO(x) ((x) << 2) -#define L2T_W_PORT(x) ((x) << 8) -#define L2T_W_NOREPLY(x) ((x) << 15) - __be16 l2t_idx; - __be16 vlan; - u8 dst_mac[6]; -}; - -struct cpl_l2t_write_rpl { - union opcode_tid ot; - u8 status; - u8 rsvd[3]; -}; - -struct cpl_rdma_terminate { - union opcode_tid ot; - __be16 rsvd; - __be16 len; -}; - -struct cpl_sge_egr_update { - __be32 opcode_qid; -#define EGR_QID(x) ((x) & 0x1FFFF) - __be16 cidx; - __be16 pidx; -}; - -struct cpl_fw4_pld { - u8 opcode; - u8 rsvd0[3]; - u8 type; - u8 rsvd1; - __be16 len; - __be64 data; - __be64 rsvd2; -}; - -struct cpl_fw6_pld { - u8 opcode; - u8 rsvd[5]; - __be16 len; - __be64 data[4]; -}; - -struct cpl_fw4_msg { - u8 opcode; - u8 type; - __be16 rsvd0; - __be32 rsvd1; - __be64 data[2]; -}; - -struct cpl_fw4_ack { - union opcode_tid ot; - u8 credits; - u8 rsvd0[2]; - u8 seq_vld; - __be32 snd_nxt; - __be32 snd_una; - __be64 rsvd1; -}; - -struct cpl_fw6_msg { - u8 opcode; - u8 type; - __be16 rsvd0; - __be32 rsvd1; - __be64 data[4]; -}; - -/* cpl_fw6_msg.type values */ -enum { - FW6_TYPE_CMD_RPL = 0, -}; - -enum { - ULP_TX_MEM_READ = 2, - ULP_TX_MEM_WRITE = 3, - ULP_TX_PKT = 4 -}; - -enum { - ULP_TX_SC_NOOP = 0x80, - ULP_TX_SC_IMM = 0x81, - ULP_TX_SC_DSGL = 0x82, - ULP_TX_SC_ISGL = 0x83 -}; - -struct ulptx_sge_pair { - __be32 len[2]; - __be64 addr[2]; -}; - -struct ulptx_sgl { - __be32 cmd_nsge; -#define ULPTX_CMD(x) ((x) << 24) -#define ULPTX_NSGE(x) ((x) << 0) - __be32 len0; - __be64 addr0; - struct ulptx_sge_pair sge[0]; -}; - -struct ulp_mem_io { - WR_HDR; - __be32 cmd; -#define ULP_MEMIO_ORDER(x) ((x) << 23) - __be32 len16; /* command length */ - __be32 dlen; /* data length in 32-byte units */ -#define ULP_MEMIO_DATA_LEN(x) ((x) << 0) - __be32 lock_addr; -#define ULP_MEMIO_ADDR(x) ((x) << 0) -#define ULP_MEMIO_LOCK(x) ((x) << 31) -}; - -#endif /* __T4_MSG_H */ diff --git a/drivers/net/cxgb4/t4_regs.h b/drivers/net/cxgb4/t4_regs.h deleted file mode 100644 index 0adc5bcec7c4..000000000000 --- a/drivers/net/cxgb4/t4_regs.h +++ /dev/null @@ -1,885 +0,0 @@ -/* - * This file is part of the Chelsio T4 Ethernet driver for Linux. - * - * Copyright (c) 2010 Chelsio Communications, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef __T4_REGS_H -#define __T4_REGS_H - -#define MYPF_BASE 0x1b000 -#define MYPF_REG(reg_addr) (MYPF_BASE + (reg_addr)) - -#define PF0_BASE 0x1e000 -#define PF0_REG(reg_addr) (PF0_BASE + (reg_addr)) - -#define PF_STRIDE 0x400 -#define PF_BASE(idx) (PF0_BASE + (idx) * PF_STRIDE) -#define PF_REG(idx, reg) (PF_BASE(idx) + (reg)) - -#define MYPORT_BASE 0x1c000 -#define MYPORT_REG(reg_addr) (MYPORT_BASE + (reg_addr)) - -#define PORT0_BASE 0x20000 -#define PORT0_REG(reg_addr) (PORT0_BASE + (reg_addr)) - -#define PORT_STRIDE 0x2000 -#define PORT_BASE(idx) (PORT0_BASE + (idx) * PORT_STRIDE) -#define PORT_REG(idx, reg) (PORT_BASE(idx) + (reg)) - -#define EDC_STRIDE (EDC_1_BASE_ADDR - EDC_0_BASE_ADDR) -#define EDC_REG(reg, idx) (reg + EDC_STRIDE * idx) - -#define PCIE_MEM_ACCESS_REG(reg_addr, idx) ((reg_addr) + (idx) * 8) -#define PCIE_MAILBOX_REG(reg_addr, idx) ((reg_addr) + (idx) * 8) -#define MC_BIST_STATUS_REG(reg_addr, idx) ((reg_addr) + (idx) * 4) -#define EDC_BIST_STATUS_REG(reg_addr, idx) ((reg_addr) + (idx) * 4) - -#define SGE_PF_KDOORBELL 0x0 -#define QID_MASK 0xffff8000U -#define QID_SHIFT 15 -#define QID(x) ((x) << QID_SHIFT) -#define DBPRIO 0x00004000U -#define PIDX_MASK 0x00003fffU -#define PIDX_SHIFT 0 -#define PIDX(x) ((x) << PIDX_SHIFT) - -#define SGE_PF_GTS 0x4 -#define INGRESSQID_MASK 0xffff0000U -#define INGRESSQID_SHIFT 16 -#define INGRESSQID(x) ((x) << INGRESSQID_SHIFT) -#define TIMERREG_MASK 0x0000e000U -#define TIMERREG_SHIFT 13 -#define TIMERREG(x) ((x) << TIMERREG_SHIFT) -#define SEINTARM_MASK 0x00001000U -#define SEINTARM_SHIFT 12 -#define SEINTARM(x) ((x) << SEINTARM_SHIFT) -#define CIDXINC_MASK 0x00000fffU -#define CIDXINC_SHIFT 0 -#define CIDXINC(x) ((x) << CIDXINC_SHIFT) - -#define SGE_CONTROL 0x1008 -#define DCASYSTYPE 0x00080000U -#define RXPKTCPLMODE 0x00040000U -#define EGRSTATUSPAGESIZE 0x00020000U -#define PKTSHIFT_MASK 0x00001c00U -#define PKTSHIFT_SHIFT 10 -#define PKTSHIFT(x) ((x) << PKTSHIFT_SHIFT) -#define PKTSHIFT_GET(x) (((x) & PKTSHIFT_MASK) >> PKTSHIFT_SHIFT) -#define INGPCIEBOUNDARY_MASK 0x00000380U -#define INGPCIEBOUNDARY_SHIFT 7 -#define INGPCIEBOUNDARY(x) ((x) << INGPCIEBOUNDARY_SHIFT) -#define INGPADBOUNDARY_MASK 0x00000070U -#define INGPADBOUNDARY_SHIFT 4 -#define INGPADBOUNDARY(x) ((x) << INGPADBOUNDARY_SHIFT) -#define INGPADBOUNDARY_GET(x) (((x) & INGPADBOUNDARY_MASK) \ - >> INGPADBOUNDARY_SHIFT) -#define EGRPCIEBOUNDARY_MASK 0x0000000eU -#define EGRPCIEBOUNDARY_SHIFT 1 -#define EGRPCIEBOUNDARY(x) ((x) << EGRPCIEBOUNDARY_SHIFT) -#define GLOBALENABLE 0x00000001U - -#define SGE_HOST_PAGE_SIZE 0x100c -#define HOSTPAGESIZEPF0_MASK 0x0000000fU -#define HOSTPAGESIZEPF0_SHIFT 0 -#define HOSTPAGESIZEPF0(x) ((x) << HOSTPAGESIZEPF0_SHIFT) - -#define SGE_EGRESS_QUEUES_PER_PAGE_PF 0x1010 -#define QUEUESPERPAGEPF0_MASK 0x0000000fU -#define QUEUESPERPAGEPF0_GET(x) ((x) & QUEUESPERPAGEPF0_MASK) - -#define SGE_INT_CAUSE1 0x1024 -#define SGE_INT_CAUSE2 0x1030 -#define SGE_INT_CAUSE3 0x103c -#define ERR_FLM_DBP 0x80000000U -#define ERR_FLM_IDMA1 0x40000000U -#define ERR_FLM_IDMA0 0x20000000U -#define ERR_FLM_HINT 0x10000000U -#define ERR_PCIE_ERROR3 0x08000000U -#define ERR_PCIE_ERROR2 0x04000000U -#define ERR_PCIE_ERROR1 0x02000000U -#define ERR_PCIE_ERROR0 0x01000000U -#define ERR_TIMER_ABOVE_MAX_QID 0x00800000U -#define ERR_CPL_EXCEED_IQE_SIZE 0x00400000U -#define ERR_INVALID_CIDX_INC 0x00200000U -#define ERR_ITP_TIME_PAUSED 0x00100000U -#define ERR_CPL_OPCODE_0 0x00080000U -#define ERR_DROPPED_DB 0x00040000U -#define ERR_DATA_CPL_ON_HIGH_QID1 0x00020000U -#define ERR_DATA_CPL_ON_HIGH_QID0 0x00010000U -#define ERR_BAD_DB_PIDX3 0x00008000U -#define ERR_BAD_DB_PIDX2 0x00004000U -#define ERR_BAD_DB_PIDX1 0x00002000U -#define ERR_BAD_DB_PIDX0 0x00001000U -#define ERR_ING_PCIE_CHAN 0x00000800U -#define ERR_ING_CTXT_PRIO 0x00000400U -#define ERR_EGR_CTXT_PRIO 0x00000200U -#define DBFIFO_HP_INT 0x00000100U -#define DBFIFO_LP_INT 0x00000080U -#define REG_ADDRESS_ERR 0x00000040U -#define INGRESS_SIZE_ERR 0x00000020U -#define EGRESS_SIZE_ERR 0x00000010U -#define ERR_INV_CTXT3 0x00000008U -#define ERR_INV_CTXT2 0x00000004U -#define ERR_INV_CTXT1 0x00000002U -#define ERR_INV_CTXT0 0x00000001U - -#define SGE_INT_ENABLE3 0x1040 -#define SGE_FL_BUFFER_SIZE0 0x1044 -#define SGE_FL_BUFFER_SIZE1 0x1048 -#define SGE_INGRESS_RX_THRESHOLD 0x10a0 -#define THRESHOLD_0_MASK 0x3f000000U -#define THRESHOLD_0_SHIFT 24 -#define THRESHOLD_0(x) ((x) << THRESHOLD_0_SHIFT) -#define THRESHOLD_0_GET(x) (((x) & THRESHOLD_0_MASK) >> THRESHOLD_0_SHIFT) -#define THRESHOLD_1_MASK 0x003f0000U -#define THRESHOLD_1_SHIFT 16 -#define THRESHOLD_1(x) ((x) << THRESHOLD_1_SHIFT) -#define THRESHOLD_1_GET(x) (((x) & THRESHOLD_1_MASK) >> THRESHOLD_1_SHIFT) -#define THRESHOLD_2_MASK 0x00003f00U -#define THRESHOLD_2_SHIFT 8 -#define THRESHOLD_2(x) ((x) << THRESHOLD_2_SHIFT) -#define THRESHOLD_2_GET(x) (((x) & THRESHOLD_2_MASK) >> THRESHOLD_2_SHIFT) -#define THRESHOLD_3_MASK 0x0000003fU -#define THRESHOLD_3_SHIFT 0 -#define THRESHOLD_3(x) ((x) << THRESHOLD_3_SHIFT) -#define THRESHOLD_3_GET(x) (((x) & THRESHOLD_3_MASK) >> THRESHOLD_3_SHIFT) - -#define SGE_TIMER_VALUE_0_AND_1 0x10b8 -#define TIMERVALUE0_MASK 0xffff0000U -#define TIMERVALUE0_SHIFT 16 -#define TIMERVALUE0(x) ((x) << TIMERVALUE0_SHIFT) -#define TIMERVALUE0_GET(x) (((x) & TIMERVALUE0_MASK) >> TIMERVALUE0_SHIFT) -#define TIMERVALUE1_MASK 0x0000ffffU -#define TIMERVALUE1_SHIFT 0 -#define TIMERVALUE1(x) ((x) << TIMERVALUE1_SHIFT) -#define TIMERVALUE1_GET(x) (((x) & TIMERVALUE1_MASK) >> TIMERVALUE1_SHIFT) - -#define SGE_TIMER_VALUE_2_AND_3 0x10bc -#define SGE_TIMER_VALUE_4_AND_5 0x10c0 -#define SGE_DEBUG_INDEX 0x10cc -#define SGE_DEBUG_DATA_HIGH 0x10d0 -#define SGE_DEBUG_DATA_LOW 0x10d4 -#define SGE_INGRESS_QUEUES_PER_PAGE_PF 0x10f4 - -#define PCIE_PF_CLI 0x44 -#define PCIE_INT_CAUSE 0x3004 -#define UNXSPLCPLERR 0x20000000U -#define PCIEPINT 0x10000000U -#define PCIESINT 0x08000000U -#define RPLPERR 0x04000000U -#define RXWRPERR 0x02000000U -#define RXCPLPERR 0x01000000U -#define PIOTAGPERR 0x00800000U -#define MATAGPERR 0x00400000U -#define INTXCLRPERR 0x00200000U -#define FIDPERR 0x00100000U -#define CFGSNPPERR 0x00080000U -#define HRSPPERR 0x00040000U -#define HREQPERR 0x00020000U -#define HCNTPERR 0x00010000U -#define DRSPPERR 0x00008000U -#define DREQPERR 0x00004000U -#define DCNTPERR 0x00002000U -#define CRSPPERR 0x00001000U -#define CREQPERR 0x00000800U -#define CCNTPERR 0x00000400U -#define TARTAGPERR 0x00000200U -#define PIOREQPERR 0x00000100U -#define PIOCPLPERR 0x00000080U -#define MSIXDIPERR 0x00000040U -#define MSIXDATAPERR 0x00000020U -#define MSIXADDRHPERR 0x00000010U -#define MSIXADDRLPERR 0x00000008U -#define MSIDATAPERR 0x00000004U -#define MSIADDRHPERR 0x00000002U -#define MSIADDRLPERR 0x00000001U - -#define PCIE_NONFAT_ERR 0x3010 -#define PCIE_MEM_ACCESS_BASE_WIN 0x3068 -#define PCIEOFST_MASK 0xfffffc00U -#define BIR_MASK 0x00000300U -#define BIR_SHIFT 8 -#define BIR(x) ((x) << BIR_SHIFT) -#define WINDOW_MASK 0x000000ffU -#define WINDOW_SHIFT 0 -#define WINDOW(x) ((x) << WINDOW_SHIFT) -#define PCIE_MEM_ACCESS_OFFSET 0x306c - -#define PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS 0x5908 -#define RNPP 0x80000000U -#define RPCP 0x20000000U -#define RCIP 0x08000000U -#define RCCP 0x04000000U -#define RFTP 0x00800000U -#define PTRP 0x00100000U - -#define PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS 0x59a4 -#define TPCP 0x40000000U -#define TNPP 0x20000000U -#define TFTP 0x10000000U -#define TCAP 0x08000000U -#define TCIP 0x04000000U -#define RCAP 0x02000000U -#define PLUP 0x00800000U -#define PLDN 0x00400000U -#define OTDD 0x00200000U -#define GTRP 0x00100000U -#define RDPE 0x00040000U -#define TDCE 0x00020000U -#define TDUE 0x00010000U - -#define MC_INT_CAUSE 0x7518 -#define ECC_UE_INT_CAUSE 0x00000004U -#define ECC_CE_INT_CAUSE 0x00000002U -#define PERR_INT_CAUSE 0x00000001U - -#define MC_ECC_STATUS 0x751c -#define ECC_CECNT_MASK 0xffff0000U -#define ECC_CECNT_SHIFT 16 -#define ECC_CECNT(x) ((x) << ECC_CECNT_SHIFT) -#define ECC_CECNT_GET(x) (((x) & ECC_CECNT_MASK) >> ECC_CECNT_SHIFT) -#define ECC_UECNT_MASK 0x0000ffffU -#define ECC_UECNT_SHIFT 0 -#define ECC_UECNT(x) ((x) << ECC_UECNT_SHIFT) -#define ECC_UECNT_GET(x) (((x) & ECC_UECNT_MASK) >> ECC_UECNT_SHIFT) - -#define MC_BIST_CMD 0x7600 -#define START_BIST 0x80000000U -#define BIST_CMD_GAP_MASK 0x0000ff00U -#define BIST_CMD_GAP_SHIFT 8 -#define BIST_CMD_GAP(x) ((x) << BIST_CMD_GAP_SHIFT) -#define BIST_OPCODE_MASK 0x00000003U -#define BIST_OPCODE_SHIFT 0 -#define BIST_OPCODE(x) ((x) << BIST_OPCODE_SHIFT) - -#define MC_BIST_CMD_ADDR 0x7604 -#define MC_BIST_CMD_LEN 0x7608 -#define MC_BIST_DATA_PATTERN 0x760c -#define BIST_DATA_TYPE_MASK 0x0000000fU -#define BIST_DATA_TYPE_SHIFT 0 -#define BIST_DATA_TYPE(x) ((x) << BIST_DATA_TYPE_SHIFT) - -#define MC_BIST_STATUS_RDATA 0x7688 - -#define MA_EXT_MEMORY_BAR 0x77c8 -#define EXT_MEM_SIZE_MASK 0x00000fffU -#define EXT_MEM_SIZE_SHIFT 0 -#define EXT_MEM_SIZE_GET(x) (((x) & EXT_MEM_SIZE_MASK) >> EXT_MEM_SIZE_SHIFT) - -#define MA_TARGET_MEM_ENABLE 0x77d8 -#define EXT_MEM_ENABLE 0x00000004U -#define EDRAM1_ENABLE 0x00000002U -#define EDRAM0_ENABLE 0x00000001U - -#define MA_INT_CAUSE 0x77e0 -#define MEM_PERR_INT_CAUSE 0x00000002U -#define MEM_WRAP_INT_CAUSE 0x00000001U - -#define MA_INT_WRAP_STATUS 0x77e4 -#define MEM_WRAP_ADDRESS_MASK 0xfffffff0U -#define MEM_WRAP_ADDRESS_SHIFT 4 -#define MEM_WRAP_ADDRESS_GET(x) (((x) & MEM_WRAP_ADDRESS_MASK) >> MEM_WRAP_ADDRESS_SHIFT) -#define MEM_WRAP_CLIENT_NUM_MASK 0x0000000fU -#define MEM_WRAP_CLIENT_NUM_SHIFT 0 -#define MEM_WRAP_CLIENT_NUM_GET(x) (((x) & MEM_WRAP_CLIENT_NUM_MASK) >> MEM_WRAP_CLIENT_NUM_SHIFT) - -#define MA_PARITY_ERROR_STATUS 0x77f4 - -#define EDC_0_BASE_ADDR 0x7900 - -#define EDC_BIST_CMD 0x7904 -#define EDC_BIST_CMD_ADDR 0x7908 -#define EDC_BIST_CMD_LEN 0x790c -#define EDC_BIST_DATA_PATTERN 0x7910 -#define EDC_BIST_STATUS_RDATA 0x7928 -#define EDC_INT_CAUSE 0x7978 -#define ECC_UE_PAR 0x00000020U -#define ECC_CE_PAR 0x00000010U -#define PERR_PAR_CAUSE 0x00000008U - -#define EDC_ECC_STATUS 0x797c - -#define EDC_1_BASE_ADDR 0x7980 - -#define CIM_BOOT_CFG 0x7b00 -#define BOOTADDR_MASK 0xffffff00U - -#define CIM_PF_MAILBOX_DATA 0x240 -#define CIM_PF_MAILBOX_CTRL 0x280 -#define MBMSGVALID 0x00000008U -#define MBINTREQ 0x00000004U -#define MBOWNER_MASK 0x00000003U -#define MBOWNER_SHIFT 0 -#define MBOWNER(x) ((x) << MBOWNER_SHIFT) -#define MBOWNER_GET(x) (((x) & MBOWNER_MASK) >> MBOWNER_SHIFT) - -#define CIM_PF_HOST_INT_CAUSE 0x28c -#define MBMSGRDYINT 0x00080000U - -#define CIM_HOST_INT_CAUSE 0x7b2c -#define TIEQOUTPARERRINT 0x00100000U -#define TIEQINPARERRINT 0x00080000U -#define MBHOSTPARERR 0x00040000U -#define MBUPPARERR 0x00020000U -#define IBQPARERR 0x0001f800U -#define IBQTP0PARERR 0x00010000U -#define IBQTP1PARERR 0x00008000U -#define IBQULPPARERR 0x00004000U -#define IBQSGELOPARERR 0x00002000U -#define IBQSGEHIPARERR 0x00001000U -#define IBQNCSIPARERR 0x00000800U -#define OBQPARERR 0x000007e0U -#define OBQULP0PARERR 0x00000400U -#define OBQULP1PARERR 0x00000200U -#define OBQULP2PARERR 0x00000100U -#define OBQULP3PARERR 0x00000080U -#define OBQSGEPARERR 0x00000040U -#define OBQNCSIPARERR 0x00000020U -#define PREFDROPINT 0x00000002U -#define UPACCNONZERO 0x00000001U - -#define CIM_HOST_UPACC_INT_CAUSE 0x7b34 -#define EEPROMWRINT 0x40000000U -#define TIMEOUTMAINT 0x20000000U -#define TIMEOUTINT 0x10000000U -#define RSPOVRLOOKUPINT 0x08000000U -#define REQOVRLOOKUPINT 0x04000000U -#define BLKWRPLINT 0x02000000U -#define BLKRDPLINT 0x01000000U -#define SGLWRPLINT 0x00800000U -#define SGLRDPLINT 0x00400000U -#define BLKWRCTLINT 0x00200000U -#define BLKRDCTLINT 0x00100000U -#define SGLWRCTLINT 0x00080000U -#define SGLRDCTLINT 0x00040000U -#define BLKWREEPROMINT 0x00020000U -#define BLKRDEEPROMINT 0x00010000U -#define SGLWREEPROMINT 0x00008000U -#define SGLRDEEPROMINT 0x00004000U -#define BLKWRFLASHINT 0x00002000U -#define BLKRDFLASHINT 0x00001000U -#define SGLWRFLASHINT 0x00000800U -#define SGLRDFLASHINT 0x00000400U -#define BLKWRBOOTINT 0x00000200U -#define BLKRDBOOTINT 0x00000100U -#define SGLWRBOOTINT 0x00000080U -#define SGLRDBOOTINT 0x00000040U -#define ILLWRBEINT 0x00000020U -#define ILLRDBEINT 0x00000010U -#define ILLRDINT 0x00000008U -#define ILLWRINT 0x00000004U -#define ILLTRANSINT 0x00000002U -#define RSVDSPACEINT 0x00000001U - -#define TP_OUT_CONFIG 0x7d04 -#define VLANEXTENABLE_MASK 0x0000f000U -#define VLANEXTENABLE_SHIFT 12 - -#define TP_PARA_REG2 0x7d68 -#define MAXRXDATA_MASK 0xffff0000U -#define MAXRXDATA_SHIFT 16 -#define MAXRXDATA_GET(x) (((x) & MAXRXDATA_MASK) >> MAXRXDATA_SHIFT) - -#define TP_TIMER_RESOLUTION 0x7d90 -#define TIMERRESOLUTION_MASK 0x00ff0000U -#define TIMERRESOLUTION_SHIFT 16 -#define TIMERRESOLUTION_GET(x) (((x) & TIMERRESOLUTION_MASK) >> TIMERRESOLUTION_SHIFT) - -#define TP_SHIFT_CNT 0x7dc0 - -#define TP_CCTRL_TABLE 0x7ddc -#define TP_MTU_TABLE 0x7de4 -#define MTUINDEX_MASK 0xff000000U -#define MTUINDEX_SHIFT 24 -#define MTUINDEX(x) ((x) << MTUINDEX_SHIFT) -#define MTUWIDTH_MASK 0x000f0000U -#define MTUWIDTH_SHIFT 16 -#define MTUWIDTH(x) ((x) << MTUWIDTH_SHIFT) -#define MTUWIDTH_GET(x) (((x) & MTUWIDTH_MASK) >> MTUWIDTH_SHIFT) -#define MTUVALUE_MASK 0x00003fffU -#define MTUVALUE_SHIFT 0 -#define MTUVALUE(x) ((x) << MTUVALUE_SHIFT) -#define MTUVALUE_GET(x) (((x) & MTUVALUE_MASK) >> MTUVALUE_SHIFT) - -#define TP_RSS_LKP_TABLE 0x7dec -#define LKPTBLROWVLD 0x80000000U -#define LKPTBLQUEUE1_MASK 0x000ffc00U -#define LKPTBLQUEUE1_SHIFT 10 -#define LKPTBLQUEUE1(x) ((x) << LKPTBLQUEUE1_SHIFT) -#define LKPTBLQUEUE1_GET(x) (((x) & LKPTBLQUEUE1_MASK) >> LKPTBLQUEUE1_SHIFT) -#define LKPTBLQUEUE0_MASK 0x000003ffU -#define LKPTBLQUEUE0_SHIFT 0 -#define LKPTBLQUEUE0(x) ((x) << LKPTBLQUEUE0_SHIFT) -#define LKPTBLQUEUE0_GET(x) (((x) & LKPTBLQUEUE0_MASK) >> LKPTBLQUEUE0_SHIFT) - -#define TP_PIO_ADDR 0x7e40 -#define TP_PIO_DATA 0x7e44 -#define TP_MIB_INDEX 0x7e50 -#define TP_MIB_DATA 0x7e54 -#define TP_INT_CAUSE 0x7e74 -#define FLMTXFLSTEMPTY 0x40000000U - -#define TP_INGRESS_CONFIG 0x141 -#define VNIC 0x00000800U -#define CSUM_HAS_PSEUDO_HDR 0x00000400U -#define RM_OVLAN 0x00000200U -#define LOOKUPEVERYPKT 0x00000100U - -#define TP_MIB_MAC_IN_ERR_0 0x0 -#define TP_MIB_TCP_OUT_RST 0xc -#define TP_MIB_TCP_IN_SEG_HI 0x10 -#define TP_MIB_TCP_IN_SEG_LO 0x11 -#define TP_MIB_TCP_OUT_SEG_HI 0x12 -#define TP_MIB_TCP_OUT_SEG_LO 0x13 -#define TP_MIB_TCP_RXT_SEG_HI 0x14 -#define TP_MIB_TCP_RXT_SEG_LO 0x15 -#define TP_MIB_TNL_CNG_DROP_0 0x18 -#define TP_MIB_TCP_V6IN_ERR_0 0x28 -#define TP_MIB_TCP_V6OUT_RST 0x2c -#define TP_MIB_OFD_ARP_DROP 0x36 -#define TP_MIB_TNL_DROP_0 0x44 -#define TP_MIB_OFD_VLN_DROP_0 0x58 - -#define ULP_TX_INT_CAUSE 0x8dcc -#define PBL_BOUND_ERR_CH3 0x80000000U -#define PBL_BOUND_ERR_CH2 0x40000000U -#define PBL_BOUND_ERR_CH1 0x20000000U -#define PBL_BOUND_ERR_CH0 0x10000000U - -#define PM_RX_INT_CAUSE 0x8fdc -#define ZERO_E_CMD_ERROR 0x00400000U -#define PMRX_FRAMING_ERROR 0x003ffff0U -#define OCSPI_PAR_ERROR 0x00000008U -#define DB_OPTIONS_PAR_ERROR 0x00000004U -#define IESPI_PAR_ERROR 0x00000002U -#define E_PCMD_PAR_ERROR 0x00000001U - -#define PM_TX_INT_CAUSE 0x8ffc -#define PCMD_LEN_OVFL0 0x80000000U -#define PCMD_LEN_OVFL1 0x40000000U -#define PCMD_LEN_OVFL2 0x20000000U -#define ZERO_C_CMD_ERROR 0x10000000U -#define PMTX_FRAMING_ERROR 0x0ffffff0U -#define OESPI_PAR_ERROR 0x00000008U -#define ICSPI_PAR_ERROR 0x00000002U -#define C_PCMD_PAR_ERROR 0x00000001U - -#define MPS_PORT_STAT_TX_PORT_BYTES_L 0x400 -#define MPS_PORT_STAT_TX_PORT_BYTES_H 0x404 -#define MPS_PORT_STAT_TX_PORT_FRAMES_L 0x408 -#define MPS_PORT_STAT_TX_PORT_FRAMES_H 0x40c -#define MPS_PORT_STAT_TX_PORT_BCAST_L 0x410 -#define MPS_PORT_STAT_TX_PORT_BCAST_H 0x414 -#define MPS_PORT_STAT_TX_PORT_MCAST_L 0x418 -#define MPS_PORT_STAT_TX_PORT_MCAST_H 0x41c -#define MPS_PORT_STAT_TX_PORT_UCAST_L 0x420 -#define MPS_PORT_STAT_TX_PORT_UCAST_H 0x424 -#define MPS_PORT_STAT_TX_PORT_ERROR_L 0x428 -#define MPS_PORT_STAT_TX_PORT_ERROR_H 0x42c -#define MPS_PORT_STAT_TX_PORT_64B_L 0x430 -#define MPS_PORT_STAT_TX_PORT_64B_H 0x434 -#define MPS_PORT_STAT_TX_PORT_65B_127B_L 0x438 -#define MPS_PORT_STAT_TX_PORT_65B_127B_H 0x43c -#define MPS_PORT_STAT_TX_PORT_128B_255B_L 0x440 -#define MPS_PORT_STAT_TX_PORT_128B_255B_H 0x444 -#define MPS_PORT_STAT_TX_PORT_256B_511B_L 0x448 -#define MPS_PORT_STAT_TX_PORT_256B_511B_H 0x44c -#define MPS_PORT_STAT_TX_PORT_512B_1023B_L 0x450 -#define MPS_PORT_STAT_TX_PORT_512B_1023B_H 0x454 -#define MPS_PORT_STAT_TX_PORT_1024B_1518B_L 0x458 -#define MPS_PORT_STAT_TX_PORT_1024B_1518B_H 0x45c -#define MPS_PORT_STAT_TX_PORT_1519B_MAX_L 0x460 -#define MPS_PORT_STAT_TX_PORT_1519B_MAX_H 0x464 -#define MPS_PORT_STAT_TX_PORT_DROP_L 0x468 -#define MPS_PORT_STAT_TX_PORT_DROP_H 0x46c -#define MPS_PORT_STAT_TX_PORT_PAUSE_L 0x470 -#define MPS_PORT_STAT_TX_PORT_PAUSE_H 0x474 -#define MPS_PORT_STAT_TX_PORT_PPP0_L 0x478 -#define MPS_PORT_STAT_TX_PORT_PPP0_H 0x47c -#define MPS_PORT_STAT_TX_PORT_PPP1_L 0x480 -#define MPS_PORT_STAT_TX_PORT_PPP1_H 0x484 -#define MPS_PORT_STAT_TX_PORT_PPP2_L 0x488 -#define MPS_PORT_STAT_TX_PORT_PPP2_H 0x48c -#define MPS_PORT_STAT_TX_PORT_PPP3_L 0x490 -#define MPS_PORT_STAT_TX_PORT_PPP3_H 0x494 -#define MPS_PORT_STAT_TX_PORT_PPP4_L 0x498 -#define MPS_PORT_STAT_TX_PORT_PPP4_H 0x49c -#define MPS_PORT_STAT_TX_PORT_PPP5_L 0x4a0 -#define MPS_PORT_STAT_TX_PORT_PPP5_H 0x4a4 -#define MPS_PORT_STAT_TX_PORT_PPP6_L 0x4a8 -#define MPS_PORT_STAT_TX_PORT_PPP6_H 0x4ac -#define MPS_PORT_STAT_TX_PORT_PPP7_L 0x4b0 -#define MPS_PORT_STAT_TX_PORT_PPP7_H 0x4b4 -#define MPS_PORT_STAT_LB_PORT_BYTES_L 0x4c0 -#define MPS_PORT_STAT_LB_PORT_BYTES_H 0x4c4 -#define MPS_PORT_STAT_LB_PORT_FRAMES_L 0x4c8 -#define MPS_PORT_STAT_LB_PORT_FRAMES_H 0x4cc -#define MPS_PORT_STAT_LB_PORT_BCAST_L 0x4d0 -#define MPS_PORT_STAT_LB_PORT_BCAST_H 0x4d4 -#define MPS_PORT_STAT_LB_PORT_MCAST_L 0x4d8 -#define MPS_PORT_STAT_LB_PORT_MCAST_H 0x4dc -#define MPS_PORT_STAT_LB_PORT_UCAST_L 0x4e0 -#define MPS_PORT_STAT_LB_PORT_UCAST_H 0x4e4 -#define MPS_PORT_STAT_LB_PORT_ERROR_L 0x4e8 -#define MPS_PORT_STAT_LB_PORT_ERROR_H 0x4ec -#define MPS_PORT_STAT_LB_PORT_64B_L 0x4f0 -#define MPS_PORT_STAT_LB_PORT_64B_H 0x4f4 -#define MPS_PORT_STAT_LB_PORT_65B_127B_L 0x4f8 -#define MPS_PORT_STAT_LB_PORT_65B_127B_H 0x4fc -#define MPS_PORT_STAT_LB_PORT_128B_255B_L 0x500 -#define MPS_PORT_STAT_LB_PORT_128B_255B_H 0x504 -#define MPS_PORT_STAT_LB_PORT_256B_511B_L 0x508 -#define MPS_PORT_STAT_LB_PORT_256B_511B_H 0x50c -#define MPS_PORT_STAT_LB_PORT_512B_1023B_L 0x510 -#define MPS_PORT_STAT_LB_PORT_512B_1023B_H 0x514 -#define MPS_PORT_STAT_LB_PORT_1024B_1518B_L 0x518 -#define MPS_PORT_STAT_LB_PORT_1024B_1518B_H 0x51c -#define MPS_PORT_STAT_LB_PORT_1519B_MAX_L 0x520 -#define MPS_PORT_STAT_LB_PORT_1519B_MAX_H 0x524 -#define MPS_PORT_STAT_LB_PORT_DROP_FRAMES 0x528 -#define MPS_PORT_STAT_RX_PORT_BYTES_L 0x540 -#define MPS_PORT_STAT_RX_PORT_BYTES_H 0x544 -#define MPS_PORT_STAT_RX_PORT_FRAMES_L 0x548 -#define MPS_PORT_STAT_RX_PORT_FRAMES_H 0x54c -#define MPS_PORT_STAT_RX_PORT_BCAST_L 0x550 -#define MPS_PORT_STAT_RX_PORT_BCAST_H 0x554 -#define MPS_PORT_STAT_RX_PORT_MCAST_L 0x558 -#define MPS_PORT_STAT_RX_PORT_MCAST_H 0x55c -#define MPS_PORT_STAT_RX_PORT_UCAST_L 0x560 -#define MPS_PORT_STAT_RX_PORT_UCAST_H 0x564 -#define MPS_PORT_STAT_RX_PORT_MTU_ERROR_L 0x568 -#define MPS_PORT_STAT_RX_PORT_MTU_ERROR_H 0x56c -#define MPS_PORT_STAT_RX_PORT_MTU_CRC_ERROR_L 0x570 -#define MPS_PORT_STAT_RX_PORT_MTU_CRC_ERROR_H 0x574 -#define MPS_PORT_STAT_RX_PORT_CRC_ERROR_L 0x578 -#define MPS_PORT_STAT_RX_PORT_CRC_ERROR_H 0x57c -#define MPS_PORT_STAT_RX_PORT_LEN_ERROR_L 0x580 -#define MPS_PORT_STAT_RX_PORT_LEN_ERROR_H 0x584 -#define MPS_PORT_STAT_RX_PORT_SYM_ERROR_L 0x588 -#define MPS_PORT_STAT_RX_PORT_SYM_ERROR_H 0x58c -#define MPS_PORT_STAT_RX_PORT_64B_L 0x590 -#define MPS_PORT_STAT_RX_PORT_64B_H 0x594 -#define MPS_PORT_STAT_RX_PORT_65B_127B_L 0x598 -#define MPS_PORT_STAT_RX_PORT_65B_127B_H 0x59c -#define MPS_PORT_STAT_RX_PORT_128B_255B_L 0x5a0 -#define MPS_PORT_STAT_RX_PORT_128B_255B_H 0x5a4 -#define MPS_PORT_STAT_RX_PORT_256B_511B_L 0x5a8 -#define MPS_PORT_STAT_RX_PORT_256B_511B_H 0x5ac -#define MPS_PORT_STAT_RX_PORT_512B_1023B_L 0x5b0 -#define MPS_PORT_STAT_RX_PORT_512B_1023B_H 0x5b4 -#define MPS_PORT_STAT_RX_PORT_1024B_1518B_L 0x5b8 -#define MPS_PORT_STAT_RX_PORT_1024B_1518B_H 0x5bc -#define MPS_PORT_STAT_RX_PORT_1519B_MAX_L 0x5c0 -#define MPS_PORT_STAT_RX_PORT_1519B_MAX_H 0x5c4 -#define MPS_PORT_STAT_RX_PORT_PAUSE_L 0x5c8 -#define MPS_PORT_STAT_RX_PORT_PAUSE_H 0x5cc -#define MPS_PORT_STAT_RX_PORT_PPP0_L 0x5d0 -#define MPS_PORT_STAT_RX_PORT_PPP0_H 0x5d4 -#define MPS_PORT_STAT_RX_PORT_PPP1_L 0x5d8 -#define MPS_PORT_STAT_RX_PORT_PPP1_H 0x5dc -#define MPS_PORT_STAT_RX_PORT_PPP2_L 0x5e0 -#define MPS_PORT_STAT_RX_PORT_PPP2_H 0x5e4 -#define MPS_PORT_STAT_RX_PORT_PPP3_L 0x5e8 -#define MPS_PORT_STAT_RX_PORT_PPP3_H 0x5ec -#define MPS_PORT_STAT_RX_PORT_PPP4_L 0x5f0 -#define MPS_PORT_STAT_RX_PORT_PPP4_H 0x5f4 -#define MPS_PORT_STAT_RX_PORT_PPP5_L 0x5f8 -#define MPS_PORT_STAT_RX_PORT_PPP5_H 0x5fc -#define MPS_PORT_STAT_RX_PORT_PPP6_L 0x600 -#define MPS_PORT_STAT_RX_PORT_PPP6_H 0x604 -#define MPS_PORT_STAT_RX_PORT_PPP7_L 0x608 -#define MPS_PORT_STAT_RX_PORT_PPP7_H 0x60c -#define MPS_PORT_STAT_RX_PORT_LESS_64B_L 0x610 -#define MPS_PORT_STAT_RX_PORT_LESS_64B_H 0x614 -#define MPS_CMN_CTL 0x9000 -#define NUMPORTS_MASK 0x00000003U -#define NUMPORTS_SHIFT 0 -#define NUMPORTS_GET(x) (((x) & NUMPORTS_MASK) >> NUMPORTS_SHIFT) - -#define MPS_INT_CAUSE 0x9008 -#define STATINT 0x00000020U -#define TXINT 0x00000010U -#define RXINT 0x00000008U -#define TRCINT 0x00000004U -#define CLSINT 0x00000002U -#define PLINT 0x00000001U - -#define MPS_TX_INT_CAUSE 0x9408 -#define PORTERR 0x00010000U -#define FRMERR 0x00008000U -#define SECNTERR 0x00004000U -#define BUBBLE 0x00002000U -#define TXDESCFIFO 0x00001e00U -#define TXDATAFIFO 0x000001e0U -#define NCSIFIFO 0x00000010U -#define TPFIFO 0x0000000fU - -#define MPS_STAT_PERR_INT_CAUSE_SRAM 0x9614 -#define MPS_STAT_PERR_INT_CAUSE_TX_FIFO 0x9620 -#define MPS_STAT_PERR_INT_CAUSE_RX_FIFO 0x962c - -#define MPS_STAT_RX_BG_0_MAC_DROP_FRAME_L 0x9640 -#define MPS_STAT_RX_BG_0_MAC_DROP_FRAME_H 0x9644 -#define MPS_STAT_RX_BG_1_MAC_DROP_FRAME_L 0x9648 -#define MPS_STAT_RX_BG_1_MAC_DROP_FRAME_H 0x964c -#define MPS_STAT_RX_BG_2_MAC_DROP_FRAME_L 0x9650 -#define MPS_STAT_RX_BG_2_MAC_DROP_FRAME_H 0x9654 -#define MPS_STAT_RX_BG_3_MAC_DROP_FRAME_L 0x9658 -#define MPS_STAT_RX_BG_3_MAC_DROP_FRAME_H 0x965c -#define MPS_STAT_RX_BG_0_LB_DROP_FRAME_L 0x9660 -#define MPS_STAT_RX_BG_0_LB_DROP_FRAME_H 0x9664 -#define MPS_STAT_RX_BG_1_LB_DROP_FRAME_L 0x9668 -#define MPS_STAT_RX_BG_1_LB_DROP_FRAME_H 0x966c -#define MPS_STAT_RX_BG_2_LB_DROP_FRAME_L 0x9670 -#define MPS_STAT_RX_BG_2_LB_DROP_FRAME_H 0x9674 -#define MPS_STAT_RX_BG_3_LB_DROP_FRAME_L 0x9678 -#define MPS_STAT_RX_BG_3_LB_DROP_FRAME_H 0x967c -#define MPS_STAT_RX_BG_0_MAC_TRUNC_FRAME_L 0x9680 -#define MPS_STAT_RX_BG_0_MAC_TRUNC_FRAME_H 0x9684 -#define MPS_STAT_RX_BG_1_MAC_TRUNC_FRAME_L 0x9688 -#define MPS_STAT_RX_BG_1_MAC_TRUNC_FRAME_H 0x968c -#define MPS_STAT_RX_BG_2_MAC_TRUNC_FRAME_L 0x9690 -#define MPS_STAT_RX_BG_2_MAC_TRUNC_FRAME_H 0x9694 -#define MPS_STAT_RX_BG_3_MAC_TRUNC_FRAME_L 0x9698 -#define MPS_STAT_RX_BG_3_MAC_TRUNC_FRAME_H 0x969c -#define MPS_STAT_RX_BG_0_LB_TRUNC_FRAME_L 0x96a0 -#define MPS_STAT_RX_BG_0_LB_TRUNC_FRAME_H 0x96a4 -#define MPS_STAT_RX_BG_1_LB_TRUNC_FRAME_L 0x96a8 -#define MPS_STAT_RX_BG_1_LB_TRUNC_FRAME_H 0x96ac -#define MPS_STAT_RX_BG_2_LB_TRUNC_FRAME_L 0x96b0 -#define MPS_STAT_RX_BG_2_LB_TRUNC_FRAME_H 0x96b4 -#define MPS_STAT_RX_BG_3_LB_TRUNC_FRAME_L 0x96b8 -#define MPS_STAT_RX_BG_3_LB_TRUNC_FRAME_H 0x96bc -#define MPS_TRC_CFG 0x9800 -#define TRCFIFOEMPTY 0x00000010U -#define TRCIGNOREDROPINPUT 0x00000008U -#define TRCKEEPDUPLICATES 0x00000004U -#define TRCEN 0x00000002U -#define TRCMULTIFILTER 0x00000001U - -#define MPS_TRC_RSS_CONTROL 0x9808 -#define RSSCONTROL_MASK 0x00ff0000U -#define RSSCONTROL_SHIFT 16 -#define RSSCONTROL(x) ((x) << RSSCONTROL_SHIFT) -#define QUEUENUMBER_MASK 0x0000ffffU -#define QUEUENUMBER_SHIFT 0 -#define QUEUENUMBER(x) ((x) << QUEUENUMBER_SHIFT) - -#define MPS_TRC_FILTER_MATCH_CTL_A 0x9810 -#define TFINVERTMATCH 0x01000000U -#define TFPKTTOOLARGE 0x00800000U -#define TFEN 0x00400000U -#define TFPORT_MASK 0x003c0000U -#define TFPORT_SHIFT 18 -#define TFPORT(x) ((x) << TFPORT_SHIFT) -#define TFPORT_GET(x) (((x) & TFPORT_MASK) >> TFPORT_SHIFT) -#define TFDROP 0x00020000U -#define TFSOPEOPERR 0x00010000U -#define TFLENGTH_MASK 0x00001f00U -#define TFLENGTH_SHIFT 8 -#define TFLENGTH(x) ((x) << TFLENGTH_SHIFT) -#define TFLENGTH_GET(x) (((x) & TFLENGTH_MASK) >> TFLENGTH_SHIFT) -#define TFOFFSET_MASK 0x0000001fU -#define TFOFFSET_SHIFT 0 -#define TFOFFSET(x) ((x) << TFOFFSET_SHIFT) -#define TFOFFSET_GET(x) (((x) & TFOFFSET_MASK) >> TFOFFSET_SHIFT) - -#define MPS_TRC_FILTER_MATCH_CTL_B 0x9820 -#define TFMINPKTSIZE_MASK 0x01ff0000U -#define TFMINPKTSIZE_SHIFT 16 -#define TFMINPKTSIZE(x) ((x) << TFMINPKTSIZE_SHIFT) -#define TFMINPKTSIZE_GET(x) (((x) & TFMINPKTSIZE_MASK) >> TFMINPKTSIZE_SHIFT) -#define TFCAPTUREMAX_MASK 0x00003fffU -#define TFCAPTUREMAX_SHIFT 0 -#define TFCAPTUREMAX(x) ((x) << TFCAPTUREMAX_SHIFT) -#define TFCAPTUREMAX_GET(x) (((x) & TFCAPTUREMAX_MASK) >> TFCAPTUREMAX_SHIFT) - -#define MPS_TRC_INT_CAUSE 0x985c -#define MISCPERR 0x00000100U -#define PKTFIFO 0x000000f0U -#define FILTMEM 0x0000000fU - -#define MPS_TRC_FILTER0_MATCH 0x9c00 -#define MPS_TRC_FILTER0_DONT_CARE 0x9c80 -#define MPS_TRC_FILTER1_MATCH 0x9d00 -#define MPS_CLS_INT_CAUSE 0xd028 -#define PLERRENB 0x00000008U -#define HASHSRAM 0x00000004U -#define MATCHTCAM 0x00000002U -#define MATCHSRAM 0x00000001U - -#define MPS_RX_PERR_INT_CAUSE 0x11074 - -#define CPL_INTR_CAUSE 0x19054 -#define CIM_OP_MAP_PERR 0x00000020U -#define CIM_OVFL_ERROR 0x00000010U -#define TP_FRAMING_ERROR 0x00000008U -#define SGE_FRAMING_ERROR 0x00000004U -#define CIM_FRAMING_ERROR 0x00000002U -#define ZERO_SWITCH_ERROR 0x00000001U - -#define SMB_INT_CAUSE 0x19090 -#define MSTTXFIFOPARINT 0x00200000U -#define MSTRXFIFOPARINT 0x00100000U -#define SLVFIFOPARINT 0x00080000U - -#define ULP_RX_INT_CAUSE 0x19158 -#define ULP_RX_ISCSI_TAGMASK 0x19164 -#define ULP_RX_ISCSI_PSZ 0x19168 -#define HPZ3_MASK 0x0f000000U -#define HPZ3_SHIFT 24 -#define HPZ3(x) ((x) << HPZ3_SHIFT) -#define HPZ2_MASK 0x000f0000U -#define HPZ2_SHIFT 16 -#define HPZ2(x) ((x) << HPZ2_SHIFT) -#define HPZ1_MASK 0x00000f00U -#define HPZ1_SHIFT 8 -#define HPZ1(x) ((x) << HPZ1_SHIFT) -#define HPZ0_MASK 0x0000000fU -#define HPZ0_SHIFT 0 -#define HPZ0(x) ((x) << HPZ0_SHIFT) - -#define ULP_RX_TDDP_PSZ 0x19178 - -#define SF_DATA 0x193f8 -#define SF_OP 0x193fc -#define BUSY 0x80000000U -#define SF_LOCK 0x00000010U -#define SF_CONT 0x00000008U -#define BYTECNT_MASK 0x00000006U -#define BYTECNT_SHIFT 1 -#define BYTECNT(x) ((x) << BYTECNT_SHIFT) -#define OP_WR 0x00000001U - -#define PL_PF_INT_CAUSE 0x3c0 -#define PFSW 0x00000008U -#define PFSGE 0x00000004U -#define PFCIM 0x00000002U -#define PFMPS 0x00000001U - -#define PL_PF_INT_ENABLE 0x3c4 -#define PL_PF_CTL 0x3c8 -#define SWINT 0x00000001U - -#define PL_WHOAMI 0x19400 -#define SOURCEPF_MASK 0x00000700U -#define SOURCEPF_SHIFT 8 -#define SOURCEPF(x) ((x) << SOURCEPF_SHIFT) -#define SOURCEPF_GET(x) (((x) & SOURCEPF_MASK) >> SOURCEPF_SHIFT) -#define ISVF 0x00000080U -#define VFID_MASK 0x0000007fU -#define VFID_SHIFT 0 -#define VFID(x) ((x) << VFID_SHIFT) -#define VFID_GET(x) (((x) & VFID_MASK) >> VFID_SHIFT) - -#define PL_INT_CAUSE 0x1940c -#define ULP_TX 0x08000000U -#define SGE 0x04000000U -#define HMA 0x02000000U -#define CPL_SWITCH 0x01000000U -#define ULP_RX 0x00800000U -#define PM_RX 0x00400000U -#define PM_TX 0x00200000U -#define MA 0x00100000U -#define TP 0x00080000U -#define LE 0x00040000U -#define EDC1 0x00020000U -#define EDC0 0x00010000U -#define MC 0x00008000U -#define PCIE 0x00004000U -#define PMU 0x00002000U -#define XGMAC_KR1 0x00001000U -#define XGMAC_KR0 0x00000800U -#define XGMAC1 0x00000400U -#define XGMAC0 0x00000200U -#define SMB 0x00000100U -#define SF 0x00000080U -#define PL 0x00000040U -#define NCSI 0x00000020U -#define MPS 0x00000010U -#define MI 0x00000008U -#define DBG 0x00000004U -#define I2CM 0x00000002U -#define CIM 0x00000001U - -#define PL_INT_MAP0 0x19414 -#define PL_RST 0x19428 -#define PIORST 0x00000002U -#define PIORSTMODE 0x00000001U - -#define PL_PL_INT_CAUSE 0x19430 -#define FATALPERR 0x00000010U -#define PERRVFID 0x00000001U - -#define PL_REV 0x1943c - -#define LE_DB_CONFIG 0x19c04 -#define HASHEN 0x00100000U - -#define LE_DB_SERVER_INDEX 0x19c18 -#define LE_DB_ACT_CNT_IPV4 0x19c20 -#define LE_DB_ACT_CNT_IPV6 0x19c24 - -#define LE_DB_INT_CAUSE 0x19c3c -#define REQQPARERR 0x00010000U -#define UNKNOWNCMD 0x00008000U -#define PARITYERR 0x00000040U -#define LIPMISS 0x00000020U -#define LIP0 0x00000010U - -#define LE_DB_TID_HASHBASE 0x19df8 - -#define NCSI_INT_CAUSE 0x1a0d8 -#define CIM_DM_PRTY_ERR 0x00000100U -#define MPS_DM_PRTY_ERR 0x00000080U -#define TXFIFO_PRTY_ERR 0x00000002U -#define RXFIFO_PRTY_ERR 0x00000001U - -#define XGMAC_PORT_CFG2 0x1018 -#define PATEN 0x00040000U -#define MAGICEN 0x00020000U - -#define XGMAC_PORT_MAGIC_MACID_LO 0x1024 -#define XGMAC_PORT_MAGIC_MACID_HI 0x1028 - -#define XGMAC_PORT_EPIO_DATA0 0x10c0 -#define XGMAC_PORT_EPIO_DATA1 0x10c4 -#define XGMAC_PORT_EPIO_DATA2 0x10c8 -#define XGMAC_PORT_EPIO_DATA3 0x10cc -#define XGMAC_PORT_EPIO_OP 0x10d0 -#define EPIOWR 0x00000100U -#define ADDRESS_MASK 0x000000ffU -#define ADDRESS_SHIFT 0 -#define ADDRESS(x) ((x) << ADDRESS_SHIFT) - -#define XGMAC_PORT_INT_CAUSE 0x10dc -#endif /* __T4_REGS_H */ diff --git a/drivers/net/cxgb4/t4fw_api.h b/drivers/net/cxgb4/t4fw_api.h deleted file mode 100644 index edcfd7ec7802..000000000000 --- a/drivers/net/cxgb4/t4fw_api.h +++ /dev/null @@ -1,1623 +0,0 @@ -/* - * This file is part of the Chelsio T4 Ethernet driver for Linux. - * - * Copyright (c) 2009-2010 Chelsio Communications, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef _T4FW_INTERFACE_H_ -#define _T4FW_INTERFACE_H_ - -#define FW_T4VF_SGE_BASE_ADDR 0x0000 -#define FW_T4VF_MPS_BASE_ADDR 0x0100 -#define FW_T4VF_PL_BASE_ADDR 0x0200 -#define FW_T4VF_MBDATA_BASE_ADDR 0x0240 -#define FW_T4VF_CIM_BASE_ADDR 0x0300 - -enum fw_wr_opcodes { - FW_FILTER_WR = 0x02, - FW_ULPTX_WR = 0x04, - FW_TP_WR = 0x05, - FW_ETH_TX_PKT_WR = 0x08, - FW_FLOWC_WR = 0x0a, - FW_OFLD_TX_DATA_WR = 0x0b, - FW_CMD_WR = 0x10, - FW_ETH_TX_PKT_VM_WR = 0x11, - FW_RI_RES_WR = 0x0c, - FW_RI_INIT_WR = 0x0d, - FW_RI_RDMA_WRITE_WR = 0x14, - FW_RI_SEND_WR = 0x15, - FW_RI_RDMA_READ_WR = 0x16, - FW_RI_RECV_WR = 0x17, - FW_RI_BIND_MW_WR = 0x18, - FW_RI_FR_NSMR_WR = 0x19, - FW_RI_INV_LSTAG_WR = 0x1a, - FW_LASTC2E_WR = 0x40 -}; - -struct fw_wr_hdr { - __be32 hi; - __be32 lo; -}; - -#define FW_WR_OP(x) ((x) << 24) -#define FW_WR_ATOMIC(x) ((x) << 23) -#define FW_WR_FLUSH(x) ((x) << 22) -#define FW_WR_COMPL(x) ((x) << 21) -#define FW_WR_IMMDLEN_MASK 0xff -#define FW_WR_IMMDLEN(x) ((x) << 0) - -#define FW_WR_EQUIQ (1U << 31) -#define FW_WR_EQUEQ (1U << 30) -#define FW_WR_FLOWID(x) ((x) << 8) -#define FW_WR_LEN16(x) ((x) << 0) - -struct fw_ulptx_wr { - __be32 op_to_compl; - __be32 flowid_len16; - u64 cookie; -}; - -struct fw_tp_wr { - __be32 op_to_immdlen; - __be32 flowid_len16; - u64 cookie; -}; - -struct fw_eth_tx_pkt_wr { - __be32 op_immdlen; - __be32 equiq_to_len16; - __be64 r3; -}; - -enum fw_flowc_mnem { - FW_FLOWC_MNEM_PFNVFN, /* PFN [15:8] VFN [7:0] */ - FW_FLOWC_MNEM_CH, - FW_FLOWC_MNEM_PORT, - FW_FLOWC_MNEM_IQID, - FW_FLOWC_MNEM_SNDNXT, - FW_FLOWC_MNEM_RCVNXT, - FW_FLOWC_MNEM_SNDBUF, - FW_FLOWC_MNEM_MSS, -}; - -struct fw_flowc_mnemval { - u8 mnemonic; - u8 r4[3]; - __be32 val; -}; - -struct fw_flowc_wr { - __be32 op_to_nparams; -#define FW_FLOWC_WR_NPARAMS(x) ((x) << 0) - __be32 flowid_len16; - struct fw_flowc_mnemval mnemval[0]; -}; - -struct fw_ofld_tx_data_wr { - __be32 op_to_immdlen; - __be32 flowid_len16; - __be32 plen; - __be32 tunnel_to_proxy; -#define FW_OFLD_TX_DATA_WR_TUNNEL(x) ((x) << 19) -#define FW_OFLD_TX_DATA_WR_SAVE(x) ((x) << 18) -#define FW_OFLD_TX_DATA_WR_FLUSH(x) ((x) << 17) -#define FW_OFLD_TX_DATA_WR_URGENT(x) ((x) << 16) -#define FW_OFLD_TX_DATA_WR_MORE(x) ((x) << 15) -#define FW_OFLD_TX_DATA_WR_SHOVE(x) ((x) << 14) -#define FW_OFLD_TX_DATA_WR_ULPMODE(x) ((x) << 10) -#define FW_OFLD_TX_DATA_WR_ULPSUBMODE(x) ((x) << 6) -}; - -struct fw_cmd_wr { - __be32 op_dma; -#define FW_CMD_WR_DMA (1U << 17) - __be32 len16_pkd; - __be64 cookie_daddr; -}; - -struct fw_eth_tx_pkt_vm_wr { - __be32 op_immdlen; - __be32 equiq_to_len16; - __be32 r3[2]; - u8 ethmacdst[6]; - u8 ethmacsrc[6]; - __be16 ethtype; - __be16 vlantci; -}; - -#define FW_CMD_MAX_TIMEOUT 3000 - -enum fw_cmd_opcodes { - FW_LDST_CMD = 0x01, - FW_RESET_CMD = 0x03, - FW_HELLO_CMD = 0x04, - FW_BYE_CMD = 0x05, - FW_INITIALIZE_CMD = 0x06, - FW_CAPS_CONFIG_CMD = 0x07, - FW_PARAMS_CMD = 0x08, - FW_PFVF_CMD = 0x09, - FW_IQ_CMD = 0x10, - FW_EQ_MNGT_CMD = 0x11, - FW_EQ_ETH_CMD = 0x12, - FW_EQ_CTRL_CMD = 0x13, - FW_EQ_OFLD_CMD = 0x21, - FW_VI_CMD = 0x14, - FW_VI_MAC_CMD = 0x15, - FW_VI_RXMODE_CMD = 0x16, - FW_VI_ENABLE_CMD = 0x17, - FW_ACL_MAC_CMD = 0x18, - FW_ACL_VLAN_CMD = 0x19, - FW_VI_STATS_CMD = 0x1a, - FW_PORT_CMD = 0x1b, - FW_PORT_STATS_CMD = 0x1c, - FW_PORT_LB_STATS_CMD = 0x1d, - FW_PORT_TRACE_CMD = 0x1e, - FW_PORT_TRACE_MMAP_CMD = 0x1f, - FW_RSS_IND_TBL_CMD = 0x20, - FW_RSS_GLB_CONFIG_CMD = 0x22, - FW_RSS_VI_CONFIG_CMD = 0x23, - FW_LASTC2E_CMD = 0x40, - FW_ERROR_CMD = 0x80, - FW_DEBUG_CMD = 0x81, -}; - -enum fw_cmd_cap { - FW_CMD_CAP_PF = 0x01, - FW_CMD_CAP_DMAQ = 0x02, - FW_CMD_CAP_PORT = 0x04, - FW_CMD_CAP_PORTPROMISC = 0x08, - FW_CMD_CAP_PORTSTATS = 0x10, - FW_CMD_CAP_VF = 0x80, -}; - -/* - * Generic command header flit0 - */ -struct fw_cmd_hdr { - __be32 hi; - __be32 lo; -}; - -#define FW_CMD_OP(x) ((x) << 24) -#define FW_CMD_OP_GET(x) (((x) >> 24) & 0xff) -#define FW_CMD_REQUEST (1U << 23) -#define FW_CMD_READ (1U << 22) -#define FW_CMD_WRITE (1U << 21) -#define FW_CMD_EXEC (1U << 20) -#define FW_CMD_RAMASK(x) ((x) << 20) -#define FW_CMD_RETVAL(x) ((x) << 8) -#define FW_CMD_RETVAL_GET(x) (((x) >> 8) & 0xff) -#define FW_CMD_LEN16(x) ((x) << 0) - -enum fw_ldst_addrspc { - FW_LDST_ADDRSPC_FIRMWARE = 0x0001, - FW_LDST_ADDRSPC_SGE_EGRC = 0x0008, - FW_LDST_ADDRSPC_SGE_INGC = 0x0009, - FW_LDST_ADDRSPC_SGE_FLMC = 0x000a, - FW_LDST_ADDRSPC_SGE_CONMC = 0x000b, - FW_LDST_ADDRSPC_TP_PIO = 0x0010, - FW_LDST_ADDRSPC_TP_TM_PIO = 0x0011, - FW_LDST_ADDRSPC_TP_MIB = 0x0012, - FW_LDST_ADDRSPC_MDIO = 0x0018, - FW_LDST_ADDRSPC_MPS = 0x0020, - FW_LDST_ADDRSPC_FUNC = 0x0028 -}; - -enum fw_ldst_mps_fid { - FW_LDST_MPS_ATRB, - FW_LDST_MPS_RPLC -}; - -enum fw_ldst_func_access_ctl { - FW_LDST_FUNC_ACC_CTL_VIID, - FW_LDST_FUNC_ACC_CTL_FID -}; - -enum fw_ldst_func_mod_index { - FW_LDST_FUNC_MPS -}; - -struct fw_ldst_cmd { - __be32 op_to_addrspace; -#define FW_LDST_CMD_ADDRSPACE(x) ((x) << 0) - __be32 cycles_to_len16; - union fw_ldst { - struct fw_ldst_addrval { - __be32 addr; - __be32 val; - } addrval; - struct fw_ldst_idctxt { - __be32 physid; - __be32 msg_pkd; - __be32 ctxt_data7; - __be32 ctxt_data6; - __be32 ctxt_data5; - __be32 ctxt_data4; - __be32 ctxt_data3; - __be32 ctxt_data2; - __be32 ctxt_data1; - __be32 ctxt_data0; - } idctxt; - struct fw_ldst_mdio { - __be16 paddr_mmd; - __be16 raddr; - __be16 vctl; - __be16 rval; - } mdio; - struct fw_ldst_mps { - __be16 fid_ctl; - __be16 rplcpf_pkd; - __be32 rplc127_96; - __be32 rplc95_64; - __be32 rplc63_32; - __be32 rplc31_0; - __be32 atrb; - __be16 vlan[16]; - } mps; - struct fw_ldst_func { - u8 access_ctl; - u8 mod_index; - __be16 ctl_id; - __be32 offset; - __be64 data0; - __be64 data1; - } func; - } u; -}; - -#define FW_LDST_CMD_MSG(x) ((x) << 31) -#define FW_LDST_CMD_PADDR(x) ((x) << 8) -#define FW_LDST_CMD_MMD(x) ((x) << 0) -#define FW_LDST_CMD_FID(x) ((x) << 15) -#define FW_LDST_CMD_CTL(x) ((x) << 0) -#define FW_LDST_CMD_RPLCPF(x) ((x) << 0) - -struct fw_reset_cmd { - __be32 op_to_write; - __be32 retval_len16; - __be32 val; - __be32 r3; -}; - -struct fw_hello_cmd { - __be32 op_to_write; - __be32 retval_len16; - __be32 err_to_mbasyncnot; -#define FW_HELLO_CMD_ERR (1U << 31) -#define FW_HELLO_CMD_INIT (1U << 30) -#define FW_HELLO_CMD_MASTERDIS(x) ((x) << 29) -#define FW_HELLO_CMD_MASTERFORCE(x) ((x) << 28) -#define FW_HELLO_CMD_MBMASTER(x) ((x) << 24) -#define FW_HELLO_CMD_MBASYNCNOT(x) ((x) << 20) - __be32 fwrev; -}; - -struct fw_bye_cmd { - __be32 op_to_write; - __be32 retval_len16; - __be64 r3; -}; - -struct fw_initialize_cmd { - __be32 op_to_write; - __be32 retval_len16; - __be64 r3; -}; - -enum fw_caps_config_hm { - FW_CAPS_CONFIG_HM_PCIE = 0x00000001, - FW_CAPS_CONFIG_HM_PL = 0x00000002, - FW_CAPS_CONFIG_HM_SGE = 0x00000004, - FW_CAPS_CONFIG_HM_CIM = 0x00000008, - FW_CAPS_CONFIG_HM_ULPTX = 0x00000010, - FW_CAPS_CONFIG_HM_TP = 0x00000020, - FW_CAPS_CONFIG_HM_ULPRX = 0x00000040, - FW_CAPS_CONFIG_HM_PMRX = 0x00000080, - FW_CAPS_CONFIG_HM_PMTX = 0x00000100, - FW_CAPS_CONFIG_HM_MC = 0x00000200, - FW_CAPS_CONFIG_HM_LE = 0x00000400, - FW_CAPS_CONFIG_HM_MPS = 0x00000800, - FW_CAPS_CONFIG_HM_XGMAC = 0x00001000, - FW_CAPS_CONFIG_HM_CPLSWITCH = 0x00002000, - FW_CAPS_CONFIG_HM_T4DBG = 0x00004000, - FW_CAPS_CONFIG_HM_MI = 0x00008000, - FW_CAPS_CONFIG_HM_I2CM = 0x00010000, - FW_CAPS_CONFIG_HM_NCSI = 0x00020000, - FW_CAPS_CONFIG_HM_SMB = 0x00040000, - FW_CAPS_CONFIG_HM_MA = 0x00080000, - FW_CAPS_CONFIG_HM_EDRAM = 0x00100000, - FW_CAPS_CONFIG_HM_PMU = 0x00200000, - FW_CAPS_CONFIG_HM_UART = 0x00400000, - FW_CAPS_CONFIG_HM_SF = 0x00800000, -}; - -enum fw_caps_config_nbm { - FW_CAPS_CONFIG_NBM_IPMI = 0x00000001, - FW_CAPS_CONFIG_NBM_NCSI = 0x00000002, -}; - -enum fw_caps_config_link { - FW_CAPS_CONFIG_LINK_PPP = 0x00000001, - FW_CAPS_CONFIG_LINK_QFC = 0x00000002, - FW_CAPS_CONFIG_LINK_DCBX = 0x00000004, -}; - -enum fw_caps_config_switch { - FW_CAPS_CONFIG_SWITCH_INGRESS = 0x00000001, - FW_CAPS_CONFIG_SWITCH_EGRESS = 0x00000002, -}; - -enum fw_caps_config_nic { - FW_CAPS_CONFIG_NIC = 0x00000001, - FW_CAPS_CONFIG_NIC_VM = 0x00000002, -}; - -enum fw_caps_config_ofld { - FW_CAPS_CONFIG_OFLD = 0x00000001, -}; - -enum fw_caps_config_rdma { - FW_CAPS_CONFIG_RDMA_RDDP = 0x00000001, - FW_CAPS_CONFIG_RDMA_RDMAC = 0x00000002, -}; - -enum fw_caps_config_iscsi { - FW_CAPS_CONFIG_ISCSI_INITIATOR_PDU = 0x00000001, - FW_CAPS_CONFIG_ISCSI_TARGET_PDU = 0x00000002, - FW_CAPS_CONFIG_ISCSI_INITIATOR_CNXOFLD = 0x00000004, - FW_CAPS_CONFIG_ISCSI_TARGET_CNXOFLD = 0x00000008, -}; - -enum fw_caps_config_fcoe { - FW_CAPS_CONFIG_FCOE_INITIATOR = 0x00000001, - FW_CAPS_CONFIG_FCOE_TARGET = 0x00000002, -}; - -struct fw_caps_config_cmd { - __be32 op_to_write; - __be32 retval_len16; - __be32 r2; - __be32 hwmbitmap; - __be16 nbmcaps; - __be16 linkcaps; - __be16 switchcaps; - __be16 r3; - __be16 niccaps; - __be16 ofldcaps; - __be16 rdmacaps; - __be16 r4; - __be16 iscsicaps; - __be16 fcoecaps; - __be32 r5; - __be64 r6; -}; - -/* - * params command mnemonics - */ -enum fw_params_mnem { - FW_PARAMS_MNEM_DEV = 1, /* device params */ - FW_PARAMS_MNEM_PFVF = 2, /* function params */ - FW_PARAMS_MNEM_REG = 3, /* limited register access */ - FW_PARAMS_MNEM_DMAQ = 4, /* dma queue params */ - FW_PARAMS_MNEM_LAST -}; - -/* - * device parameters - */ -enum fw_params_param_dev { - FW_PARAMS_PARAM_DEV_CCLK = 0x00, /* chip core clock in khz */ - FW_PARAMS_PARAM_DEV_PORTVEC = 0x01, /* the port vector */ - FW_PARAMS_PARAM_DEV_NTID = 0x02, /* reads the number of TIDs - * allocated by the device's - * Lookup Engine - */ - FW_PARAMS_PARAM_DEV_FLOWC_BUFFIFO_SZ = 0x03, - FW_PARAMS_PARAM_DEV_INTVER_NIC = 0x04, - FW_PARAMS_PARAM_DEV_INTVER_VNIC = 0x05, - FW_PARAMS_PARAM_DEV_INTVER_OFLD = 0x06, - FW_PARAMS_PARAM_DEV_INTVER_RI = 0x07, - FW_PARAMS_PARAM_DEV_INTVER_ISCSIPDU = 0x08, - FW_PARAMS_PARAM_DEV_INTVER_ISCSI = 0x09, - FW_PARAMS_PARAM_DEV_INTVER_FCOE = 0x0A, - FW_PARAMS_PARAM_DEV_FWREV = 0x0B, - FW_PARAMS_PARAM_DEV_TPREV = 0x0C, -}; - -/* - * physical and virtual function parameters - */ -enum fw_params_param_pfvf { - FW_PARAMS_PARAM_PFVF_RWXCAPS = 0x00, - FW_PARAMS_PARAM_PFVF_ROUTE_START = 0x01, - FW_PARAMS_PARAM_PFVF_ROUTE_END = 0x02, - FW_PARAMS_PARAM_PFVF_CLIP_START = 0x03, - FW_PARAMS_PARAM_PFVF_CLIP_END = 0x04, - FW_PARAMS_PARAM_PFVF_FILTER_START = 0x05, - FW_PARAMS_PARAM_PFVF_FILTER_END = 0x06, - FW_PARAMS_PARAM_PFVF_SERVER_START = 0x07, - FW_PARAMS_PARAM_PFVF_SERVER_END = 0x08, - FW_PARAMS_PARAM_PFVF_TDDP_START = 0x09, - FW_PARAMS_PARAM_PFVF_TDDP_END = 0x0A, - FW_PARAMS_PARAM_PFVF_ISCSI_START = 0x0B, - FW_PARAMS_PARAM_PFVF_ISCSI_END = 0x0C, - FW_PARAMS_PARAM_PFVF_STAG_START = 0x0D, - FW_PARAMS_PARAM_PFVF_STAG_END = 0x0E, - FW_PARAMS_PARAM_PFVF_RQ_START = 0x1F, - FW_PARAMS_PARAM_PFVF_RQ_END = 0x10, - FW_PARAMS_PARAM_PFVF_PBL_START = 0x11, - FW_PARAMS_PARAM_PFVF_PBL_END = 0x12, - FW_PARAMS_PARAM_PFVF_L2T_START = 0x13, - FW_PARAMS_PARAM_PFVF_L2T_END = 0x14, - FW_PARAMS_PARAM_PFVF_SQRQ_START = 0x15, - FW_PARAMS_PARAM_PFVF_SQRQ_END = 0x16, - FW_PARAMS_PARAM_PFVF_CQ_START = 0x17, - FW_PARAMS_PARAM_PFVF_CQ_END = 0x18, - FW_PARAMS_PARAM_PFVF_SCHEDCLASS_ETH = 0x20, - FW_PARAMS_PARAM_PFVF_VIID = 0x24, - FW_PARAMS_PARAM_PFVF_CPMASK = 0x25, - FW_PARAMS_PARAM_PFVF_OCQ_START = 0x26, - FW_PARAMS_PARAM_PFVF_OCQ_END = 0x27, - FW_PARAMS_PARAM_PFVF_CONM_MAP = 0x28, - FW_PARAMS_PARAM_PFVF_IQFLINT_START = 0x29, - FW_PARAMS_PARAM_PFVF_IQFLINT_END = 0x2A, - FW_PARAMS_PARAM_PFVF_EQ_START = 0x2B, - FW_PARAMS_PARAM_PFVF_EQ_END = 0x2C, -}; - -/* - * dma queue parameters - */ -enum fw_params_param_dmaq { - FW_PARAMS_PARAM_DMAQ_IQ_DCAEN_DCACPU = 0x00, - FW_PARAMS_PARAM_DMAQ_IQ_INTCNTTHRESH = 0x01, - FW_PARAMS_PARAM_DMAQ_EQ_CMPLIQID_MNGT = 0x10, - FW_PARAMS_PARAM_DMAQ_EQ_CMPLIQID_CTRL = 0x11, - FW_PARAMS_PARAM_DMAQ_EQ_SCHEDCLASS_ETH = 0x12, -}; - -#define FW_PARAMS_MNEM(x) ((x) << 24) -#define FW_PARAMS_PARAM_X(x) ((x) << 16) -#define FW_PARAMS_PARAM_Y(x) ((x) << 8) -#define FW_PARAMS_PARAM_Z(x) ((x) << 0) -#define FW_PARAMS_PARAM_XYZ(x) ((x) << 0) -#define FW_PARAMS_PARAM_YZ(x) ((x) << 0) - -struct fw_params_cmd { - __be32 op_to_vfn; - __be32 retval_len16; - struct fw_params_param { - __be32 mnem; - __be32 val; - } param[7]; -}; - -#define FW_PARAMS_CMD_PFN(x) ((x) << 8) -#define FW_PARAMS_CMD_VFN(x) ((x) << 0) - -struct fw_pfvf_cmd { - __be32 op_to_vfn; - __be32 retval_len16; - __be32 niqflint_niq; - __be32 type_to_neq; - __be32 tc_to_nexactf; - __be32 r_caps_to_nethctrl; - __be16 nricq; - __be16 nriqp; - __be32 r4; -}; - -#define FW_PFVF_CMD_PFN(x) ((x) << 8) -#define FW_PFVF_CMD_VFN(x) ((x) << 0) - -#define FW_PFVF_CMD_NIQFLINT(x) ((x) << 20) -#define FW_PFVF_CMD_NIQFLINT_GET(x) (((x) >> 20) & 0xfff) - -#define FW_PFVF_CMD_NIQ(x) ((x) << 0) -#define FW_PFVF_CMD_NIQ_GET(x) (((x) >> 0) & 0xfffff) - -#define FW_PFVF_CMD_TYPE (1 << 31) -#define FW_PFVF_CMD_TYPE_GET(x) (((x) >> 31) & 0x1) - -#define FW_PFVF_CMD_CMASK(x) ((x) << 24) -#define FW_PFVF_CMD_CMASK_MASK 0xf -#define FW_PFVF_CMD_CMASK_GET(x) (((x) >> 24) & FW_PFVF_CMD_CMASK_MASK) - -#define FW_PFVF_CMD_PMASK(x) ((x) << 20) -#define FW_PFVF_CMD_PMASK_MASK 0xf -#define FW_PFVF_CMD_PMASK_GET(x) (((x) >> 20) & FW_PFVF_CMD_PMASK_MASK) - -#define FW_PFVF_CMD_NEQ(x) ((x) << 0) -#define FW_PFVF_CMD_NEQ_GET(x) (((x) >> 0) & 0xfffff) - -#define FW_PFVF_CMD_TC(x) ((x) << 24) -#define FW_PFVF_CMD_TC_GET(x) (((x) >> 24) & 0xff) - -#define FW_PFVF_CMD_NVI(x) ((x) << 16) -#define FW_PFVF_CMD_NVI_GET(x) (((x) >> 16) & 0xff) - -#define FW_PFVF_CMD_NEXACTF(x) ((x) << 0) -#define FW_PFVF_CMD_NEXACTF_GET(x) (((x) >> 0) & 0xffff) - -#define FW_PFVF_CMD_R_CAPS(x) ((x) << 24) -#define FW_PFVF_CMD_R_CAPS_GET(x) (((x) >> 24) & 0xff) - -#define FW_PFVF_CMD_WX_CAPS(x) ((x) << 16) -#define FW_PFVF_CMD_WX_CAPS_GET(x) (((x) >> 16) & 0xff) - -#define FW_PFVF_CMD_NETHCTRL(x) ((x) << 0) -#define FW_PFVF_CMD_NETHCTRL_GET(x) (((x) >> 0) & 0xffff) - -enum fw_iq_type { - FW_IQ_TYPE_FL_INT_CAP, - FW_IQ_TYPE_NO_FL_INT_CAP -}; - -struct fw_iq_cmd { - __be32 op_to_vfn; - __be32 alloc_to_len16; - __be16 physiqid; - __be16 iqid; - __be16 fl0id; - __be16 fl1id; - __be32 type_to_iqandstindex; - __be16 iqdroprss_to_iqesize; - __be16 iqsize; - __be64 iqaddr; - __be32 iqns_to_fl0congen; - __be16 fl0dcaen_to_fl0cidxfthresh; - __be16 fl0size; - __be64 fl0addr; - __be32 fl1cngchmap_to_fl1congen; - __be16 fl1dcaen_to_fl1cidxfthresh; - __be16 fl1size; - __be64 fl1addr; -}; - -#define FW_IQ_CMD_PFN(x) ((x) << 8) -#define FW_IQ_CMD_VFN(x) ((x) << 0) - -#define FW_IQ_CMD_ALLOC (1U << 31) -#define FW_IQ_CMD_FREE (1U << 30) -#define FW_IQ_CMD_MODIFY (1U << 29) -#define FW_IQ_CMD_IQSTART(x) ((x) << 28) -#define FW_IQ_CMD_IQSTOP(x) ((x) << 27) - -#define FW_IQ_CMD_TYPE(x) ((x) << 29) -#define FW_IQ_CMD_IQASYNCH(x) ((x) << 28) -#define FW_IQ_CMD_VIID(x) ((x) << 16) -#define FW_IQ_CMD_IQANDST(x) ((x) << 15) -#define FW_IQ_CMD_IQANUS(x) ((x) << 14) -#define FW_IQ_CMD_IQANUD(x) ((x) << 12) -#define FW_IQ_CMD_IQANDSTINDEX(x) ((x) << 0) - -#define FW_IQ_CMD_IQDROPRSS (1U << 15) -#define FW_IQ_CMD_IQGTSMODE (1U << 14) -#define FW_IQ_CMD_IQPCIECH(x) ((x) << 12) -#define FW_IQ_CMD_IQDCAEN(x) ((x) << 11) -#define FW_IQ_CMD_IQDCACPU(x) ((x) << 6) -#define FW_IQ_CMD_IQINTCNTTHRESH(x) ((x) << 4) -#define FW_IQ_CMD_IQO (1U << 3) -#define FW_IQ_CMD_IQCPRIO(x) ((x) << 2) -#define FW_IQ_CMD_IQESIZE(x) ((x) << 0) - -#define FW_IQ_CMD_IQNS(x) ((x) << 31) -#define FW_IQ_CMD_IQRO(x) ((x) << 30) -#define FW_IQ_CMD_IQFLINTIQHSEN(x) ((x) << 28) -#define FW_IQ_CMD_IQFLINTCONGEN(x) ((x) << 27) -#define FW_IQ_CMD_IQFLINTISCSIC(x) ((x) << 26) -#define FW_IQ_CMD_FL0CNGCHMAP(x) ((x) << 20) -#define FW_IQ_CMD_FL0CACHELOCK(x) ((x) << 15) -#define FW_IQ_CMD_FL0DBP(x) ((x) << 14) -#define FW_IQ_CMD_FL0DATANS(x) ((x) << 13) -#define FW_IQ_CMD_FL0DATARO(x) ((x) << 12) -#define FW_IQ_CMD_FL0CONGCIF(x) ((x) << 11) -#define FW_IQ_CMD_FL0ONCHIP(x) ((x) << 10) -#define FW_IQ_CMD_FL0STATUSPGNS(x) ((x) << 9) -#define FW_IQ_CMD_FL0STATUSPGRO(x) ((x) << 8) -#define FW_IQ_CMD_FL0FETCHNS(x) ((x) << 7) -#define FW_IQ_CMD_FL0FETCHRO(x) ((x) << 6) -#define FW_IQ_CMD_FL0HOSTFCMODE(x) ((x) << 4) -#define FW_IQ_CMD_FL0CPRIO(x) ((x) << 3) -#define FW_IQ_CMD_FL0PADEN (1U << 2) -#define FW_IQ_CMD_FL0PACKEN (1U << 1) -#define FW_IQ_CMD_FL0CONGEN (1U << 0) - -#define FW_IQ_CMD_FL0DCAEN(x) ((x) << 15) -#define FW_IQ_CMD_FL0DCACPU(x) ((x) << 10) -#define FW_IQ_CMD_FL0FBMIN(x) ((x) << 7) -#define FW_IQ_CMD_FL0FBMAX(x) ((x) << 4) -#define FW_IQ_CMD_FL0CIDXFTHRESHO (1U << 3) -#define FW_IQ_CMD_FL0CIDXFTHRESH(x) ((x) << 0) - -#define FW_IQ_CMD_FL1CNGCHMAP(x) ((x) << 20) -#define FW_IQ_CMD_FL1CACHELOCK(x) ((x) << 15) -#define FW_IQ_CMD_FL1DBP(x) ((x) << 14) -#define FW_IQ_CMD_FL1DATANS(x) ((x) << 13) -#define FW_IQ_CMD_FL1DATARO(x) ((x) << 12) -#define FW_IQ_CMD_FL1CONGCIF(x) ((x) << 11) -#define FW_IQ_CMD_FL1ONCHIP(x) ((x) << 10) -#define FW_IQ_CMD_FL1STATUSPGNS(x) ((x) << 9) -#define FW_IQ_CMD_FL1STATUSPGRO(x) ((x) << 8) -#define FW_IQ_CMD_FL1FETCHNS(x) ((x) << 7) -#define FW_IQ_CMD_FL1FETCHRO(x) ((x) << 6) -#define FW_IQ_CMD_FL1HOSTFCMODE(x) ((x) << 4) -#define FW_IQ_CMD_FL1CPRIO(x) ((x) << 3) -#define FW_IQ_CMD_FL1PADEN (1U << 2) -#define FW_IQ_CMD_FL1PACKEN (1U << 1) -#define FW_IQ_CMD_FL1CONGEN (1U << 0) - -#define FW_IQ_CMD_FL1DCAEN(x) ((x) << 15) -#define FW_IQ_CMD_FL1DCACPU(x) ((x) << 10) -#define FW_IQ_CMD_FL1FBMIN(x) ((x) << 7) -#define FW_IQ_CMD_FL1FBMAX(x) ((x) << 4) -#define FW_IQ_CMD_FL1CIDXFTHRESHO (1U << 3) -#define FW_IQ_CMD_FL1CIDXFTHRESH(x) ((x) << 0) - -struct fw_eq_eth_cmd { - __be32 op_to_vfn; - __be32 alloc_to_len16; - __be32 eqid_pkd; - __be32 physeqid_pkd; - __be32 fetchszm_to_iqid; - __be32 dcaen_to_eqsize; - __be64 eqaddr; - __be32 viid_pkd; - __be32 r8_lo; - __be64 r9; -}; - -#define FW_EQ_ETH_CMD_PFN(x) ((x) << 8) -#define FW_EQ_ETH_CMD_VFN(x) ((x) << 0) -#define FW_EQ_ETH_CMD_ALLOC (1U << 31) -#define FW_EQ_ETH_CMD_FREE (1U << 30) -#define FW_EQ_ETH_CMD_MODIFY (1U << 29) -#define FW_EQ_ETH_CMD_EQSTART (1U << 28) -#define FW_EQ_ETH_CMD_EQSTOP (1U << 27) - -#define FW_EQ_ETH_CMD_EQID(x) ((x) << 0) -#define FW_EQ_ETH_CMD_EQID_GET(x) (((x) >> 0) & 0xfffff) -#define FW_EQ_ETH_CMD_PHYSEQID(x) ((x) << 0) -#define FW_EQ_ETH_CMD_PHYSEQID_GET(x) (((x) >> 0) & 0xfffff) - -#define FW_EQ_ETH_CMD_FETCHSZM(x) ((x) << 26) -#define FW_EQ_ETH_CMD_STATUSPGNS(x) ((x) << 25) -#define FW_EQ_ETH_CMD_STATUSPGRO(x) ((x) << 24) -#define FW_EQ_ETH_CMD_FETCHNS(x) ((x) << 23) -#define FW_EQ_ETH_CMD_FETCHRO(x) ((x) << 22) -#define FW_EQ_ETH_CMD_HOSTFCMODE(x) ((x) << 20) -#define FW_EQ_ETH_CMD_CPRIO(x) ((x) << 19) -#define FW_EQ_ETH_CMD_ONCHIP(x) ((x) << 18) -#define FW_EQ_ETH_CMD_PCIECHN(x) ((x) << 16) -#define FW_EQ_ETH_CMD_IQID(x) ((x) << 0) - -#define FW_EQ_ETH_CMD_DCAEN(x) ((x) << 31) -#define FW_EQ_ETH_CMD_DCACPU(x) ((x) << 26) -#define FW_EQ_ETH_CMD_FBMIN(x) ((x) << 23) -#define FW_EQ_ETH_CMD_FBMAX(x) ((x) << 20) -#define FW_EQ_ETH_CMD_CIDXFTHRESHO(x) ((x) << 19) -#define FW_EQ_ETH_CMD_CIDXFTHRESH(x) ((x) << 16) -#define FW_EQ_ETH_CMD_EQSIZE(x) ((x) << 0) - -#define FW_EQ_ETH_CMD_VIID(x) ((x) << 16) - -struct fw_eq_ctrl_cmd { - __be32 op_to_vfn; - __be32 alloc_to_len16; - __be32 cmpliqid_eqid; - __be32 physeqid_pkd; - __be32 fetchszm_to_iqid; - __be32 dcaen_to_eqsize; - __be64 eqaddr; -}; - -#define FW_EQ_CTRL_CMD_PFN(x) ((x) << 8) -#define FW_EQ_CTRL_CMD_VFN(x) ((x) << 0) - -#define FW_EQ_CTRL_CMD_ALLOC (1U << 31) -#define FW_EQ_CTRL_CMD_FREE (1U << 30) -#define FW_EQ_CTRL_CMD_MODIFY (1U << 29) -#define FW_EQ_CTRL_CMD_EQSTART (1U << 28) -#define FW_EQ_CTRL_CMD_EQSTOP (1U << 27) - -#define FW_EQ_CTRL_CMD_CMPLIQID(x) ((x) << 20) -#define FW_EQ_CTRL_CMD_EQID(x) ((x) << 0) -#define FW_EQ_CTRL_CMD_EQID_GET(x) (((x) >> 0) & 0xfffff) -#define FW_EQ_CTRL_CMD_PHYSEQID_GET(x) (((x) >> 0) & 0xfffff) - -#define FW_EQ_CTRL_CMD_FETCHSZM (1U << 26) -#define FW_EQ_CTRL_CMD_STATUSPGNS (1U << 25) -#define FW_EQ_CTRL_CMD_STATUSPGRO (1U << 24) -#define FW_EQ_CTRL_CMD_FETCHNS (1U << 23) -#define FW_EQ_CTRL_CMD_FETCHRO (1U << 22) -#define FW_EQ_CTRL_CMD_HOSTFCMODE(x) ((x) << 20) -#define FW_EQ_CTRL_CMD_CPRIO(x) ((x) << 19) -#define FW_EQ_CTRL_CMD_ONCHIP(x) ((x) << 18) -#define FW_EQ_CTRL_CMD_PCIECHN(x) ((x) << 16) -#define FW_EQ_CTRL_CMD_IQID(x) ((x) << 0) - -#define FW_EQ_CTRL_CMD_DCAEN(x) ((x) << 31) -#define FW_EQ_CTRL_CMD_DCACPU(x) ((x) << 26) -#define FW_EQ_CTRL_CMD_FBMIN(x) ((x) << 23) -#define FW_EQ_CTRL_CMD_FBMAX(x) ((x) << 20) -#define FW_EQ_CTRL_CMD_CIDXFTHRESHO(x) ((x) << 19) -#define FW_EQ_CTRL_CMD_CIDXFTHRESH(x) ((x) << 16) -#define FW_EQ_CTRL_CMD_EQSIZE(x) ((x) << 0) - -struct fw_eq_ofld_cmd { - __be32 op_to_vfn; - __be32 alloc_to_len16; - __be32 eqid_pkd; - __be32 physeqid_pkd; - __be32 fetchszm_to_iqid; - __be32 dcaen_to_eqsize; - __be64 eqaddr; -}; - -#define FW_EQ_OFLD_CMD_PFN(x) ((x) << 8) -#define FW_EQ_OFLD_CMD_VFN(x) ((x) << 0) - -#define FW_EQ_OFLD_CMD_ALLOC (1U << 31) -#define FW_EQ_OFLD_CMD_FREE (1U << 30) -#define FW_EQ_OFLD_CMD_MODIFY (1U << 29) -#define FW_EQ_OFLD_CMD_EQSTART (1U << 28) -#define FW_EQ_OFLD_CMD_EQSTOP (1U << 27) - -#define FW_EQ_OFLD_CMD_EQID(x) ((x) << 0) -#define FW_EQ_OFLD_CMD_EQID_GET(x) (((x) >> 0) & 0xfffff) -#define FW_EQ_OFLD_CMD_PHYSEQID_GET(x) (((x) >> 0) & 0xfffff) - -#define FW_EQ_OFLD_CMD_FETCHSZM(x) ((x) << 26) -#define FW_EQ_OFLD_CMD_STATUSPGNS(x) ((x) << 25) -#define FW_EQ_OFLD_CMD_STATUSPGRO(x) ((x) << 24) -#define FW_EQ_OFLD_CMD_FETCHNS(x) ((x) << 23) -#define FW_EQ_OFLD_CMD_FETCHRO(x) ((x) << 22) -#define FW_EQ_OFLD_CMD_HOSTFCMODE(x) ((x) << 20) -#define FW_EQ_OFLD_CMD_CPRIO(x) ((x) << 19) -#define FW_EQ_OFLD_CMD_ONCHIP(x) ((x) << 18) -#define FW_EQ_OFLD_CMD_PCIECHN(x) ((x) << 16) -#define FW_EQ_OFLD_CMD_IQID(x) ((x) << 0) - -#define FW_EQ_OFLD_CMD_DCAEN(x) ((x) << 31) -#define FW_EQ_OFLD_CMD_DCACPU(x) ((x) << 26) -#define FW_EQ_OFLD_CMD_FBMIN(x) ((x) << 23) -#define FW_EQ_OFLD_CMD_FBMAX(x) ((x) << 20) -#define FW_EQ_OFLD_CMD_CIDXFTHRESHO(x) ((x) << 19) -#define FW_EQ_OFLD_CMD_CIDXFTHRESH(x) ((x) << 16) -#define FW_EQ_OFLD_CMD_EQSIZE(x) ((x) << 0) - -/* - * Macros for VIID parsing: - * VIID - [10:8] PFN, [7] VI Valid, [6:0] VI number - */ -#define FW_VIID_PFN_GET(x) (((x) >> 8) & 0x7) -#define FW_VIID_VIVLD_GET(x) (((x) >> 7) & 0x1) -#define FW_VIID_VIN_GET(x) (((x) >> 0) & 0x7F) - -struct fw_vi_cmd { - __be32 op_to_vfn; - __be32 alloc_to_len16; - __be16 type_viid; - u8 mac[6]; - u8 portid_pkd; - u8 nmac; - u8 nmac0[6]; - __be16 rsssize_pkd; - u8 nmac1[6]; - __be16 idsiiq_pkd; - u8 nmac2[6]; - __be16 idseiq_pkd; - u8 nmac3[6]; - __be64 r9; - __be64 r10; -}; - -#define FW_VI_CMD_PFN(x) ((x) << 8) -#define FW_VI_CMD_VFN(x) ((x) << 0) -#define FW_VI_CMD_ALLOC (1U << 31) -#define FW_VI_CMD_FREE (1U << 30) -#define FW_VI_CMD_VIID(x) ((x) << 0) -#define FW_VI_CMD_VIID_GET(x) ((x) & 0xfff) -#define FW_VI_CMD_PORTID(x) ((x) << 4) -#define FW_VI_CMD_PORTID_GET(x) (((x) >> 4) & 0xf) -#define FW_VI_CMD_RSSSIZE_GET(x) (((x) >> 0) & 0x7ff) - -/* Special VI_MAC command index ids */ -#define FW_VI_MAC_ADD_MAC 0x3FF -#define FW_VI_MAC_ADD_PERSIST_MAC 0x3FE -#define FW_VI_MAC_MAC_BASED_FREE 0x3FD -#define FW_CLS_TCAM_NUM_ENTRIES 336 - -enum fw_vi_mac_smac { - FW_VI_MAC_MPS_TCAM_ENTRY, - FW_VI_MAC_MPS_TCAM_ONLY, - FW_VI_MAC_SMT_ONLY, - FW_VI_MAC_SMT_AND_MPSTCAM -}; - -enum fw_vi_mac_result { - FW_VI_MAC_R_SUCCESS, - FW_VI_MAC_R_F_NONEXISTENT_NOMEM, - FW_VI_MAC_R_SMAC_FAIL, - FW_VI_MAC_R_F_ACL_CHECK -}; - -struct fw_vi_mac_cmd { - __be32 op_to_viid; - __be32 freemacs_to_len16; - union fw_vi_mac { - struct fw_vi_mac_exact { - __be16 valid_to_idx; - u8 macaddr[6]; - } exact[7]; - struct fw_vi_mac_hash { - __be64 hashvec; - } hash; - } u; -}; - -#define FW_VI_MAC_CMD_VIID(x) ((x) << 0) -#define FW_VI_MAC_CMD_FREEMACS(x) ((x) << 31) -#define FW_VI_MAC_CMD_HASHVECEN (1U << 23) -#define FW_VI_MAC_CMD_HASHUNIEN(x) ((x) << 22) -#define FW_VI_MAC_CMD_VALID (1U << 15) -#define FW_VI_MAC_CMD_PRIO(x) ((x) << 12) -#define FW_VI_MAC_CMD_SMAC_RESULT(x) ((x) << 10) -#define FW_VI_MAC_CMD_SMAC_RESULT_GET(x) (((x) >> 10) & 0x3) -#define FW_VI_MAC_CMD_IDX(x) ((x) << 0) -#define FW_VI_MAC_CMD_IDX_GET(x) (((x) >> 0) & 0x3ff) - -#define FW_RXMODE_MTU_NO_CHG 65535 - -struct fw_vi_rxmode_cmd { - __be32 op_to_viid; - __be32 retval_len16; - __be32 mtu_to_vlanexen; - __be32 r4_lo; -}; - -#define FW_VI_RXMODE_CMD_VIID(x) ((x) << 0) -#define FW_VI_RXMODE_CMD_MTU_MASK 0xffff -#define FW_VI_RXMODE_CMD_MTU(x) ((x) << 16) -#define FW_VI_RXMODE_CMD_PROMISCEN_MASK 0x3 -#define FW_VI_RXMODE_CMD_PROMISCEN(x) ((x) << 14) -#define FW_VI_RXMODE_CMD_ALLMULTIEN_MASK 0x3 -#define FW_VI_RXMODE_CMD_ALLMULTIEN(x) ((x) << 12) -#define FW_VI_RXMODE_CMD_BROADCASTEN_MASK 0x3 -#define FW_VI_RXMODE_CMD_BROADCASTEN(x) ((x) << 10) -#define FW_VI_RXMODE_CMD_VLANEXEN_MASK 0x3 -#define FW_VI_RXMODE_CMD_VLANEXEN(x) ((x) << 8) - -struct fw_vi_enable_cmd { - __be32 op_to_viid; - __be32 ien_to_len16; - __be16 blinkdur; - __be16 r3; - __be32 r4; -}; - -#define FW_VI_ENABLE_CMD_VIID(x) ((x) << 0) -#define FW_VI_ENABLE_CMD_IEN(x) ((x) << 31) -#define FW_VI_ENABLE_CMD_EEN(x) ((x) << 30) -#define FW_VI_ENABLE_CMD_LED (1U << 29) - -/* VI VF stats offset definitions */ -#define VI_VF_NUM_STATS 16 -enum fw_vi_stats_vf_index { - FW_VI_VF_STAT_TX_BCAST_BYTES_IX, - FW_VI_VF_STAT_TX_BCAST_FRAMES_IX, - FW_VI_VF_STAT_TX_MCAST_BYTES_IX, - FW_VI_VF_STAT_TX_MCAST_FRAMES_IX, - FW_VI_VF_STAT_TX_UCAST_BYTES_IX, - FW_VI_VF_STAT_TX_UCAST_FRAMES_IX, - FW_VI_VF_STAT_TX_DROP_FRAMES_IX, - FW_VI_VF_STAT_TX_OFLD_BYTES_IX, - FW_VI_VF_STAT_TX_OFLD_FRAMES_IX, - FW_VI_VF_STAT_RX_BCAST_BYTES_IX, - FW_VI_VF_STAT_RX_BCAST_FRAMES_IX, - FW_VI_VF_STAT_RX_MCAST_BYTES_IX, - FW_VI_VF_STAT_RX_MCAST_FRAMES_IX, - FW_VI_VF_STAT_RX_UCAST_BYTES_IX, - FW_VI_VF_STAT_RX_UCAST_FRAMES_IX, - FW_VI_VF_STAT_RX_ERR_FRAMES_IX -}; - -/* VI PF stats offset definitions */ -#define VI_PF_NUM_STATS 17 -enum fw_vi_stats_pf_index { - FW_VI_PF_STAT_TX_BCAST_BYTES_IX, - FW_VI_PF_STAT_TX_BCAST_FRAMES_IX, - FW_VI_PF_STAT_TX_MCAST_BYTES_IX, - FW_VI_PF_STAT_TX_MCAST_FRAMES_IX, - FW_VI_PF_STAT_TX_UCAST_BYTES_IX, - FW_VI_PF_STAT_TX_UCAST_FRAMES_IX, - FW_VI_PF_STAT_TX_OFLD_BYTES_IX, - FW_VI_PF_STAT_TX_OFLD_FRAMES_IX, - FW_VI_PF_STAT_RX_BYTES_IX, - FW_VI_PF_STAT_RX_FRAMES_IX, - FW_VI_PF_STAT_RX_BCAST_BYTES_IX, - FW_VI_PF_STAT_RX_BCAST_FRAMES_IX, - FW_VI_PF_STAT_RX_MCAST_BYTES_IX, - FW_VI_PF_STAT_RX_MCAST_FRAMES_IX, - FW_VI_PF_STAT_RX_UCAST_BYTES_IX, - FW_VI_PF_STAT_RX_UCAST_FRAMES_IX, - FW_VI_PF_STAT_RX_ERR_FRAMES_IX -}; - -struct fw_vi_stats_cmd { - __be32 op_to_viid; - __be32 retval_len16; - union fw_vi_stats { - struct fw_vi_stats_ctl { - __be16 nstats_ix; - __be16 r6; - __be32 r7; - __be64 stat0; - __be64 stat1; - __be64 stat2; - __be64 stat3; - __be64 stat4; - __be64 stat5; - } ctl; - struct fw_vi_stats_pf { - __be64 tx_bcast_bytes; - __be64 tx_bcast_frames; - __be64 tx_mcast_bytes; - __be64 tx_mcast_frames; - __be64 tx_ucast_bytes; - __be64 tx_ucast_frames; - __be64 tx_offload_bytes; - __be64 tx_offload_frames; - __be64 rx_pf_bytes; - __be64 rx_pf_frames; - __be64 rx_bcast_bytes; - __be64 rx_bcast_frames; - __be64 rx_mcast_bytes; - __be64 rx_mcast_frames; - __be64 rx_ucast_bytes; - __be64 rx_ucast_frames; - __be64 rx_err_frames; - } pf; - struct fw_vi_stats_vf { - __be64 tx_bcast_bytes; - __be64 tx_bcast_frames; - __be64 tx_mcast_bytes; - __be64 tx_mcast_frames; - __be64 tx_ucast_bytes; - __be64 tx_ucast_frames; - __be64 tx_drop_frames; - __be64 tx_offload_bytes; - __be64 tx_offload_frames; - __be64 rx_bcast_bytes; - __be64 rx_bcast_frames; - __be64 rx_mcast_bytes; - __be64 rx_mcast_frames; - __be64 rx_ucast_bytes; - __be64 rx_ucast_frames; - __be64 rx_err_frames; - } vf; - } u; -}; - -#define FW_VI_STATS_CMD_VIID(x) ((x) << 0) -#define FW_VI_STATS_CMD_NSTATS(x) ((x) << 12) -#define FW_VI_STATS_CMD_IX(x) ((x) << 0) - -struct fw_acl_mac_cmd { - __be32 op_to_vfn; - __be32 en_to_len16; - u8 nmac; - u8 r3[7]; - __be16 r4; - u8 macaddr0[6]; - __be16 r5; - u8 macaddr1[6]; - __be16 r6; - u8 macaddr2[6]; - __be16 r7; - u8 macaddr3[6]; -}; - -#define FW_ACL_MAC_CMD_PFN(x) ((x) << 8) -#define FW_ACL_MAC_CMD_VFN(x) ((x) << 0) -#define FW_ACL_MAC_CMD_EN(x) ((x) << 31) - -struct fw_acl_vlan_cmd { - __be32 op_to_vfn; - __be32 en_to_len16; - u8 nvlan; - u8 dropnovlan_fm; - u8 r3_lo[6]; - __be16 vlanid[16]; -}; - -#define FW_ACL_VLAN_CMD_PFN(x) ((x) << 8) -#define FW_ACL_VLAN_CMD_VFN(x) ((x) << 0) -#define FW_ACL_VLAN_CMD_EN(x) ((x) << 31) -#define FW_ACL_VLAN_CMD_DROPNOVLAN(x) ((x) << 7) -#define FW_ACL_VLAN_CMD_FM(x) ((x) << 6) - -enum fw_port_cap { - FW_PORT_CAP_SPEED_100M = 0x0001, - FW_PORT_CAP_SPEED_1G = 0x0002, - FW_PORT_CAP_SPEED_2_5G = 0x0004, - FW_PORT_CAP_SPEED_10G = 0x0008, - FW_PORT_CAP_SPEED_40G = 0x0010, - FW_PORT_CAP_SPEED_100G = 0x0020, - FW_PORT_CAP_FC_RX = 0x0040, - FW_PORT_CAP_FC_TX = 0x0080, - FW_PORT_CAP_ANEG = 0x0100, - FW_PORT_CAP_MDI_0 = 0x0200, - FW_PORT_CAP_MDI_1 = 0x0400, - FW_PORT_CAP_BEAN = 0x0800, - FW_PORT_CAP_PMA_LPBK = 0x1000, - FW_PORT_CAP_PCS_LPBK = 0x2000, - FW_PORT_CAP_PHYXS_LPBK = 0x4000, - FW_PORT_CAP_FAR_END_LPBK = 0x8000, -}; - -enum fw_port_mdi { - FW_PORT_MDI_UNCHANGED, - FW_PORT_MDI_AUTO, - FW_PORT_MDI_F_STRAIGHT, - FW_PORT_MDI_F_CROSSOVER -}; - -#define FW_PORT_MDI(x) ((x) << 9) - -enum fw_port_action { - FW_PORT_ACTION_L1_CFG = 0x0001, - FW_PORT_ACTION_L2_CFG = 0x0002, - FW_PORT_ACTION_GET_PORT_INFO = 0x0003, - FW_PORT_ACTION_L2_PPP_CFG = 0x0004, - FW_PORT_ACTION_L2_DCB_CFG = 0x0005, - FW_PORT_ACTION_LOW_PWR_TO_NORMAL = 0x0010, - FW_PORT_ACTION_L1_LOW_PWR_EN = 0x0011, - FW_PORT_ACTION_L2_WOL_MODE_EN = 0x0012, - FW_PORT_ACTION_LPBK_TO_NORMAL = 0x0020, - FW_PORT_ACTION_L1_LPBK = 0x0021, - FW_PORT_ACTION_L1_PMA_LPBK = 0x0022, - FW_PORT_ACTION_L1_PCS_LPBK = 0x0023, - FW_PORT_ACTION_L1_PHYXS_CSIDE_LPBK = 0x0024, - FW_PORT_ACTION_L1_PHYXS_ESIDE_LPBK = 0x0025, - FW_PORT_ACTION_PHY_RESET = 0x0040, - FW_PORT_ACTION_PMA_RESET = 0x0041, - FW_PORT_ACTION_PCS_RESET = 0x0042, - FW_PORT_ACTION_PHYXS_RESET = 0x0043, - FW_PORT_ACTION_DTEXS_REEST = 0x0044, - FW_PORT_ACTION_AN_RESET = 0x0045 -}; - -enum fw_port_l2cfg_ctlbf { - FW_PORT_L2_CTLBF_OVLAN0 = 0x01, - FW_PORT_L2_CTLBF_OVLAN1 = 0x02, - FW_PORT_L2_CTLBF_OVLAN2 = 0x04, - FW_PORT_L2_CTLBF_OVLAN3 = 0x08, - FW_PORT_L2_CTLBF_IVLAN = 0x10, - FW_PORT_L2_CTLBF_TXIPG = 0x20 -}; - -enum fw_port_dcb_cfg { - FW_PORT_DCB_CFG_PG = 0x01, - FW_PORT_DCB_CFG_PFC = 0x02, - FW_PORT_DCB_CFG_APPL = 0x04 -}; - -enum fw_port_dcb_cfg_rc { - FW_PORT_DCB_CFG_SUCCESS = 0x0, - FW_PORT_DCB_CFG_ERROR = 0x1 -}; - -struct fw_port_cmd { - __be32 op_to_portid; - __be32 action_to_len16; - union fw_port { - struct fw_port_l1cfg { - __be32 rcap; - __be32 r; - } l1cfg; - struct fw_port_l2cfg { - __be16 ctlbf_to_ivlan0; - __be16 ivlantype; - __be32 txipg_pkd; - __be16 ovlan0mask; - __be16 ovlan0type; - __be16 ovlan1mask; - __be16 ovlan1type; - __be16 ovlan2mask; - __be16 ovlan2type; - __be16 ovlan3mask; - __be16 ovlan3type; - } l2cfg; - struct fw_port_info { - __be32 lstatus_to_modtype; - __be16 pcap; - __be16 acap; - __be16 mtu; - __u8 cbllen; - __u8 r9; - __be32 r10; - __be64 r11; - } info; - struct fw_port_ppp { - __be32 pppen_to_ncsich; - __be32 r11; - } ppp; - struct fw_port_dcb { - __be16 cfg; - u8 up_map; - u8 sf_cfgrc; - __be16 prot_ix; - u8 pe7_to_pe0; - u8 numTCPFCs; - __be32 pgid0_to_pgid7; - __be32 numTCs_oui; - u8 pgpc[8]; - } dcb; - } u; -}; - -#define FW_PORT_CMD_READ (1U << 22) - -#define FW_PORT_CMD_PORTID(x) ((x) << 0) -#define FW_PORT_CMD_PORTID_GET(x) (((x) >> 0) & 0xf) - -#define FW_PORT_CMD_ACTION(x) ((x) << 16) -#define FW_PORT_CMD_ACTION_GET(x) (((x) >> 16) & 0xffff) - -#define FW_PORT_CMD_CTLBF(x) ((x) << 10) -#define FW_PORT_CMD_OVLAN3(x) ((x) << 7) -#define FW_PORT_CMD_OVLAN2(x) ((x) << 6) -#define FW_PORT_CMD_OVLAN1(x) ((x) << 5) -#define FW_PORT_CMD_OVLAN0(x) ((x) << 4) -#define FW_PORT_CMD_IVLAN0(x) ((x) << 3) - -#define FW_PORT_CMD_TXIPG(x) ((x) << 19) - -#define FW_PORT_CMD_LSTATUS (1U << 31) -#define FW_PORT_CMD_LSPEED(x) ((x) << 24) -#define FW_PORT_CMD_LSPEED_GET(x) (((x) >> 24) & 0x3f) -#define FW_PORT_CMD_TXPAUSE (1U << 23) -#define FW_PORT_CMD_RXPAUSE (1U << 22) -#define FW_PORT_CMD_MDIOCAP (1U << 21) -#define FW_PORT_CMD_MDIOADDR_GET(x) (((x) >> 16) & 0x1f) -#define FW_PORT_CMD_LPTXPAUSE (1U << 15) -#define FW_PORT_CMD_LPRXPAUSE (1U << 14) -#define FW_PORT_CMD_PTYPE_MASK 0x1f -#define FW_PORT_CMD_PTYPE_GET(x) (((x) >> 8) & FW_PORT_CMD_PTYPE_MASK) -#define FW_PORT_CMD_MODTYPE_MASK 0x1f -#define FW_PORT_CMD_MODTYPE_GET(x) (((x) >> 0) & FW_PORT_CMD_MODTYPE_MASK) - -#define FW_PORT_CMD_PPPEN(x) ((x) << 31) -#define FW_PORT_CMD_TPSRC(x) ((x) << 28) -#define FW_PORT_CMD_NCSISRC(x) ((x) << 24) - -#define FW_PORT_CMD_CH0(x) ((x) << 20) -#define FW_PORT_CMD_CH1(x) ((x) << 16) -#define FW_PORT_CMD_CH2(x) ((x) << 12) -#define FW_PORT_CMD_CH3(x) ((x) << 8) -#define FW_PORT_CMD_NCSICH(x) ((x) << 4) - -enum fw_port_type { - FW_PORT_TYPE_FIBER_XFI, - FW_PORT_TYPE_FIBER_XAUI, - FW_PORT_TYPE_BT_SGMII, - FW_PORT_TYPE_BT_XFI, - FW_PORT_TYPE_BT_XAUI, - FW_PORT_TYPE_KX4, - FW_PORT_TYPE_CX4, - FW_PORT_TYPE_KX, - FW_PORT_TYPE_KR, - FW_PORT_TYPE_SFP, - FW_PORT_TYPE_BP_AP, - FW_PORT_TYPE_BP4_AP, - - FW_PORT_TYPE_NONE = FW_PORT_CMD_PTYPE_MASK -}; - -enum fw_port_module_type { - FW_PORT_MOD_TYPE_NA, - FW_PORT_MOD_TYPE_LR, - FW_PORT_MOD_TYPE_SR, - FW_PORT_MOD_TYPE_ER, - FW_PORT_MOD_TYPE_TWINAX_PASSIVE, - FW_PORT_MOD_TYPE_TWINAX_ACTIVE, - FW_PORT_MOD_TYPE_LRM, - - FW_PORT_MOD_TYPE_NONE = FW_PORT_CMD_MODTYPE_MASK -}; - -/* port stats */ -#define FW_NUM_PORT_STATS 50 -#define FW_NUM_PORT_TX_STATS 23 -#define FW_NUM_PORT_RX_STATS 27 - -enum fw_port_stats_tx_index { - FW_STAT_TX_PORT_BYTES_IX, - FW_STAT_TX_PORT_FRAMES_IX, - FW_STAT_TX_PORT_BCAST_IX, - FW_STAT_TX_PORT_MCAST_IX, - FW_STAT_TX_PORT_UCAST_IX, - FW_STAT_TX_PORT_ERROR_IX, - FW_STAT_TX_PORT_64B_IX, - FW_STAT_TX_PORT_65B_127B_IX, - FW_STAT_TX_PORT_128B_255B_IX, - FW_STAT_TX_PORT_256B_511B_IX, - FW_STAT_TX_PORT_512B_1023B_IX, - FW_STAT_TX_PORT_1024B_1518B_IX, - FW_STAT_TX_PORT_1519B_MAX_IX, - FW_STAT_TX_PORT_DROP_IX, - FW_STAT_TX_PORT_PAUSE_IX, - FW_STAT_TX_PORT_PPP0_IX, - FW_STAT_TX_PORT_PPP1_IX, - FW_STAT_TX_PORT_PPP2_IX, - FW_STAT_TX_PORT_PPP3_IX, - FW_STAT_TX_PORT_PPP4_IX, - FW_STAT_TX_PORT_PPP5_IX, - FW_STAT_TX_PORT_PPP6_IX, - FW_STAT_TX_PORT_PPP7_IX -}; - -enum fw_port_stat_rx_index { - FW_STAT_RX_PORT_BYTES_IX, - FW_STAT_RX_PORT_FRAMES_IX, - FW_STAT_RX_PORT_BCAST_IX, - FW_STAT_RX_PORT_MCAST_IX, - FW_STAT_RX_PORT_UCAST_IX, - FW_STAT_RX_PORT_MTU_ERROR_IX, - FW_STAT_RX_PORT_MTU_CRC_ERROR_IX, - FW_STAT_RX_PORT_CRC_ERROR_IX, - FW_STAT_RX_PORT_LEN_ERROR_IX, - FW_STAT_RX_PORT_SYM_ERROR_IX, - FW_STAT_RX_PORT_64B_IX, - FW_STAT_RX_PORT_65B_127B_IX, - FW_STAT_RX_PORT_128B_255B_IX, - FW_STAT_RX_PORT_256B_511B_IX, - FW_STAT_RX_PORT_512B_1023B_IX, - FW_STAT_RX_PORT_1024B_1518B_IX, - FW_STAT_RX_PORT_1519B_MAX_IX, - FW_STAT_RX_PORT_PAUSE_IX, - FW_STAT_RX_PORT_PPP0_IX, - FW_STAT_RX_PORT_PPP1_IX, - FW_STAT_RX_PORT_PPP2_IX, - FW_STAT_RX_PORT_PPP3_IX, - FW_STAT_RX_PORT_PPP4_IX, - FW_STAT_RX_PORT_PPP5_IX, - FW_STAT_RX_PORT_PPP6_IX, - FW_STAT_RX_PORT_PPP7_IX, - FW_STAT_RX_PORT_LESS_64B_IX -}; - -struct fw_port_stats_cmd { - __be32 op_to_portid; - __be32 retval_len16; - union fw_port_stats { - struct fw_port_stats_ctl { - u8 nstats_bg_bm; - u8 tx_ix; - __be16 r6; - __be32 r7; - __be64 stat0; - __be64 stat1; - __be64 stat2; - __be64 stat3; - __be64 stat4; - __be64 stat5; - } ctl; - struct fw_port_stats_all { - __be64 tx_bytes; - __be64 tx_frames; - __be64 tx_bcast; - __be64 tx_mcast; - __be64 tx_ucast; - __be64 tx_error; - __be64 tx_64b; - __be64 tx_65b_127b; - __be64 tx_128b_255b; - __be64 tx_256b_511b; - __be64 tx_512b_1023b; - __be64 tx_1024b_1518b; - __be64 tx_1519b_max; - __be64 tx_drop; - __be64 tx_pause; - __be64 tx_ppp0; - __be64 tx_ppp1; - __be64 tx_ppp2; - __be64 tx_ppp3; - __be64 tx_ppp4; - __be64 tx_ppp5; - __be64 tx_ppp6; - __be64 tx_ppp7; - __be64 rx_bytes; - __be64 rx_frames; - __be64 rx_bcast; - __be64 rx_mcast; - __be64 rx_ucast; - __be64 rx_mtu_error; - __be64 rx_mtu_crc_error; - __be64 rx_crc_error; - __be64 rx_len_error; - __be64 rx_sym_error; - __be64 rx_64b; - __be64 rx_65b_127b; - __be64 rx_128b_255b; - __be64 rx_256b_511b; - __be64 rx_512b_1023b; - __be64 rx_1024b_1518b; - __be64 rx_1519b_max; - __be64 rx_pause; - __be64 rx_ppp0; - __be64 rx_ppp1; - __be64 rx_ppp2; - __be64 rx_ppp3; - __be64 rx_ppp4; - __be64 rx_ppp5; - __be64 rx_ppp6; - __be64 rx_ppp7; - __be64 rx_less_64b; - __be64 rx_bg_drop; - __be64 rx_bg_trunc; - } all; - } u; -}; - -#define FW_PORT_STATS_CMD_NSTATS(x) ((x) << 4) -#define FW_PORT_STATS_CMD_BG_BM(x) ((x) << 0) -#define FW_PORT_STATS_CMD_TX(x) ((x) << 7) -#define FW_PORT_STATS_CMD_IX(x) ((x) << 0) - -/* port loopback stats */ -#define FW_NUM_LB_STATS 16 -enum fw_port_lb_stats_index { - FW_STAT_LB_PORT_BYTES_IX, - FW_STAT_LB_PORT_FRAMES_IX, - FW_STAT_LB_PORT_BCAST_IX, - FW_STAT_LB_PORT_MCAST_IX, - FW_STAT_LB_PORT_UCAST_IX, - FW_STAT_LB_PORT_ERROR_IX, - FW_STAT_LB_PORT_64B_IX, - FW_STAT_LB_PORT_65B_127B_IX, - FW_STAT_LB_PORT_128B_255B_IX, - FW_STAT_LB_PORT_256B_511B_IX, - FW_STAT_LB_PORT_512B_1023B_IX, - FW_STAT_LB_PORT_1024B_1518B_IX, - FW_STAT_LB_PORT_1519B_MAX_IX, - FW_STAT_LB_PORT_DROP_FRAMES_IX -}; - -struct fw_port_lb_stats_cmd { - __be32 op_to_lbport; - __be32 retval_len16; - union fw_port_lb_stats { - struct fw_port_lb_stats_ctl { - u8 nstats_bg_bm; - u8 ix_pkd; - __be16 r6; - __be32 r7; - __be64 stat0; - __be64 stat1; - __be64 stat2; - __be64 stat3; - __be64 stat4; - __be64 stat5; - } ctl; - struct fw_port_lb_stats_all { - __be64 tx_bytes; - __be64 tx_frames; - __be64 tx_bcast; - __be64 tx_mcast; - __be64 tx_ucast; - __be64 tx_error; - __be64 tx_64b; - __be64 tx_65b_127b; - __be64 tx_128b_255b; - __be64 tx_256b_511b; - __be64 tx_512b_1023b; - __be64 tx_1024b_1518b; - __be64 tx_1519b_max; - __be64 rx_lb_drop; - __be64 rx_lb_trunc; - } all; - } u; -}; - -#define FW_PORT_LB_STATS_CMD_LBPORT(x) ((x) << 0) -#define FW_PORT_LB_STATS_CMD_NSTATS(x) ((x) << 4) -#define FW_PORT_LB_STATS_CMD_BG_BM(x) ((x) << 0) -#define FW_PORT_LB_STATS_CMD_IX(x) ((x) << 0) - -struct fw_rss_ind_tbl_cmd { - __be32 op_to_viid; -#define FW_RSS_IND_TBL_CMD_VIID(x) ((x) << 0) - __be32 retval_len16; - __be16 niqid; - __be16 startidx; - __be32 r3; - __be32 iq0_to_iq2; -#define FW_RSS_IND_TBL_CMD_IQ0(x) ((x) << 20) -#define FW_RSS_IND_TBL_CMD_IQ1(x) ((x) << 10) -#define FW_RSS_IND_TBL_CMD_IQ2(x) ((x) << 0) - __be32 iq3_to_iq5; - __be32 iq6_to_iq8; - __be32 iq9_to_iq11; - __be32 iq12_to_iq14; - __be32 iq15_to_iq17; - __be32 iq18_to_iq20; - __be32 iq21_to_iq23; - __be32 iq24_to_iq26; - __be32 iq27_to_iq29; - __be32 iq30_iq31; - __be32 r15_lo; -}; - -struct fw_rss_glb_config_cmd { - __be32 op_to_write; - __be32 retval_len16; - union fw_rss_glb_config { - struct fw_rss_glb_config_manual { - __be32 mode_pkd; - __be32 r3; - __be64 r4; - __be64 r5; - } manual; - struct fw_rss_glb_config_basicvirtual { - __be32 mode_pkd; - __be32 synmapen_to_hashtoeplitz; -#define FW_RSS_GLB_CONFIG_CMD_SYNMAPEN (1U << 8) -#define FW_RSS_GLB_CONFIG_CMD_SYN4TUPENIPV6 (1U << 7) -#define FW_RSS_GLB_CONFIG_CMD_SYN2TUPENIPV6 (1U << 6) -#define FW_RSS_GLB_CONFIG_CMD_SYN4TUPENIPV4 (1U << 5) -#define FW_RSS_GLB_CONFIG_CMD_SYN2TUPENIPV4 (1U << 4) -#define FW_RSS_GLB_CONFIG_CMD_OFDMAPEN (1U << 3) -#define FW_RSS_GLB_CONFIG_CMD_TNLMAPEN (1U << 2) -#define FW_RSS_GLB_CONFIG_CMD_TNLALLLKP (1U << 1) -#define FW_RSS_GLB_CONFIG_CMD_HASHTOEPLITZ (1U << 0) - __be64 r8; - __be64 r9; - } basicvirtual; - } u; -}; - -#define FW_RSS_GLB_CONFIG_CMD_MODE(x) ((x) << 28) -#define FW_RSS_GLB_CONFIG_CMD_MODE_GET(x) (((x) >> 28) & 0xf) - -#define FW_RSS_GLB_CONFIG_CMD_MODE_MANUAL 0 -#define FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL 1 - -struct fw_rss_vi_config_cmd { - __be32 op_to_viid; -#define FW_RSS_VI_CONFIG_CMD_VIID(x) ((x) << 0) - __be32 retval_len16; - union fw_rss_vi_config { - struct fw_rss_vi_config_manual { - __be64 r3; - __be64 r4; - __be64 r5; - } manual; - struct fw_rss_vi_config_basicvirtual { - __be32 r6; - __be32 defaultq_to_udpen; -#define FW_RSS_VI_CONFIG_CMD_DEFAULTQ(x) ((x) << 16) -#define FW_RSS_VI_CONFIG_CMD_DEFAULTQ_GET(x) (((x) >> 16) & 0x3ff) -#define FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN (1U << 4) -#define FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN (1U << 3) -#define FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN (1U << 2) -#define FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN (1U << 1) -#define FW_RSS_VI_CONFIG_CMD_UDPEN (1U << 0) - __be64 r9; - __be64 r10; - } basicvirtual; - } u; -}; - -enum fw_error_type { - FW_ERROR_TYPE_EXCEPTION = 0x0, - FW_ERROR_TYPE_HWMODULE = 0x1, - FW_ERROR_TYPE_WR = 0x2, - FW_ERROR_TYPE_ACL = 0x3, -}; - -struct fw_error_cmd { - __be32 op_to_type; - __be32 len16_pkd; - union fw_error { - struct fw_error_exception { - __be32 info[6]; - } exception; - struct fw_error_hwmodule { - __be32 regaddr; - __be32 regval; - } hwmodule; - struct fw_error_wr { - __be16 cidx; - __be16 pfn_vfn; - __be32 eqid; - u8 wrhdr[16]; - } wr; - struct fw_error_acl { - __be16 cidx; - __be16 pfn_vfn; - __be32 eqid; - __be16 mv_pkd; - u8 val[6]; - __be64 r4; - } acl; - } u; -}; - -struct fw_debug_cmd { - __be32 op_type; -#define FW_DEBUG_CMD_TYPE_GET(x) ((x) & 0xff) - __be32 len16_pkd; - union fw_debug { - struct fw_debug_assert { - __be32 fcid; - __be32 line; - __be32 x; - __be32 y; - u8 filename_0_7[8]; - u8 filename_8_15[8]; - __be64 r3; - } assert; - struct fw_debug_prt { - __be16 dprtstridx; - __be16 r3[3]; - __be32 dprtstrparam0; - __be32 dprtstrparam1; - __be32 dprtstrparam2; - __be32 dprtstrparam3; - } prt; - } u; -}; - -struct fw_hdr { - u8 ver; - u8 reserved1; - __be16 len512; /* bin length in units of 512-bytes */ - __be32 fw_ver; /* firmware version */ - __be32 tp_microcode_ver; - u8 intfver_nic; - u8 intfver_vnic; - u8 intfver_ofld; - u8 intfver_ri; - u8 intfver_iscsipdu; - u8 intfver_iscsi; - u8 intfver_fcoe; - u8 reserved2; - __be32 reserved3[27]; -}; - -#define FW_HDR_FW_VER_MAJOR_GET(x) (((x) >> 24) & 0xff) -#define FW_HDR_FW_VER_MINOR_GET(x) (((x) >> 16) & 0xff) -#define FW_HDR_FW_VER_MICRO_GET(x) (((x) >> 8) & 0xff) -#define FW_HDR_FW_VER_BUILD_GET(x) (((x) >> 0) & 0xff) -#endif /* _T4FW_INTERFACE_H_ */ diff --git a/drivers/net/cxgb4vf/Makefile b/drivers/net/cxgb4vf/Makefile deleted file mode 100644 index d72ee26cb4c7..000000000000 --- a/drivers/net/cxgb4vf/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# Chelsio T4 SR-IOV Virtual Function Driver -# - -obj-$(CONFIG_CHELSIO_T4VF) += cxgb4vf.o - -cxgb4vf-objs := cxgb4vf_main.o t4vf_hw.o sge.o diff --git a/drivers/net/cxgb4vf/adapter.h b/drivers/net/cxgb4vf/adapter.h deleted file mode 100644 index 594334d5c711..000000000000 --- a/drivers/net/cxgb4vf/adapter.h +++ /dev/null @@ -1,534 +0,0 @@ -/* - * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet - * driver for Linux. - * - * Copyright (c) 2009-2010 Chelsio Communications, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* - * This file should not be included directly. Include t4vf_common.h instead. - */ - -#ifndef __CXGB4VF_ADAPTER_H__ -#define __CXGB4VF_ADAPTER_H__ - -#include -#include -#include -#include -#include -#include - -#include "../cxgb4/t4_hw.h" - -/* - * Constants of the implementation. - */ -enum { - MAX_NPORTS = 1, /* max # of "ports" */ - MAX_PORT_QSETS = 8, /* max # of Queue Sets / "port" */ - MAX_ETH_QSETS = MAX_NPORTS*MAX_PORT_QSETS, - - /* - * MSI-X interrupt index usage. - */ - MSIX_FW = 0, /* MSI-X index for firmware Q */ - MSIX_IQFLINT = 1, /* MSI-X index base for Ingress Qs */ - MSIX_EXTRAS = 1, - MSIX_ENTRIES = MAX_ETH_QSETS + MSIX_EXTRAS, - - /* - * The maximum number of Ingress and Egress Queues is determined by - * the maximum number of "Queue Sets" which we support plus any - * ancillary queues. Each "Queue Set" requires one Ingress Queue - * for RX Packet Ingress Event notifications and two Egress Queues for - * a Free List and an Ethernet TX list. - */ - INGQ_EXTRAS = 2, /* firmware event queue and */ - /* forwarded interrupts */ - MAX_INGQ = MAX_ETH_QSETS+INGQ_EXTRAS, - MAX_EGRQ = MAX_ETH_QSETS*2, -}; - -/* - * Forward structure definition references. - */ -struct adapter; -struct sge_eth_rxq; -struct sge_rspq; - -/* - * Per-"port" information. This is really per-Virtual Interface information - * but the use of the "port" nomanclature makes it easier to go back and forth - * between the PF and VF drivers ... - */ -struct port_info { - struct adapter *adapter; /* our adapter */ - u16 viid; /* virtual interface ID */ - s16 xact_addr_filt; /* index of our MAC address filter */ - u16 rss_size; /* size of VI's RSS table slice */ - u8 pidx; /* index into adapter port[] */ - u8 port_id; /* physical port ID */ - u8 nqsets; /* # of "Queue Sets" */ - u8 first_qset; /* index of first "Queue Set" */ - struct link_config link_cfg; /* physical port configuration */ -}; - -/* - * Scatter Gather Engine resources for the "adapter". Our ingress and egress - * queues are organized into "Queue Sets" with one ingress and one egress - * queue per Queue Set. These Queue Sets are aportionable between the "ports" - * (Virtual Interfaces). One extra ingress queue is used to receive - * asynchronous messages from the firmware. Note that the "Queue IDs" that we - * use here are really "Relative Queue IDs" which are returned as part of the - * firmware command to allocate queues. These queue IDs are relative to the - * absolute Queue ID base of the section of the Queue ID space allocated to - * the PF/VF. - */ - -/* - * SGE free-list queue state. - */ -struct rx_sw_desc; -struct sge_fl { - unsigned int avail; /* # of available RX buffers */ - unsigned int pend_cred; /* new buffers since last FL DB ring */ - unsigned int cidx; /* consumer index */ - unsigned int pidx; /* producer index */ - unsigned long alloc_failed; /* # of buffer allocation failures */ - unsigned long large_alloc_failed; - unsigned long starving; /* # of times FL was found starving */ - - /* - * Write-once/infrequently fields. - * ------------------------------- - */ - - unsigned int cntxt_id; /* SGE relative QID for the free list */ - unsigned int abs_id; /* SGE absolute QID for the free list */ - unsigned int size; /* capacity of free list */ - struct rx_sw_desc *sdesc; /* address of SW RX descriptor ring */ - __be64 *desc; /* address of HW RX descriptor ring */ - dma_addr_t addr; /* PCI bus address of hardware ring */ -}; - -/* - * An ingress packet gather list. - */ -struct pkt_gl { - skb_frag_t frags[MAX_SKB_FRAGS]; - void *va; /* virtual address of first byte */ - unsigned int nfrags; /* # of fragments */ - unsigned int tot_len; /* total length of fragments */ -}; - -typedef int (*rspq_handler_t)(struct sge_rspq *, const __be64 *, - const struct pkt_gl *); - -/* - * State for an SGE Response Queue. - */ -struct sge_rspq { - struct napi_struct napi; /* NAPI scheduling control */ - const __be64 *cur_desc; /* current descriptor in queue */ - unsigned int cidx; /* consumer index */ - u8 gen; /* current generation bit */ - u8 next_intr_params; /* holdoff params for next interrupt */ - int offset; /* offset into current FL buffer */ - - unsigned int unhandled_irqs; /* bogus interrupts */ - - /* - * Write-once/infrequently fields. - * ------------------------------- - */ - - u8 intr_params; /* interrupt holdoff parameters */ - u8 pktcnt_idx; /* interrupt packet threshold */ - u8 idx; /* queue index within its group */ - u16 cntxt_id; /* SGE rel QID for the response Q */ - u16 abs_id; /* SGE abs QID for the response Q */ - __be64 *desc; /* address of hardware response ring */ - dma_addr_t phys_addr; /* PCI bus address of ring */ - unsigned int iqe_len; /* entry size */ - unsigned int size; /* capcity of response Q */ - struct adapter *adapter; /* our adapter */ - struct net_device *netdev; /* associated net device */ - rspq_handler_t handler; /* the handler for this response Q */ -}; - -/* - * Ethernet queue statistics - */ -struct sge_eth_stats { - unsigned long pkts; /* # of ethernet packets */ - unsigned long lro_pkts; /* # of LRO super packets */ - unsigned long lro_merged; /* # of wire packets merged by LRO */ - unsigned long rx_cso; /* # of Rx checksum offloads */ - unsigned long vlan_ex; /* # of Rx VLAN extractions */ - unsigned long rx_drops; /* # of packets dropped due to no mem */ -}; - -/* - * State for an Ethernet Receive Queue. - */ -struct sge_eth_rxq { - struct sge_rspq rspq; /* Response Queue */ - struct sge_fl fl; /* Free List */ - struct sge_eth_stats stats; /* receive statistics */ -}; - -/* - * SGE Transmit Queue state. This contains all of the resources associated - * with the hardware status of a TX Queue which is a circular ring of hardware - * TX Descriptors. For convenience, it also contains a pointer to a parallel - * "Software Descriptor" array but we don't know anything about it here other - * than its type name. - */ -struct tx_desc { - /* - * Egress Queues are measured in units of SGE_EQ_IDXSIZE by the - * hardware: Sizes, Producer and Consumer indices, etc. - */ - __be64 flit[SGE_EQ_IDXSIZE/sizeof(__be64)]; -}; -struct tx_sw_desc; -struct sge_txq { - unsigned int in_use; /* # of in-use TX descriptors */ - unsigned int size; /* # of descriptors */ - unsigned int cidx; /* SW consumer index */ - unsigned int pidx; /* producer index */ - unsigned long stops; /* # of times queue has been stopped */ - unsigned long restarts; /* # of queue restarts */ - - /* - * Write-once/infrequently fields. - * ------------------------------- - */ - - unsigned int cntxt_id; /* SGE relative QID for the TX Q */ - unsigned int abs_id; /* SGE absolute QID for the TX Q */ - struct tx_desc *desc; /* address of HW TX descriptor ring */ - struct tx_sw_desc *sdesc; /* address of SW TX descriptor ring */ - struct sge_qstat *stat; /* queue status entry */ - dma_addr_t phys_addr; /* PCI bus address of hardware ring */ -}; - -/* - * State for an Ethernet Transmit Queue. - */ -struct sge_eth_txq { - struct sge_txq q; /* SGE TX Queue */ - struct netdev_queue *txq; /* associated netdev TX queue */ - unsigned long tso; /* # of TSO requests */ - unsigned long tx_cso; /* # of TX checksum offloads */ - unsigned long vlan_ins; /* # of TX VLAN insertions */ - unsigned long mapping_err; /* # of I/O MMU packet mapping errors */ -}; - -/* - * The complete set of Scatter/Gather Engine resources. - */ -struct sge { - /* - * Our "Queue Sets" ... - */ - struct sge_eth_txq ethtxq[MAX_ETH_QSETS]; - struct sge_eth_rxq ethrxq[MAX_ETH_QSETS]; - - /* - * Extra ingress queues for asynchronous firmware events and - * forwarded interrupts (when in MSI mode). - */ - struct sge_rspq fw_evtq ____cacheline_aligned_in_smp; - - struct sge_rspq intrq ____cacheline_aligned_in_smp; - spinlock_t intrq_lock; - - /* - * State for managing "starving Free Lists" -- Free Lists which have - * fallen below a certain threshold of buffers available to the - * hardware and attempts to refill them up to that threshold have - * failed. We have a regular "slow tick" timer process which will - * make periodic attempts to refill these starving Free Lists ... - */ - DECLARE_BITMAP(starving_fl, MAX_EGRQ); - struct timer_list rx_timer; - - /* - * State for cleaning up completed TX descriptors. - */ - struct timer_list tx_timer; - - /* - * Write-once/infrequently fields. - * ------------------------------- - */ - - u16 max_ethqsets; /* # of available Ethernet queue sets */ - u16 ethqsets; /* # of active Ethernet queue sets */ - u16 ethtxq_rover; /* Tx queue to clean up next */ - u16 timer_val[SGE_NTIMERS]; /* interrupt holdoff timer array */ - u8 counter_val[SGE_NCOUNTERS]; /* interrupt RX threshold array */ - - /* - * Reverse maps from Absolute Queue IDs to associated queue pointers. - * The absolute Queue IDs are in a compact range which start at a - * [potentially large] Base Queue ID. We perform the reverse map by - * first converting the Absolute Queue ID into a Relative Queue ID by - * subtracting off the Base Queue ID and then use a Relative Queue ID - * indexed table to get the pointer to the corresponding software - * queue structure. - */ - unsigned int egr_base; - unsigned int ingr_base; - void *egr_map[MAX_EGRQ]; - struct sge_rspq *ingr_map[MAX_INGQ]; -}; - -/* - * Utility macros to convert Absolute- to Relative-Queue indices and Egress- - * and Ingress-Queues. The EQ_MAP() and IQ_MAP() macros which provide - * pointers to Ingress- and Egress-Queues can be used as both L- and R-values - */ -#define EQ_IDX(s, abs_id) ((unsigned int)((abs_id) - (s)->egr_base)) -#define IQ_IDX(s, abs_id) ((unsigned int)((abs_id) - (s)->ingr_base)) - -#define EQ_MAP(s, abs_id) ((s)->egr_map[EQ_IDX(s, abs_id)]) -#define IQ_MAP(s, abs_id) ((s)->ingr_map[IQ_IDX(s, abs_id)]) - -/* - * Macro to iterate across Queue Sets ("rxq" is a historic misnomer). - */ -#define for_each_ethrxq(sge, iter) \ - for (iter = 0; iter < (sge)->ethqsets; iter++) - -/* - * Per-"adapter" (Virtual Function) information. - */ -struct adapter { - /* PCI resources */ - void __iomem *regs; - struct pci_dev *pdev; - struct device *pdev_dev; - - /* "adapter" resources */ - unsigned long registered_device_map; - unsigned long open_device_map; - unsigned long flags; - struct adapter_params params; - - /* queue and interrupt resources */ - struct { - unsigned short vec; - char desc[22]; - } msix_info[MSIX_ENTRIES]; - struct sge sge; - - /* Linux network device resources */ - struct net_device *port[MAX_NPORTS]; - const char *name; - unsigned int msg_enable; - - /* debugfs resources */ - struct dentry *debugfs_root; - - /* various locks */ - spinlock_t stats_lock; -}; - -enum { /* adapter flags */ - FULL_INIT_DONE = (1UL << 0), - USING_MSI = (1UL << 1), - USING_MSIX = (1UL << 2), - QUEUES_BOUND = (1UL << 3), -}; - -/* - * The following register read/write routine definitions are required by - * the common code. - */ - -/** - * t4_read_reg - read a HW register - * @adapter: the adapter - * @reg_addr: the register address - * - * Returns the 32-bit value of the given HW register. - */ -static inline u32 t4_read_reg(struct adapter *adapter, u32 reg_addr) -{ - return readl(adapter->regs + reg_addr); -} - -/** - * t4_write_reg - write a HW register - * @adapter: the adapter - * @reg_addr: the register address - * @val: the value to write - * - * Write a 32-bit value into the given HW register. - */ -static inline void t4_write_reg(struct adapter *adapter, u32 reg_addr, u32 val) -{ - writel(val, adapter->regs + reg_addr); -} - -#ifndef readq -static inline u64 readq(const volatile void __iomem *addr) -{ - return readl(addr) + ((u64)readl(addr + 4) << 32); -} - -static inline void writeq(u64 val, volatile void __iomem *addr) -{ - writel(val, addr); - writel(val >> 32, addr + 4); -} -#endif - -/** - * t4_read_reg64 - read a 64-bit HW register - * @adapter: the adapter - * @reg_addr: the register address - * - * Returns the 64-bit value of the given HW register. - */ -static inline u64 t4_read_reg64(struct adapter *adapter, u32 reg_addr) -{ - return readq(adapter->regs + reg_addr); -} - -/** - * t4_write_reg64 - write a 64-bit HW register - * @adapter: the adapter - * @reg_addr: the register address - * @val: the value to write - * - * Write a 64-bit value into the given HW register. - */ -static inline void t4_write_reg64(struct adapter *adapter, u32 reg_addr, - u64 val) -{ - writeq(val, adapter->regs + reg_addr); -} - -/** - * port_name - return the string name of a port - * @adapter: the adapter - * @pidx: the port index - * - * Return the string name of the selected port. - */ -static inline const char *port_name(struct adapter *adapter, int pidx) -{ - return adapter->port[pidx]->name; -} - -/** - * t4_os_set_hw_addr - store a port's MAC address in SW - * @adapter: the adapter - * @pidx: the port index - * @hw_addr: the Ethernet address - * - * Store the Ethernet address of the given port in SW. Called by the common - * code when it retrieves a port's Ethernet address from EEPROM. - */ -static inline void t4_os_set_hw_addr(struct adapter *adapter, int pidx, - u8 hw_addr[]) -{ - memcpy(adapter->port[pidx]->dev_addr, hw_addr, ETH_ALEN); - memcpy(adapter->port[pidx]->perm_addr, hw_addr, ETH_ALEN); -} - -/** - * netdev2pinfo - return the port_info structure associated with a net_device - * @dev: the netdev - * - * Return the struct port_info associated with a net_device - */ -static inline struct port_info *netdev2pinfo(const struct net_device *dev) -{ - return netdev_priv(dev); -} - -/** - * adap2pinfo - return the port_info of a port - * @adap: the adapter - * @pidx: the port index - * - * Return the port_info structure for the adapter. - */ -static inline struct port_info *adap2pinfo(struct adapter *adapter, int pidx) -{ - return netdev_priv(adapter->port[pidx]); -} - -/** - * netdev2adap - return the adapter structure associated with a net_device - * @dev: the netdev - * - * Return the struct adapter associated with a net_device - */ -static inline struct adapter *netdev2adap(const struct net_device *dev) -{ - return netdev2pinfo(dev)->adapter; -} - -/* - * OS "Callback" function declarations. These are functions that the OS code - * is "contracted" to provide for the common code. - */ -void t4vf_os_link_changed(struct adapter *, int, int); - -/* - * SGE function prototype declarations. - */ -int t4vf_sge_alloc_rxq(struct adapter *, struct sge_rspq *, bool, - struct net_device *, int, - struct sge_fl *, rspq_handler_t); -int t4vf_sge_alloc_eth_txq(struct adapter *, struct sge_eth_txq *, - struct net_device *, struct netdev_queue *, - unsigned int); -void t4vf_free_sge_resources(struct adapter *); - -int t4vf_eth_xmit(struct sk_buff *, struct net_device *); -int t4vf_ethrx_handler(struct sge_rspq *, const __be64 *, - const struct pkt_gl *); - -irq_handler_t t4vf_intr_handler(struct adapter *); -irqreturn_t t4vf_sge_intr_msix(int, void *); - -int t4vf_sge_init(struct adapter *); -void t4vf_sge_start(struct adapter *); -void t4vf_sge_stop(struct adapter *); - -#endif /* __CXGB4VF_ADAPTER_H__ */ diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c deleted file mode 100644 index ec799139dfe2..000000000000 --- a/drivers/net/cxgb4vf/cxgb4vf_main.c +++ /dev/null @@ -1,2947 +0,0 @@ -/* - * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet - * driver for Linux. - * - * Copyright (c) 2009-2010 Chelsio Communications, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "t4vf_common.h" -#include "t4vf_defs.h" - -#include "../cxgb4/t4_regs.h" -#include "../cxgb4/t4_msg.h" - -/* - * Generic information about the driver. - */ -#define DRV_VERSION "1.0.0" -#define DRV_DESC "Chelsio T4 Virtual Function (VF) Network Driver" - -/* - * Module Parameters. - * ================== - */ - -/* - * Default ethtool "message level" for adapters. - */ -#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \ - NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\ - NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) - -static int dflt_msg_enable = DFLT_MSG_ENABLE; - -module_param(dflt_msg_enable, int, 0644); -MODULE_PARM_DESC(dflt_msg_enable, - "default adapter ethtool message level bitmap"); - -/* - * The driver uses the best interrupt scheme available on a platform in the - * order MSI-X then MSI. This parameter determines which of these schemes the - * driver may consider as follows: - * - * msi = 2: choose from among MSI-X and MSI - * msi = 1: only consider MSI interrupts - * - * Note that unlike the Physical Function driver, this Virtual Function driver - * does _not_ support legacy INTx interrupts (this limitation is mandated by - * the PCI-E SR-IOV standard). - */ -#define MSI_MSIX 2 -#define MSI_MSI 1 -#define MSI_DEFAULT MSI_MSIX - -static int msi = MSI_DEFAULT; - -module_param(msi, int, 0644); -MODULE_PARM_DESC(msi, "whether to use MSI-X or MSI"); - -/* - * Fundamental constants. - * ====================== - */ - -enum { - MAX_TXQ_ENTRIES = 16384, - MAX_RSPQ_ENTRIES = 16384, - MAX_RX_BUFFERS = 16384, - - MIN_TXQ_ENTRIES = 32, - MIN_RSPQ_ENTRIES = 128, - MIN_FL_ENTRIES = 16, - - /* - * For purposes of manipulating the Free List size we need to - * recognize that Free Lists are actually Egress Queues (the host - * produces free buffers which the hardware consumes), Egress Queues - * indices are all in units of Egress Context Units bytes, and free - * list entries are 64-bit PCI DMA addresses. And since the state of - * the Producer Index == the Consumer Index implies an EMPTY list, we - * always have at least one Egress Unit's worth of Free List entries - * unused. See sge.c for more details ... - */ - EQ_UNIT = SGE_EQ_IDXSIZE, - FL_PER_EQ_UNIT = EQ_UNIT / sizeof(__be64), - MIN_FL_RESID = FL_PER_EQ_UNIT, -}; - -/* - * Global driver state. - * ==================== - */ - -static struct dentry *cxgb4vf_debugfs_root; - -/* - * OS "Callback" functions. - * ======================== - */ - -/* - * The link status has changed on the indicated "port" (Virtual Interface). - */ -void t4vf_os_link_changed(struct adapter *adapter, int pidx, int link_ok) -{ - struct net_device *dev = adapter->port[pidx]; - - /* - * If the port is disabled or the current recorded "link up" - * status matches the new status, just return. - */ - if (!netif_running(dev) || link_ok == netif_carrier_ok(dev)) - return; - - /* - * Tell the OS that the link status has changed and print a short - * informative message on the console about the event. - */ - if (link_ok) { - const char *s; - const char *fc; - const struct port_info *pi = netdev_priv(dev); - - netif_carrier_on(dev); - - switch (pi->link_cfg.speed) { - case SPEED_10000: - s = "10Gbps"; - break; - - case SPEED_1000: - s = "1000Mbps"; - break; - - case SPEED_100: - s = "100Mbps"; - break; - - default: - s = "unknown"; - break; - } - - switch (pi->link_cfg.fc) { - case PAUSE_RX: - fc = "RX"; - break; - - case PAUSE_TX: - fc = "TX"; - break; - - case PAUSE_RX|PAUSE_TX: - fc = "RX/TX"; - break; - - default: - fc = "no"; - break; - } - - printk(KERN_INFO "%s: link up, %s, full-duplex, %s PAUSE\n", - dev->name, s, fc); - } else { - netif_carrier_off(dev); - printk(KERN_INFO "%s: link down\n", dev->name); - } -} - -/* - * Net device operations. - * ====================== - */ - - - - -/* - * Perform the MAC and PHY actions needed to enable a "port" (Virtual - * Interface). - */ -static int link_start(struct net_device *dev) -{ - int ret; - struct port_info *pi = netdev_priv(dev); - - /* - * We do not set address filters and promiscuity here, the stack does - * that step explicitly. Enable vlan accel. - */ - ret = t4vf_set_rxmode(pi->adapter, pi->viid, dev->mtu, -1, -1, -1, 1, - true); - if (ret == 0) { - ret = t4vf_change_mac(pi->adapter, pi->viid, - pi->xact_addr_filt, dev->dev_addr, true); - if (ret >= 0) { - pi->xact_addr_filt = ret; - ret = 0; - } - } - - /* - * We don't need to actually "start the link" itself since the - * firmware will do that for us when the first Virtual Interface - * is enabled on a port. - */ - if (ret == 0) - ret = t4vf_enable_vi(pi->adapter, pi->viid, true, true); - return ret; -} - -/* - * Name the MSI-X interrupts. - */ -static void name_msix_vecs(struct adapter *adapter) -{ - int namelen = sizeof(adapter->msix_info[0].desc) - 1; - int pidx; - - /* - * Firmware events. - */ - snprintf(adapter->msix_info[MSIX_FW].desc, namelen, - "%s-FWeventq", adapter->name); - adapter->msix_info[MSIX_FW].desc[namelen] = 0; - - /* - * Ethernet queues. - */ - for_each_port(adapter, pidx) { - struct net_device *dev = adapter->port[pidx]; - const struct port_info *pi = netdev_priv(dev); - int qs, msi; - - for (qs = 0, msi = MSIX_IQFLINT; qs < pi->nqsets; qs++, msi++) { - snprintf(adapter->msix_info[msi].desc, namelen, - "%s-%d", dev->name, qs); - adapter->msix_info[msi].desc[namelen] = 0; - } - } -} - -/* - * Request all of our MSI-X resources. - */ -static int request_msix_queue_irqs(struct adapter *adapter) -{ - struct sge *s = &adapter->sge; - int rxq, msi, err; - - /* - * Firmware events. - */ - err = request_irq(adapter->msix_info[MSIX_FW].vec, t4vf_sge_intr_msix, - 0, adapter->msix_info[MSIX_FW].desc, &s->fw_evtq); - if (err) - return err; - - /* - * Ethernet queues. - */ - msi = MSIX_IQFLINT; - for_each_ethrxq(s, rxq) { - err = request_irq(adapter->msix_info[msi].vec, - t4vf_sge_intr_msix, 0, - adapter->msix_info[msi].desc, - &s->ethrxq[rxq].rspq); - if (err) - goto err_free_irqs; - msi++; - } - return 0; - -err_free_irqs: - while (--rxq >= 0) - free_irq(adapter->msix_info[--msi].vec, &s->ethrxq[rxq].rspq); - free_irq(adapter->msix_info[MSIX_FW].vec, &s->fw_evtq); - return err; -} - -/* - * Free our MSI-X resources. - */ -static void free_msix_queue_irqs(struct adapter *adapter) -{ - struct sge *s = &adapter->sge; - int rxq, msi; - - free_irq(adapter->msix_info[MSIX_FW].vec, &s->fw_evtq); - msi = MSIX_IQFLINT; - for_each_ethrxq(s, rxq) - free_irq(adapter->msix_info[msi++].vec, - &s->ethrxq[rxq].rspq); -} - -/* - * Turn on NAPI and start up interrupts on a response queue. - */ -static void qenable(struct sge_rspq *rspq) -{ - napi_enable(&rspq->napi); - - /* - * 0-increment the Going To Sleep register to start the timer and - * enable interrupts. - */ - t4_write_reg(rspq->adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS, - CIDXINC(0) | - SEINTARM(rspq->intr_params) | - INGRESSQID(rspq->cntxt_id)); -} - -/* - * Enable NAPI scheduling and interrupt generation for all Receive Queues. - */ -static void enable_rx(struct adapter *adapter) -{ - int rxq; - struct sge *s = &adapter->sge; - - for_each_ethrxq(s, rxq) - qenable(&s->ethrxq[rxq].rspq); - qenable(&s->fw_evtq); - - /* - * The interrupt queue doesn't use NAPI so we do the 0-increment of - * its Going To Sleep register here to get it started. - */ - if (adapter->flags & USING_MSI) - t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS, - CIDXINC(0) | - SEINTARM(s->intrq.intr_params) | - INGRESSQID(s->intrq.cntxt_id)); - -} - -/* - * Wait until all NAPI handlers are descheduled. - */ -static void quiesce_rx(struct adapter *adapter) -{ - struct sge *s = &adapter->sge; - int rxq; - - for_each_ethrxq(s, rxq) - napi_disable(&s->ethrxq[rxq].rspq.napi); - napi_disable(&s->fw_evtq.napi); -} - -/* - * Response queue handler for the firmware event queue. - */ -static int fwevtq_handler(struct sge_rspq *rspq, const __be64 *rsp, - const struct pkt_gl *gl) -{ - /* - * Extract response opcode and get pointer to CPL message body. - */ - struct adapter *adapter = rspq->adapter; - u8 opcode = ((const struct rss_header *)rsp)->opcode; - void *cpl = (void *)(rsp + 1); - - switch (opcode) { - case CPL_FW6_MSG: { - /* - * We've received an asynchronous message from the firmware. - */ - const struct cpl_fw6_msg *fw_msg = cpl; - if (fw_msg->type == FW6_TYPE_CMD_RPL) - t4vf_handle_fw_rpl(adapter, fw_msg->data); - break; - } - - case CPL_SGE_EGR_UPDATE: { - /* - * We've received an Egress Queue Status Update message. We - * get these, if the SGE is configured to send these when the - * firmware passes certain points in processing our TX - * Ethernet Queue or if we make an explicit request for one. - * We use these updates to determine when we may need to - * restart a TX Ethernet Queue which was stopped for lack of - * free TX Queue Descriptors ... - */ - const struct cpl_sge_egr_update *p = (void *)cpl; - unsigned int qid = EGR_QID(be32_to_cpu(p->opcode_qid)); - struct sge *s = &adapter->sge; - struct sge_txq *tq; - struct sge_eth_txq *txq; - unsigned int eq_idx; - - /* - * Perform sanity checking on the Queue ID to make sure it - * really refers to one of our TX Ethernet Egress Queues which - * is active and matches the queue's ID. None of these error - * conditions should ever happen so we may want to either make - * them fatal and/or conditionalized under DEBUG. - */ - eq_idx = EQ_IDX(s, qid); - if (unlikely(eq_idx >= MAX_EGRQ)) { - dev_err(adapter->pdev_dev, - "Egress Update QID %d out of range\n", qid); - break; - } - tq = s->egr_map[eq_idx]; - if (unlikely(tq == NULL)) { - dev_err(adapter->pdev_dev, - "Egress Update QID %d TXQ=NULL\n", qid); - break; - } - txq = container_of(tq, struct sge_eth_txq, q); - if (unlikely(tq->abs_id != qid)) { - dev_err(adapter->pdev_dev, - "Egress Update QID %d refers to TXQ %d\n", - qid, tq->abs_id); - break; - } - - /* - * Restart a stopped TX Queue which has less than half of its - * TX ring in use ... - */ - txq->q.restarts++; - netif_tx_wake_queue(txq->txq); - break; - } - - default: - dev_err(adapter->pdev_dev, - "unexpected CPL %#x on FW event queue\n", opcode); - } - - return 0; -} - -/* - * Allocate SGE TX/RX response queues. Determine how many sets of SGE queues - * to use and initializes them. We support multiple "Queue Sets" per port if - * we have MSI-X, otherwise just one queue set per port. - */ -static int setup_sge_queues(struct adapter *adapter) -{ - struct sge *s = &adapter->sge; - int err, pidx, msix; - - /* - * Clear "Queue Set" Free List Starving and TX Queue Mapping Error - * state. - */ - bitmap_zero(s->starving_fl, MAX_EGRQ); - - /* - * If we're using MSI interrupt mode we need to set up a "forwarded - * interrupt" queue which we'll set up with our MSI vector. The rest - * of the ingress queues will be set up to forward their interrupts to - * this queue ... This must be first since t4vf_sge_alloc_rxq() uses - * the intrq's queue ID as the interrupt forwarding queue for the - * subsequent calls ... - */ - if (adapter->flags & USING_MSI) { - err = t4vf_sge_alloc_rxq(adapter, &s->intrq, false, - adapter->port[0], 0, NULL, NULL); - if (err) - goto err_free_queues; - } - - /* - * Allocate our ingress queue for asynchronous firmware messages. - */ - err = t4vf_sge_alloc_rxq(adapter, &s->fw_evtq, true, adapter->port[0], - MSIX_FW, NULL, fwevtq_handler); - if (err) - goto err_free_queues; - - /* - * Allocate each "port"'s initial Queue Sets. These can be changed - * later on ... up to the point where any interface on the adapter is - * brought up at which point lots of things get nailed down - * permanently ... - */ - msix = MSIX_IQFLINT; - for_each_port(adapter, pidx) { - struct net_device *dev = adapter->port[pidx]; - struct port_info *pi = netdev_priv(dev); - struct sge_eth_rxq *rxq = &s->ethrxq[pi->first_qset]; - struct sge_eth_txq *txq = &s->ethtxq[pi->first_qset]; - int qs; - - for (qs = 0; qs < pi->nqsets; qs++, rxq++, txq++) { - err = t4vf_sge_alloc_rxq(adapter, &rxq->rspq, false, - dev, msix++, - &rxq->fl, t4vf_ethrx_handler); - if (err) - goto err_free_queues; - - err = t4vf_sge_alloc_eth_txq(adapter, txq, dev, - netdev_get_tx_queue(dev, qs), - s->fw_evtq.cntxt_id); - if (err) - goto err_free_queues; - - rxq->rspq.idx = qs; - memset(&rxq->stats, 0, sizeof(rxq->stats)); - } - } - - /* - * Create the reverse mappings for the queues. - */ - s->egr_base = s->ethtxq[0].q.abs_id - s->ethtxq[0].q.cntxt_id; - s->ingr_base = s->ethrxq[0].rspq.abs_id - s->ethrxq[0].rspq.cntxt_id; - IQ_MAP(s, s->fw_evtq.abs_id) = &s->fw_evtq; - for_each_port(adapter, pidx) { - struct net_device *dev = adapter->port[pidx]; - struct port_info *pi = netdev_priv(dev); - struct sge_eth_rxq *rxq = &s->ethrxq[pi->first_qset]; - struct sge_eth_txq *txq = &s->ethtxq[pi->first_qset]; - int qs; - - for (qs = 0; qs < pi->nqsets; qs++, rxq++, txq++) { - IQ_MAP(s, rxq->rspq.abs_id) = &rxq->rspq; - EQ_MAP(s, txq->q.abs_id) = &txq->q; - - /* - * The FW_IQ_CMD doesn't return the Absolute Queue IDs - * for Free Lists but since all of the Egress Queues - * (including Free Lists) have Relative Queue IDs - * which are computed as Absolute - Base Queue ID, we - * can synthesize the Absolute Queue IDs for the Free - * Lists. This is useful for debugging purposes when - * we want to dump Queue Contexts via the PF Driver. - */ - rxq->fl.abs_id = rxq->fl.cntxt_id + s->egr_base; - EQ_MAP(s, rxq->fl.abs_id) = &rxq->fl; - } - } - return 0; - -err_free_queues: - t4vf_free_sge_resources(adapter); - return err; -} - -/* - * Set up Receive Side Scaling (RSS) to distribute packets to multiple receive - * queues. We configure the RSS CPU lookup table to distribute to the number - * of HW receive queues, and the response queue lookup table to narrow that - * down to the response queues actually configured for each "port" (Virtual - * Interface). We always configure the RSS mapping for all ports since the - * mapping table has plenty of entries. - */ -static int setup_rss(struct adapter *adapter) -{ - int pidx; - - for_each_port(adapter, pidx) { - struct port_info *pi = adap2pinfo(adapter, pidx); - struct sge_eth_rxq *rxq = &adapter->sge.ethrxq[pi->first_qset]; - u16 rss[MAX_PORT_QSETS]; - int qs, err; - - for (qs = 0; qs < pi->nqsets; qs++) - rss[qs] = rxq[qs].rspq.abs_id; - - err = t4vf_config_rss_range(adapter, pi->viid, - 0, pi->rss_size, rss, pi->nqsets); - if (err) - return err; - - /* - * Perform Global RSS Mode-specific initialization. - */ - switch (adapter->params.rss.mode) { - case FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL: - /* - * If Tunnel All Lookup isn't specified in the global - * RSS Configuration, then we need to specify a - * default Ingress Queue for any ingress packets which - * aren't hashed. We'll use our first ingress queue - * ... - */ - if (!adapter->params.rss.u.basicvirtual.tnlalllookup) { - union rss_vi_config config; - err = t4vf_read_rss_vi_config(adapter, - pi->viid, - &config); - if (err) - return err; - config.basicvirtual.defaultq = - rxq[0].rspq.abs_id; - err = t4vf_write_rss_vi_config(adapter, - pi->viid, - &config); - if (err) - return err; - } - break; - } - } - - return 0; -} - -/* - * Bring the adapter up. Called whenever we go from no "ports" open to having - * one open. This function performs the actions necessary to make an adapter - * operational, such as completing the initialization of HW modules, and - * enabling interrupts. Must be called with the rtnl lock held. (Note that - * this is called "cxgb_up" in the PF Driver.) - */ -static int adapter_up(struct adapter *adapter) -{ - int err; - - /* - * If this is the first time we've been called, perform basic - * adapter setup. Once we've done this, many of our adapter - * parameters can no longer be changed ... - */ - if ((adapter->flags & FULL_INIT_DONE) == 0) { - err = setup_sge_queues(adapter); - if (err) - return err; - err = setup_rss(adapter); - if (err) { - t4vf_free_sge_resources(adapter); - return err; - } - - if (adapter->flags & USING_MSIX) - name_msix_vecs(adapter); - adapter->flags |= FULL_INIT_DONE; - } - - /* - * Acquire our interrupt resources. We only support MSI-X and MSI. - */ - BUG_ON((adapter->flags & (USING_MSIX|USING_MSI)) == 0); - if (adapter->flags & USING_MSIX) - err = request_msix_queue_irqs(adapter); - else - err = request_irq(adapter->pdev->irq, - t4vf_intr_handler(adapter), 0, - adapter->name, adapter); - if (err) { - dev_err(adapter->pdev_dev, "request_irq failed, err %d\n", - err); - return err; - } - - /* - * Enable NAPI ingress processing and return success. - */ - enable_rx(adapter); - t4vf_sge_start(adapter); - return 0; -} - -/* - * Bring the adapter down. Called whenever the last "port" (Virtual - * Interface) closed. (Note that this routine is called "cxgb_down" in the PF - * Driver.) - */ -static void adapter_down(struct adapter *adapter) -{ - /* - * Free interrupt resources. - */ - if (adapter->flags & USING_MSIX) - free_msix_queue_irqs(adapter); - else - free_irq(adapter->pdev->irq, adapter); - - /* - * Wait for NAPI handlers to finish. - */ - quiesce_rx(adapter); -} - -/* - * Start up a net device. - */ -static int cxgb4vf_open(struct net_device *dev) -{ - int err; - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - - /* - * If this is the first interface that we're opening on the "adapter", - * bring the "adapter" up now. - */ - if (adapter->open_device_map == 0) { - err = adapter_up(adapter); - if (err) - return err; - } - - /* - * Note that this interface is up and start everything up ... - */ - netif_set_real_num_tx_queues(dev, pi->nqsets); - err = netif_set_real_num_rx_queues(dev, pi->nqsets); - if (err) - goto err_unwind; - err = link_start(dev); - if (err) - goto err_unwind; - - netif_tx_start_all_queues(dev); - set_bit(pi->port_id, &adapter->open_device_map); - return 0; - -err_unwind: - if (adapter->open_device_map == 0) - adapter_down(adapter); - return err; -} - -/* - * Shut down a net device. This routine is called "cxgb_close" in the PF - * Driver ... - */ -static int cxgb4vf_stop(struct net_device *dev) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - - netif_tx_stop_all_queues(dev); - netif_carrier_off(dev); - t4vf_enable_vi(adapter, pi->viid, false, false); - pi->link_cfg.link_ok = 0; - - clear_bit(pi->port_id, &adapter->open_device_map); - if (adapter->open_device_map == 0) - adapter_down(adapter); - return 0; -} - -/* - * Translate our basic statistics into the standard "ifconfig" statistics. - */ -static struct net_device_stats *cxgb4vf_get_stats(struct net_device *dev) -{ - struct t4vf_port_stats stats; - struct port_info *pi = netdev2pinfo(dev); - struct adapter *adapter = pi->adapter; - struct net_device_stats *ns = &dev->stats; - int err; - - spin_lock(&adapter->stats_lock); - err = t4vf_get_port_stats(adapter, pi->pidx, &stats); - spin_unlock(&adapter->stats_lock); - - memset(ns, 0, sizeof(*ns)); - if (err) - return ns; - - ns->tx_bytes = (stats.tx_bcast_bytes + stats.tx_mcast_bytes + - stats.tx_ucast_bytes + stats.tx_offload_bytes); - ns->tx_packets = (stats.tx_bcast_frames + stats.tx_mcast_frames + - stats.tx_ucast_frames + stats.tx_offload_frames); - ns->rx_bytes = (stats.rx_bcast_bytes + stats.rx_mcast_bytes + - stats.rx_ucast_bytes); - ns->rx_packets = (stats.rx_bcast_frames + stats.rx_mcast_frames + - stats.rx_ucast_frames); - ns->multicast = stats.rx_mcast_frames; - ns->tx_errors = stats.tx_drop_frames; - ns->rx_errors = stats.rx_err_frames; - - return ns; -} - -/* - * Collect up to maxaddrs worth of a netdevice's unicast addresses, starting - * at a specified offset within the list, into an array of addrss pointers and - * return the number collected. - */ -static inline unsigned int collect_netdev_uc_list_addrs(const struct net_device *dev, - const u8 **addr, - unsigned int offset, - unsigned int maxaddrs) -{ - unsigned int index = 0; - unsigned int naddr = 0; - const struct netdev_hw_addr *ha; - - for_each_dev_addr(dev, ha) - if (index++ >= offset) { - addr[naddr++] = ha->addr; - if (naddr >= maxaddrs) - break; - } - return naddr; -} - -/* - * Collect up to maxaddrs worth of a netdevice's multicast addresses, starting - * at a specified offset within the list, into an array of addrss pointers and - * return the number collected. - */ -static inline unsigned int collect_netdev_mc_list_addrs(const struct net_device *dev, - const u8 **addr, - unsigned int offset, - unsigned int maxaddrs) -{ - unsigned int index = 0; - unsigned int naddr = 0; - const struct netdev_hw_addr *ha; - - netdev_for_each_mc_addr(ha, dev) - if (index++ >= offset) { - addr[naddr++] = ha->addr; - if (naddr >= maxaddrs) - break; - } - return naddr; -} - -/* - * Configure the exact and hash address filters to handle a port's multicast - * and secondary unicast MAC addresses. - */ -static int set_addr_filters(const struct net_device *dev, bool sleep) -{ - u64 mhash = 0; - u64 uhash = 0; - bool free = true; - unsigned int offset, naddr; - const u8 *addr[7]; - int ret; - const struct port_info *pi = netdev_priv(dev); - - /* first do the secondary unicast addresses */ - for (offset = 0; ; offset += naddr) { - naddr = collect_netdev_uc_list_addrs(dev, addr, offset, - ARRAY_SIZE(addr)); - if (naddr == 0) - break; - - ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free, - naddr, addr, NULL, &uhash, sleep); - if (ret < 0) - return ret; - - free = false; - } - - /* next set up the multicast addresses */ - for (offset = 0; ; offset += naddr) { - naddr = collect_netdev_mc_list_addrs(dev, addr, offset, - ARRAY_SIZE(addr)); - if (naddr == 0) - break; - - ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free, - naddr, addr, NULL, &mhash, sleep); - if (ret < 0) - return ret; - free = false; - } - - return t4vf_set_addr_hash(pi->adapter, pi->viid, uhash != 0, - uhash | mhash, sleep); -} - -/* - * Set RX properties of a port, such as promiscruity, address filters, and MTU. - * If @mtu is -1 it is left unchanged. - */ -static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok) -{ - int ret; - struct port_info *pi = netdev_priv(dev); - - ret = set_addr_filters(dev, sleep_ok); - if (ret == 0) - ret = t4vf_set_rxmode(pi->adapter, pi->viid, -1, - (dev->flags & IFF_PROMISC) != 0, - (dev->flags & IFF_ALLMULTI) != 0, - 1, -1, sleep_ok); - return ret; -} - -/* - * Set the current receive modes on the device. - */ -static void cxgb4vf_set_rxmode(struct net_device *dev) -{ - /* unfortunately we can't return errors to the stack */ - set_rxmode(dev, -1, false); -} - -/* - * Find the entry in the interrupt holdoff timer value array which comes - * closest to the specified interrupt holdoff value. - */ -static int closest_timer(const struct sge *s, int us) -{ - int i, timer_idx = 0, min_delta = INT_MAX; - - for (i = 0; i < ARRAY_SIZE(s->timer_val); i++) { - int delta = us - s->timer_val[i]; - if (delta < 0) - delta = -delta; - if (delta < min_delta) { - min_delta = delta; - timer_idx = i; - } - } - return timer_idx; -} - -static int closest_thres(const struct sge *s, int thres) -{ - int i, delta, pktcnt_idx = 0, min_delta = INT_MAX; - - for (i = 0; i < ARRAY_SIZE(s->counter_val); i++) { - delta = thres - s->counter_val[i]; - if (delta < 0) - delta = -delta; - if (delta < min_delta) { - min_delta = delta; - pktcnt_idx = i; - } - } - return pktcnt_idx; -} - -/* - * Return a queue's interrupt hold-off time in us. 0 means no timer. - */ -static unsigned int qtimer_val(const struct adapter *adapter, - const struct sge_rspq *rspq) -{ - unsigned int timer_idx = QINTR_TIMER_IDX_GET(rspq->intr_params); - - return timer_idx < SGE_NTIMERS - ? adapter->sge.timer_val[timer_idx] - : 0; -} - -/** - * set_rxq_intr_params - set a queue's interrupt holdoff parameters - * @adapter: the adapter - * @rspq: the RX response queue - * @us: the hold-off time in us, or 0 to disable timer - * @cnt: the hold-off packet count, or 0 to disable counter - * - * Sets an RX response queue's interrupt hold-off time and packet count. - * At least one of the two needs to be enabled for the queue to generate - * interrupts. - */ -static int set_rxq_intr_params(struct adapter *adapter, struct sge_rspq *rspq, - unsigned int us, unsigned int cnt) -{ - unsigned int timer_idx; - - /* - * If both the interrupt holdoff timer and count are specified as - * zero, default to a holdoff count of 1 ... - */ - if ((us | cnt) == 0) - cnt = 1; - - /* - * If an interrupt holdoff count has been specified, then find the - * closest configured holdoff count and use that. If the response - * queue has already been created, then update its queue context - * parameters ... - */ - if (cnt) { - int err; - u32 v, pktcnt_idx; - - pktcnt_idx = closest_thres(&adapter->sge, cnt); - if (rspq->desc && rspq->pktcnt_idx != pktcnt_idx) { - v = FW_PARAMS_MNEM(FW_PARAMS_MNEM_DMAQ) | - FW_PARAMS_PARAM_X( - FW_PARAMS_PARAM_DMAQ_IQ_INTCNTTHRESH) | - FW_PARAMS_PARAM_YZ(rspq->cntxt_id); - err = t4vf_set_params(adapter, 1, &v, &pktcnt_idx); - if (err) - return err; - } - rspq->pktcnt_idx = pktcnt_idx; - } - - /* - * Compute the closest holdoff timer index from the supplied holdoff - * timer value. - */ - timer_idx = (us == 0 - ? SGE_TIMER_RSTRT_CNTR - : closest_timer(&adapter->sge, us)); - - /* - * Update the response queue's interrupt coalescing parameters and - * return success. - */ - rspq->intr_params = (QINTR_TIMER_IDX(timer_idx) | - (cnt > 0 ? QINTR_CNT_EN : 0)); - return 0; -} - -/* - * Return a version number to identify the type of adapter. The scheme is: - * - bits 0..9: chip version - * - bits 10..15: chip revision - */ -static inline unsigned int mk_adap_vers(const struct adapter *adapter) -{ - /* - * Chip version 4, revision 0x3f (cxgb4vf). - */ - return 4 | (0x3f << 10); -} - -/* - * Execute the specified ioctl command. - */ -static int cxgb4vf_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - int ret = 0; - - switch (cmd) { - /* - * The VF Driver doesn't have access to any of the other - * common Ethernet device ioctl()'s (like reading/writing - * PHY registers, etc. - */ - - default: - ret = -EOPNOTSUPP; - break; - } - return ret; -} - -/* - * Change the device's MTU. - */ -static int cxgb4vf_change_mtu(struct net_device *dev, int new_mtu) -{ - int ret; - struct port_info *pi = netdev_priv(dev); - - /* accommodate SACK */ - if (new_mtu < 81) - return -EINVAL; - - ret = t4vf_set_rxmode(pi->adapter, pi->viid, new_mtu, - -1, -1, -1, -1, true); - if (!ret) - dev->mtu = new_mtu; - return ret; -} - -static u32 cxgb4vf_fix_features(struct net_device *dev, u32 features) -{ - /* - * Since there is no support for separate rx/tx vlan accel - * enable/disable make sure tx flag is always in same state as rx. - */ - if (features & NETIF_F_HW_VLAN_RX) - features |= NETIF_F_HW_VLAN_TX; - else - features &= ~NETIF_F_HW_VLAN_TX; - - return features; -} - -static int cxgb4vf_set_features(struct net_device *dev, u32 features) -{ - struct port_info *pi = netdev_priv(dev); - u32 changed = dev->features ^ features; - - if (changed & NETIF_F_HW_VLAN_RX) - t4vf_set_rxmode(pi->adapter, pi->viid, -1, -1, -1, -1, - features & NETIF_F_HW_VLAN_TX, 0); - - return 0; -} - -/* - * Change the devices MAC address. - */ -static int cxgb4vf_set_mac_addr(struct net_device *dev, void *_addr) -{ - int ret; - struct sockaddr *addr = _addr; - struct port_info *pi = netdev_priv(dev); - - if (!is_valid_ether_addr(addr->sa_data)) - return -EINVAL; - - ret = t4vf_change_mac(pi->adapter, pi->viid, pi->xact_addr_filt, - addr->sa_data, true); - if (ret < 0) - return ret; - - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - pi->xact_addr_filt = ret; - return 0; -} - -#ifdef CONFIG_NET_POLL_CONTROLLER -/* - * Poll all of our receive queues. This is called outside of normal interrupt - * context. - */ -static void cxgb4vf_poll_controller(struct net_device *dev) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - - if (adapter->flags & USING_MSIX) { - struct sge_eth_rxq *rxq; - int nqsets; - - rxq = &adapter->sge.ethrxq[pi->first_qset]; - for (nqsets = pi->nqsets; nqsets; nqsets--) { - t4vf_sge_intr_msix(0, &rxq->rspq); - rxq++; - } - } else - t4vf_intr_handler(adapter)(0, adapter); -} -#endif - -/* - * Ethtool operations. - * =================== - * - * Note that we don't support any ethtool operations which change the physical - * state of the port to which we're linked. - */ - -/* - * Return current port link settings. - */ -static int cxgb4vf_get_settings(struct net_device *dev, - struct ethtool_cmd *cmd) -{ - const struct port_info *pi = netdev_priv(dev); - - cmd->supported = pi->link_cfg.supported; - cmd->advertising = pi->link_cfg.advertising; - ethtool_cmd_speed_set(cmd, - netif_carrier_ok(dev) ? pi->link_cfg.speed : -1); - cmd->duplex = DUPLEX_FULL; - - cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE; - cmd->phy_address = pi->port_id; - cmd->transceiver = XCVR_EXTERNAL; - cmd->autoneg = pi->link_cfg.autoneg; - cmd->maxtxpkt = 0; - cmd->maxrxpkt = 0; - return 0; -} - -/* - * Return our driver information. - */ -static void cxgb4vf_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *drvinfo) -{ - struct adapter *adapter = netdev2adap(dev); - - strcpy(drvinfo->driver, KBUILD_MODNAME); - strcpy(drvinfo->version, DRV_VERSION); - strcpy(drvinfo->bus_info, pci_name(to_pci_dev(dev->dev.parent))); - snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), - "%u.%u.%u.%u, TP %u.%u.%u.%u", - FW_HDR_FW_VER_MAJOR_GET(adapter->params.dev.fwrev), - FW_HDR_FW_VER_MINOR_GET(adapter->params.dev.fwrev), - FW_HDR_FW_VER_MICRO_GET(adapter->params.dev.fwrev), - FW_HDR_FW_VER_BUILD_GET(adapter->params.dev.fwrev), - FW_HDR_FW_VER_MAJOR_GET(adapter->params.dev.tprev), - FW_HDR_FW_VER_MINOR_GET(adapter->params.dev.tprev), - FW_HDR_FW_VER_MICRO_GET(adapter->params.dev.tprev), - FW_HDR_FW_VER_BUILD_GET(adapter->params.dev.tprev)); -} - -/* - * Return current adapter message level. - */ -static u32 cxgb4vf_get_msglevel(struct net_device *dev) -{ - return netdev2adap(dev)->msg_enable; -} - -/* - * Set current adapter message level. - */ -static void cxgb4vf_set_msglevel(struct net_device *dev, u32 msglevel) -{ - netdev2adap(dev)->msg_enable = msglevel; -} - -/* - * Return the device's current Queue Set ring size parameters along with the - * allowed maximum values. Since ethtool doesn't understand the concept of - * multi-queue devices, we just return the current values associated with the - * first Queue Set. - */ -static void cxgb4vf_get_ringparam(struct net_device *dev, - struct ethtool_ringparam *rp) -{ - const struct port_info *pi = netdev_priv(dev); - const struct sge *s = &pi->adapter->sge; - - rp->rx_max_pending = MAX_RX_BUFFERS; - rp->rx_mini_max_pending = MAX_RSPQ_ENTRIES; - rp->rx_jumbo_max_pending = 0; - rp->tx_max_pending = MAX_TXQ_ENTRIES; - - rp->rx_pending = s->ethrxq[pi->first_qset].fl.size - MIN_FL_RESID; - rp->rx_mini_pending = s->ethrxq[pi->first_qset].rspq.size; - rp->rx_jumbo_pending = 0; - rp->tx_pending = s->ethtxq[pi->first_qset].q.size; -} - -/* - * Set the Queue Set ring size parameters for the device. Again, since - * ethtool doesn't allow for the concept of multiple queues per device, we'll - * apply these new values across all of the Queue Sets associated with the - * device -- after vetting them of course! - */ -static int cxgb4vf_set_ringparam(struct net_device *dev, - struct ethtool_ringparam *rp) -{ - const struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - struct sge *s = &adapter->sge; - int qs; - - if (rp->rx_pending > MAX_RX_BUFFERS || - rp->rx_jumbo_pending || - rp->tx_pending > MAX_TXQ_ENTRIES || - rp->rx_mini_pending > MAX_RSPQ_ENTRIES || - rp->rx_mini_pending < MIN_RSPQ_ENTRIES || - rp->rx_pending < MIN_FL_ENTRIES || - rp->tx_pending < MIN_TXQ_ENTRIES) - return -EINVAL; - - if (adapter->flags & FULL_INIT_DONE) - return -EBUSY; - - for (qs = pi->first_qset; qs < pi->first_qset + pi->nqsets; qs++) { - s->ethrxq[qs].fl.size = rp->rx_pending + MIN_FL_RESID; - s->ethrxq[qs].rspq.size = rp->rx_mini_pending; - s->ethtxq[qs].q.size = rp->tx_pending; - } - return 0; -} - -/* - * Return the interrupt holdoff timer and count for the first Queue Set on the - * device. Our extension ioctl() (the cxgbtool interface) allows the - * interrupt holdoff timer to be read on all of the device's Queue Sets. - */ -static int cxgb4vf_get_coalesce(struct net_device *dev, - struct ethtool_coalesce *coalesce) -{ - const struct port_info *pi = netdev_priv(dev); - const struct adapter *adapter = pi->adapter; - const struct sge_rspq *rspq = &adapter->sge.ethrxq[pi->first_qset].rspq; - - coalesce->rx_coalesce_usecs = qtimer_val(adapter, rspq); - coalesce->rx_max_coalesced_frames = - ((rspq->intr_params & QINTR_CNT_EN) - ? adapter->sge.counter_val[rspq->pktcnt_idx] - : 0); - return 0; -} - -/* - * Set the RX interrupt holdoff timer and count for the first Queue Set on the - * interface. Our extension ioctl() (the cxgbtool interface) allows us to set - * the interrupt holdoff timer on any of the device's Queue Sets. - */ -static int cxgb4vf_set_coalesce(struct net_device *dev, - struct ethtool_coalesce *coalesce) -{ - const struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - - return set_rxq_intr_params(adapter, - &adapter->sge.ethrxq[pi->first_qset].rspq, - coalesce->rx_coalesce_usecs, - coalesce->rx_max_coalesced_frames); -} - -/* - * Report current port link pause parameter settings. - */ -static void cxgb4vf_get_pauseparam(struct net_device *dev, - struct ethtool_pauseparam *pauseparam) -{ - struct port_info *pi = netdev_priv(dev); - - pauseparam->autoneg = (pi->link_cfg.requested_fc & PAUSE_AUTONEG) != 0; - pauseparam->rx_pause = (pi->link_cfg.fc & PAUSE_RX) != 0; - pauseparam->tx_pause = (pi->link_cfg.fc & PAUSE_TX) != 0; -} - -/* - * Identify the port by blinking the port's LED. - */ -static int cxgb4vf_phys_id(struct net_device *dev, - enum ethtool_phys_id_state state) -{ - unsigned int val; - struct port_info *pi = netdev_priv(dev); - - if (state == ETHTOOL_ID_ACTIVE) - val = 0xffff; - else if (state == ETHTOOL_ID_INACTIVE) - val = 0; - else - return -EINVAL; - - return t4vf_identify_port(pi->adapter, pi->viid, val); -} - -/* - * Port stats maintained per queue of the port. - */ -struct queue_port_stats { - u64 tso; - u64 tx_csum; - u64 rx_csum; - u64 vlan_ex; - u64 vlan_ins; - u64 lro_pkts; - u64 lro_merged; -}; - -/* - * Strings for the ETH_SS_STATS statistics set ("ethtool -S"). Note that - * these need to match the order of statistics returned by - * t4vf_get_port_stats(). - */ -static const char stats_strings[][ETH_GSTRING_LEN] = { - /* - * These must match the layout of the t4vf_port_stats structure. - */ - "TxBroadcastBytes ", - "TxBroadcastFrames ", - "TxMulticastBytes ", - "TxMulticastFrames ", - "TxUnicastBytes ", - "TxUnicastFrames ", - "TxDroppedFrames ", - "TxOffloadBytes ", - "TxOffloadFrames ", - "RxBroadcastBytes ", - "RxBroadcastFrames ", - "RxMulticastBytes ", - "RxMulticastFrames ", - "RxUnicastBytes ", - "RxUnicastFrames ", - "RxErrorFrames ", - - /* - * These are accumulated per-queue statistics and must match the - * order of the fields in the queue_port_stats structure. - */ - "TSO ", - "TxCsumOffload ", - "RxCsumGood ", - "VLANextractions ", - "VLANinsertions ", - "GROPackets ", - "GROMerged ", -}; - -/* - * Return the number of statistics in the specified statistics set. - */ -static int cxgb4vf_get_sset_count(struct net_device *dev, int sset) -{ - switch (sset) { - case ETH_SS_STATS: - return ARRAY_SIZE(stats_strings); - default: - return -EOPNOTSUPP; - } - /*NOTREACHED*/ -} - -/* - * Return the strings for the specified statistics set. - */ -static void cxgb4vf_get_strings(struct net_device *dev, - u32 sset, - u8 *data) -{ - switch (sset) { - case ETH_SS_STATS: - memcpy(data, stats_strings, sizeof(stats_strings)); - break; - } -} - -/* - * Small utility routine to accumulate queue statistics across the queues of - * a "port". - */ -static void collect_sge_port_stats(const struct adapter *adapter, - const struct port_info *pi, - struct queue_port_stats *stats) -{ - const struct sge_eth_txq *txq = &adapter->sge.ethtxq[pi->first_qset]; - const struct sge_eth_rxq *rxq = &adapter->sge.ethrxq[pi->first_qset]; - int qs; - - memset(stats, 0, sizeof(*stats)); - for (qs = 0; qs < pi->nqsets; qs++, rxq++, txq++) { - stats->tso += txq->tso; - stats->tx_csum += txq->tx_cso; - stats->rx_csum += rxq->stats.rx_cso; - stats->vlan_ex += rxq->stats.vlan_ex; - stats->vlan_ins += txq->vlan_ins; - stats->lro_pkts += rxq->stats.lro_pkts; - stats->lro_merged += rxq->stats.lro_merged; - } -} - -/* - * Return the ETH_SS_STATS statistics set. - */ -static void cxgb4vf_get_ethtool_stats(struct net_device *dev, - struct ethtool_stats *stats, - u64 *data) -{ - struct port_info *pi = netdev2pinfo(dev); - struct adapter *adapter = pi->adapter; - int err = t4vf_get_port_stats(adapter, pi->pidx, - (struct t4vf_port_stats *)data); - if (err) - memset(data, 0, sizeof(struct t4vf_port_stats)); - - data += sizeof(struct t4vf_port_stats) / sizeof(u64); - collect_sge_port_stats(adapter, pi, (struct queue_port_stats *)data); -} - -/* - * Return the size of our register map. - */ -static int cxgb4vf_get_regs_len(struct net_device *dev) -{ - return T4VF_REGMAP_SIZE; -} - -/* - * Dump a block of registers, start to end inclusive, into a buffer. - */ -static void reg_block_dump(struct adapter *adapter, void *regbuf, - unsigned int start, unsigned int end) -{ - u32 *bp = regbuf + start - T4VF_REGMAP_START; - - for ( ; start <= end; start += sizeof(u32)) { - /* - * Avoid reading the Mailbox Control register since that - * can trigger a Mailbox Ownership Arbitration cycle and - * interfere with communication with the firmware. - */ - if (start == T4VF_CIM_BASE_ADDR + CIM_VF_EXT_MAILBOX_CTRL) - *bp++ = 0xffff; - else - *bp++ = t4_read_reg(adapter, start); - } -} - -/* - * Copy our entire register map into the provided buffer. - */ -static void cxgb4vf_get_regs(struct net_device *dev, - struct ethtool_regs *regs, - void *regbuf) -{ - struct adapter *adapter = netdev2adap(dev); - - regs->version = mk_adap_vers(adapter); - - /* - * Fill in register buffer with our register map. - */ - memset(regbuf, 0, T4VF_REGMAP_SIZE); - - reg_block_dump(adapter, regbuf, - T4VF_SGE_BASE_ADDR + T4VF_MOD_MAP_SGE_FIRST, - T4VF_SGE_BASE_ADDR + T4VF_MOD_MAP_SGE_LAST); - reg_block_dump(adapter, regbuf, - T4VF_MPS_BASE_ADDR + T4VF_MOD_MAP_MPS_FIRST, - T4VF_MPS_BASE_ADDR + T4VF_MOD_MAP_MPS_LAST); - reg_block_dump(adapter, regbuf, - T4VF_PL_BASE_ADDR + T4VF_MOD_MAP_PL_FIRST, - T4VF_PL_BASE_ADDR + T4VF_MOD_MAP_PL_LAST); - reg_block_dump(adapter, regbuf, - T4VF_CIM_BASE_ADDR + T4VF_MOD_MAP_CIM_FIRST, - T4VF_CIM_BASE_ADDR + T4VF_MOD_MAP_CIM_LAST); - - reg_block_dump(adapter, regbuf, - T4VF_MBDATA_BASE_ADDR + T4VF_MBDATA_FIRST, - T4VF_MBDATA_BASE_ADDR + T4VF_MBDATA_LAST); -} - -/* - * Report current Wake On LAN settings. - */ -static void cxgb4vf_get_wol(struct net_device *dev, - struct ethtool_wolinfo *wol) -{ - wol->supported = 0; - wol->wolopts = 0; - memset(&wol->sopass, 0, sizeof(wol->sopass)); -} - -/* - * TCP Segmentation Offload flags which we support. - */ -#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN) - -static struct ethtool_ops cxgb4vf_ethtool_ops = { - .get_settings = cxgb4vf_get_settings, - .get_drvinfo = cxgb4vf_get_drvinfo, - .get_msglevel = cxgb4vf_get_msglevel, - .set_msglevel = cxgb4vf_set_msglevel, - .get_ringparam = cxgb4vf_get_ringparam, - .set_ringparam = cxgb4vf_set_ringparam, - .get_coalesce = cxgb4vf_get_coalesce, - .set_coalesce = cxgb4vf_set_coalesce, - .get_pauseparam = cxgb4vf_get_pauseparam, - .get_link = ethtool_op_get_link, - .get_strings = cxgb4vf_get_strings, - .set_phys_id = cxgb4vf_phys_id, - .get_sset_count = cxgb4vf_get_sset_count, - .get_ethtool_stats = cxgb4vf_get_ethtool_stats, - .get_regs_len = cxgb4vf_get_regs_len, - .get_regs = cxgb4vf_get_regs, - .get_wol = cxgb4vf_get_wol, -}; - -/* - * /sys/kernel/debug/cxgb4vf support code and data. - * ================================================ - */ - -/* - * Show SGE Queue Set information. We display QPL Queues Sets per line. - */ -#define QPL 4 - -static int sge_qinfo_show(struct seq_file *seq, void *v) -{ - struct adapter *adapter = seq->private; - int eth_entries = DIV_ROUND_UP(adapter->sge.ethqsets, QPL); - int qs, r = (uintptr_t)v - 1; - - if (r) - seq_putc(seq, '\n'); - - #define S3(fmt_spec, s, v) \ - do {\ - seq_printf(seq, "%-12s", s); \ - for (qs = 0; qs < n; ++qs) \ - seq_printf(seq, " %16" fmt_spec, v); \ - seq_putc(seq, '\n'); \ - } while (0) - #define S(s, v) S3("s", s, v) - #define T(s, v) S3("u", s, txq[qs].v) - #define R(s, v) S3("u", s, rxq[qs].v) - - if (r < eth_entries) { - const struct sge_eth_rxq *rxq = &adapter->sge.ethrxq[r * QPL]; - const struct sge_eth_txq *txq = &adapter->sge.ethtxq[r * QPL]; - int n = min(QPL, adapter->sge.ethqsets - QPL * r); - - S("QType:", "Ethernet"); - S("Interface:", - (rxq[qs].rspq.netdev - ? rxq[qs].rspq.netdev->name - : "N/A")); - S3("d", "Port:", - (rxq[qs].rspq.netdev - ? ((struct port_info *) - netdev_priv(rxq[qs].rspq.netdev))->port_id - : -1)); - T("TxQ ID:", q.abs_id); - T("TxQ size:", q.size); - T("TxQ inuse:", q.in_use); - T("TxQ PIdx:", q.pidx); - T("TxQ CIdx:", q.cidx); - R("RspQ ID:", rspq.abs_id); - R("RspQ size:", rspq.size); - R("RspQE size:", rspq.iqe_len); - S3("u", "Intr delay:", qtimer_val(adapter, &rxq[qs].rspq)); - S3("u", "Intr pktcnt:", - adapter->sge.counter_val[rxq[qs].rspq.pktcnt_idx]); - R("RspQ CIdx:", rspq.cidx); - R("RspQ Gen:", rspq.gen); - R("FL ID:", fl.abs_id); - R("FL size:", fl.size - MIN_FL_RESID); - R("FL avail:", fl.avail); - R("FL PIdx:", fl.pidx); - R("FL CIdx:", fl.cidx); - return 0; - } - - r -= eth_entries; - if (r == 0) { - const struct sge_rspq *evtq = &adapter->sge.fw_evtq; - - seq_printf(seq, "%-12s %16s\n", "QType:", "FW event queue"); - seq_printf(seq, "%-12s %16u\n", "RspQ ID:", evtq->abs_id); - seq_printf(seq, "%-12s %16u\n", "Intr delay:", - qtimer_val(adapter, evtq)); - seq_printf(seq, "%-12s %16u\n", "Intr pktcnt:", - adapter->sge.counter_val[evtq->pktcnt_idx]); - seq_printf(seq, "%-12s %16u\n", "RspQ Cidx:", evtq->cidx); - seq_printf(seq, "%-12s %16u\n", "RspQ Gen:", evtq->gen); - } else if (r == 1) { - const struct sge_rspq *intrq = &adapter->sge.intrq; - - seq_printf(seq, "%-12s %16s\n", "QType:", "Interrupt Queue"); - seq_printf(seq, "%-12s %16u\n", "RspQ ID:", intrq->abs_id); - seq_printf(seq, "%-12s %16u\n", "Intr delay:", - qtimer_val(adapter, intrq)); - seq_printf(seq, "%-12s %16u\n", "Intr pktcnt:", - adapter->sge.counter_val[intrq->pktcnt_idx]); - seq_printf(seq, "%-12s %16u\n", "RspQ Cidx:", intrq->cidx); - seq_printf(seq, "%-12s %16u\n", "RspQ Gen:", intrq->gen); - } - - #undef R - #undef T - #undef S - #undef S3 - - return 0; -} - -/* - * Return the number of "entries" in our "file". We group the multi-Queue - * sections with QPL Queue Sets per "entry". The sections of the output are: - * - * Ethernet RX/TX Queue Sets - * Firmware Event Queue - * Forwarded Interrupt Queue (if in MSI mode) - */ -static int sge_queue_entries(const struct adapter *adapter) -{ - return DIV_ROUND_UP(adapter->sge.ethqsets, QPL) + 1 + - ((adapter->flags & USING_MSI) != 0); -} - -static void *sge_queue_start(struct seq_file *seq, loff_t *pos) -{ - int entries = sge_queue_entries(seq->private); - - return *pos < entries ? (void *)((uintptr_t)*pos + 1) : NULL; -} - -static void sge_queue_stop(struct seq_file *seq, void *v) -{ -} - -static void *sge_queue_next(struct seq_file *seq, void *v, loff_t *pos) -{ - int entries = sge_queue_entries(seq->private); - - ++*pos; - return *pos < entries ? (void *)((uintptr_t)*pos + 1) : NULL; -} - -static const struct seq_operations sge_qinfo_seq_ops = { - .start = sge_queue_start, - .next = sge_queue_next, - .stop = sge_queue_stop, - .show = sge_qinfo_show -}; - -static int sge_qinfo_open(struct inode *inode, struct file *file) -{ - int res = seq_open(file, &sge_qinfo_seq_ops); - - if (!res) { - struct seq_file *seq = file->private_data; - seq->private = inode->i_private; - } - return res; -} - -static const struct file_operations sge_qinfo_debugfs_fops = { - .owner = THIS_MODULE, - .open = sge_qinfo_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -/* - * Show SGE Queue Set statistics. We display QPL Queues Sets per line. - */ -#define QPL 4 - -static int sge_qstats_show(struct seq_file *seq, void *v) -{ - struct adapter *adapter = seq->private; - int eth_entries = DIV_ROUND_UP(adapter->sge.ethqsets, QPL); - int qs, r = (uintptr_t)v - 1; - - if (r) - seq_putc(seq, '\n'); - - #define S3(fmt, s, v) \ - do { \ - seq_printf(seq, "%-16s", s); \ - for (qs = 0; qs < n; ++qs) \ - seq_printf(seq, " %8" fmt, v); \ - seq_putc(seq, '\n'); \ - } while (0) - #define S(s, v) S3("s", s, v) - - #define T3(fmt, s, v) S3(fmt, s, txq[qs].v) - #define T(s, v) T3("lu", s, v) - - #define R3(fmt, s, v) S3(fmt, s, rxq[qs].v) - #define R(s, v) R3("lu", s, v) - - if (r < eth_entries) { - const struct sge_eth_rxq *rxq = &adapter->sge.ethrxq[r * QPL]; - const struct sge_eth_txq *txq = &adapter->sge.ethtxq[r * QPL]; - int n = min(QPL, adapter->sge.ethqsets - QPL * r); - - S("QType:", "Ethernet"); - S("Interface:", - (rxq[qs].rspq.netdev - ? rxq[qs].rspq.netdev->name - : "N/A")); - R3("u", "RspQNullInts:", rspq.unhandled_irqs); - R("RxPackets:", stats.pkts); - R("RxCSO:", stats.rx_cso); - R("VLANxtract:", stats.vlan_ex); - R("LROmerged:", stats.lro_merged); - R("LROpackets:", stats.lro_pkts); - R("RxDrops:", stats.rx_drops); - T("TSO:", tso); - T("TxCSO:", tx_cso); - T("VLANins:", vlan_ins); - T("TxQFull:", q.stops); - T("TxQRestarts:", q.restarts); - T("TxMapErr:", mapping_err); - R("FLAllocErr:", fl.alloc_failed); - R("FLLrgAlcErr:", fl.large_alloc_failed); - R("FLStarving:", fl.starving); - return 0; - } - - r -= eth_entries; - if (r == 0) { - const struct sge_rspq *evtq = &adapter->sge.fw_evtq; - - seq_printf(seq, "%-8s %16s\n", "QType:", "FW event queue"); - seq_printf(seq, "%-16s %8u\n", "RspQNullInts:", - evtq->unhandled_irqs); - seq_printf(seq, "%-16s %8u\n", "RspQ CIdx:", evtq->cidx); - seq_printf(seq, "%-16s %8u\n", "RspQ Gen:", evtq->gen); - } else if (r == 1) { - const struct sge_rspq *intrq = &adapter->sge.intrq; - - seq_printf(seq, "%-8s %16s\n", "QType:", "Interrupt Queue"); - seq_printf(seq, "%-16s %8u\n", "RspQNullInts:", - intrq->unhandled_irqs); - seq_printf(seq, "%-16s %8u\n", "RspQ CIdx:", intrq->cidx); - seq_printf(seq, "%-16s %8u\n", "RspQ Gen:", intrq->gen); - } - - #undef R - #undef T - #undef S - #undef R3 - #undef T3 - #undef S3 - - return 0; -} - -/* - * Return the number of "entries" in our "file". We group the multi-Queue - * sections with QPL Queue Sets per "entry". The sections of the output are: - * - * Ethernet RX/TX Queue Sets - * Firmware Event Queue - * Forwarded Interrupt Queue (if in MSI mode) - */ -static int sge_qstats_entries(const struct adapter *adapter) -{ - return DIV_ROUND_UP(adapter->sge.ethqsets, QPL) + 1 + - ((adapter->flags & USING_MSI) != 0); -} - -static void *sge_qstats_start(struct seq_file *seq, loff_t *pos) -{ - int entries = sge_qstats_entries(seq->private); - - return *pos < entries ? (void *)((uintptr_t)*pos + 1) : NULL; -} - -static void sge_qstats_stop(struct seq_file *seq, void *v) -{ -} - -static void *sge_qstats_next(struct seq_file *seq, void *v, loff_t *pos) -{ - int entries = sge_qstats_entries(seq->private); - - (*pos)++; - return *pos < entries ? (void *)((uintptr_t)*pos + 1) : NULL; -} - -static const struct seq_operations sge_qstats_seq_ops = { - .start = sge_qstats_start, - .next = sge_qstats_next, - .stop = sge_qstats_stop, - .show = sge_qstats_show -}; - -static int sge_qstats_open(struct inode *inode, struct file *file) -{ - int res = seq_open(file, &sge_qstats_seq_ops); - - if (res == 0) { - struct seq_file *seq = file->private_data; - seq->private = inode->i_private; - } - return res; -} - -static const struct file_operations sge_qstats_proc_fops = { - .owner = THIS_MODULE, - .open = sge_qstats_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -/* - * Show PCI-E SR-IOV Virtual Function Resource Limits. - */ -static int resources_show(struct seq_file *seq, void *v) -{ - struct adapter *adapter = seq->private; - struct vf_resources *vfres = &adapter->params.vfres; - - #define S(desc, fmt, var) \ - seq_printf(seq, "%-60s " fmt "\n", \ - desc " (" #var "):", vfres->var) - - S("Virtual Interfaces", "%d", nvi); - S("Egress Queues", "%d", neq); - S("Ethernet Control", "%d", nethctrl); - S("Ingress Queues/w Free Lists/Interrupts", "%d", niqflint); - S("Ingress Queues", "%d", niq); - S("Traffic Class", "%d", tc); - S("Port Access Rights Mask", "%#x", pmask); - S("MAC Address Filters", "%d", nexactf); - S("Firmware Command Read Capabilities", "%#x", r_caps); - S("Firmware Command Write/Execute Capabilities", "%#x", wx_caps); - - #undef S - - return 0; -} - -static int resources_open(struct inode *inode, struct file *file) -{ - return single_open(file, resources_show, inode->i_private); -} - -static const struct file_operations resources_proc_fops = { - .owner = THIS_MODULE, - .open = resources_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -/* - * Show Virtual Interfaces. - */ -static int interfaces_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) { - seq_puts(seq, "Interface Port VIID\n"); - } else { - struct adapter *adapter = seq->private; - int pidx = (uintptr_t)v - 2; - struct net_device *dev = adapter->port[pidx]; - struct port_info *pi = netdev_priv(dev); - - seq_printf(seq, "%9s %4d %#5x\n", - dev->name, pi->port_id, pi->viid); - } - return 0; -} - -static inline void *interfaces_get_idx(struct adapter *adapter, loff_t pos) -{ - return pos <= adapter->params.nports - ? (void *)(uintptr_t)(pos + 1) - : NULL; -} - -static void *interfaces_start(struct seq_file *seq, loff_t *pos) -{ - return *pos - ? interfaces_get_idx(seq->private, *pos) - : SEQ_START_TOKEN; -} - -static void *interfaces_next(struct seq_file *seq, void *v, loff_t *pos) -{ - (*pos)++; - return interfaces_get_idx(seq->private, *pos); -} - -static void interfaces_stop(struct seq_file *seq, void *v) -{ -} - -static const struct seq_operations interfaces_seq_ops = { - .start = interfaces_start, - .next = interfaces_next, - .stop = interfaces_stop, - .show = interfaces_show -}; - -static int interfaces_open(struct inode *inode, struct file *file) -{ - int res = seq_open(file, &interfaces_seq_ops); - - if (res == 0) { - struct seq_file *seq = file->private_data; - seq->private = inode->i_private; - } - return res; -} - -static const struct file_operations interfaces_proc_fops = { - .owner = THIS_MODULE, - .open = interfaces_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -/* - * /sys/kernel/debugfs/cxgb4vf/ files list. - */ -struct cxgb4vf_debugfs_entry { - const char *name; /* name of debugfs node */ - mode_t mode; /* file system mode */ - const struct file_operations *fops; -}; - -static struct cxgb4vf_debugfs_entry debugfs_files[] = { - { "sge_qinfo", S_IRUGO, &sge_qinfo_debugfs_fops }, - { "sge_qstats", S_IRUGO, &sge_qstats_proc_fops }, - { "resources", S_IRUGO, &resources_proc_fops }, - { "interfaces", S_IRUGO, &interfaces_proc_fops }, -}; - -/* - * Module and device initialization and cleanup code. - * ================================================== - */ - -/* - * Set up out /sys/kernel/debug/cxgb4vf sub-nodes. We assume that the - * directory (debugfs_root) has already been set up. - */ -static int __devinit setup_debugfs(struct adapter *adapter) -{ - int i; - - BUG_ON(IS_ERR_OR_NULL(adapter->debugfs_root)); - - /* - * Debugfs support is best effort. - */ - for (i = 0; i < ARRAY_SIZE(debugfs_files); i++) - (void)debugfs_create_file(debugfs_files[i].name, - debugfs_files[i].mode, - adapter->debugfs_root, - (void *)adapter, - debugfs_files[i].fops); - - return 0; -} - -/* - * Tear down the /sys/kernel/debug/cxgb4vf sub-nodes created above. We leave - * it to our caller to tear down the directory (debugfs_root). - */ -static void cleanup_debugfs(struct adapter *adapter) -{ - BUG_ON(IS_ERR_OR_NULL(adapter->debugfs_root)); - - /* - * Unlike our sister routine cleanup_proc(), we don't need to remove - * individual entries because a call will be made to - * debugfs_remove_recursive(). We just need to clean up any ancillary - * persistent state. - */ - /* nothing to do */ -} - -/* - * Perform early "adapter" initialization. This is where we discover what - * adapter parameters we're going to be using and initialize basic adapter - * hardware support. - */ -static int __devinit adap_init0(struct adapter *adapter) -{ - struct vf_resources *vfres = &adapter->params.vfres; - struct sge_params *sge_params = &adapter->params.sge; - struct sge *s = &adapter->sge; - unsigned int ethqsets; - int err; - - /* - * Wait for the device to become ready before proceeding ... - */ - err = t4vf_wait_dev_ready(adapter); - if (err) { - dev_err(adapter->pdev_dev, "device didn't become ready:" - " err=%d\n", err); - return err; - } - - /* - * Some environments do not properly handle PCIE FLRs -- e.g. in Linux - * 2.6.31 and later we can't call pci_reset_function() in order to - * issue an FLR because of a self- deadlock on the device semaphore. - * Meanwhile, the OS infrastructure doesn't issue FLRs in all the - * cases where they're needed -- for instance, some versions of KVM - * fail to reset "Assigned Devices" when the VM reboots. Therefore we - * use the firmware based reset in order to reset any per function - * state. - */ - err = t4vf_fw_reset(adapter); - if (err < 0) { - dev_err(adapter->pdev_dev, "FW reset failed: err=%d\n", err); - return err; - } - - /* - * Grab basic operational parameters. These will predominantly have - * been set up by the Physical Function Driver or will be hard coded - * into the adapter. We just have to live with them ... Note that - * we _must_ get our VPD parameters before our SGE parameters because - * we need to know the adapter's core clock from the VPD in order to - * properly decode the SGE Timer Values. - */ - err = t4vf_get_dev_params(adapter); - if (err) { - dev_err(adapter->pdev_dev, "unable to retrieve adapter" - " device parameters: err=%d\n", err); - return err; - } - err = t4vf_get_vpd_params(adapter); - if (err) { - dev_err(adapter->pdev_dev, "unable to retrieve adapter" - " VPD parameters: err=%d\n", err); - return err; - } - err = t4vf_get_sge_params(adapter); - if (err) { - dev_err(adapter->pdev_dev, "unable to retrieve adapter" - " SGE parameters: err=%d\n", err); - return err; - } - err = t4vf_get_rss_glb_config(adapter); - if (err) { - dev_err(adapter->pdev_dev, "unable to retrieve adapter" - " RSS parameters: err=%d\n", err); - return err; - } - if (adapter->params.rss.mode != - FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL) { - dev_err(adapter->pdev_dev, "unable to operate with global RSS" - " mode %d\n", adapter->params.rss.mode); - return -EINVAL; - } - err = t4vf_sge_init(adapter); - if (err) { - dev_err(adapter->pdev_dev, "unable to use adapter parameters:" - " err=%d\n", err); - return err; - } - - /* - * Retrieve our RX interrupt holdoff timer values and counter - * threshold values from the SGE parameters. - */ - s->timer_val[0] = core_ticks_to_us(adapter, - TIMERVALUE0_GET(sge_params->sge_timer_value_0_and_1)); - s->timer_val[1] = core_ticks_to_us(adapter, - TIMERVALUE1_GET(sge_params->sge_timer_value_0_and_1)); - s->timer_val[2] = core_ticks_to_us(adapter, - TIMERVALUE0_GET(sge_params->sge_timer_value_2_and_3)); - s->timer_val[3] = core_ticks_to_us(adapter, - TIMERVALUE1_GET(sge_params->sge_timer_value_2_and_3)); - s->timer_val[4] = core_ticks_to_us(adapter, - TIMERVALUE0_GET(sge_params->sge_timer_value_4_and_5)); - s->timer_val[5] = core_ticks_to_us(adapter, - TIMERVALUE1_GET(sge_params->sge_timer_value_4_and_5)); - - s->counter_val[0] = - THRESHOLD_0_GET(sge_params->sge_ingress_rx_threshold); - s->counter_val[1] = - THRESHOLD_1_GET(sge_params->sge_ingress_rx_threshold); - s->counter_val[2] = - THRESHOLD_2_GET(sge_params->sge_ingress_rx_threshold); - s->counter_val[3] = - THRESHOLD_3_GET(sge_params->sge_ingress_rx_threshold); - - /* - * Grab our Virtual Interface resource allocation, extract the - * features that we're interested in and do a bit of sanity testing on - * what we discover. - */ - err = t4vf_get_vfres(adapter); - if (err) { - dev_err(adapter->pdev_dev, "unable to get virtual interface" - " resources: err=%d\n", err); - return err; - } - - /* - * The number of "ports" which we support is equal to the number of - * Virtual Interfaces with which we've been provisioned. - */ - adapter->params.nports = vfres->nvi; - if (adapter->params.nports > MAX_NPORTS) { - dev_warn(adapter->pdev_dev, "only using %d of %d allowed" - " virtual interfaces\n", MAX_NPORTS, - adapter->params.nports); - adapter->params.nports = MAX_NPORTS; - } - - /* - * We need to reserve a number of the ingress queues with Free List - * and Interrupt capabilities for special interrupt purposes (like - * asynchronous firmware messages, or forwarded interrupts if we're - * using MSI). The rest of the FL/Intr-capable ingress queues will be - * matched up one-for-one with Ethernet/Control egress queues in order - * to form "Queue Sets" which will be aportioned between the "ports". - * For each Queue Set, we'll need the ability to allocate two Egress - * Contexts -- one for the Ingress Queue Free List and one for the TX - * Ethernet Queue. - */ - ethqsets = vfres->niqflint - INGQ_EXTRAS; - if (vfres->nethctrl != ethqsets) { - dev_warn(adapter->pdev_dev, "unequal number of [available]" - " ingress/egress queues (%d/%d); using minimum for" - " number of Queue Sets\n", ethqsets, vfres->nethctrl); - ethqsets = min(vfres->nethctrl, ethqsets); - } - if (vfres->neq < ethqsets*2) { - dev_warn(adapter->pdev_dev, "Not enough Egress Contexts (%d)" - " to support Queue Sets (%d); reducing allowed Queue" - " Sets\n", vfres->neq, ethqsets); - ethqsets = vfres->neq/2; - } - if (ethqsets > MAX_ETH_QSETS) { - dev_warn(adapter->pdev_dev, "only using %d of %d allowed Queue" - " Sets\n", MAX_ETH_QSETS, adapter->sge.max_ethqsets); - ethqsets = MAX_ETH_QSETS; - } - if (vfres->niq != 0 || vfres->neq > ethqsets*2) { - dev_warn(adapter->pdev_dev, "unused resources niq/neq (%d/%d)" - " ignored\n", vfres->niq, vfres->neq - ethqsets*2); - } - adapter->sge.max_ethqsets = ethqsets; - - /* - * Check for various parameter sanity issues. Most checks simply - * result in us using fewer resources than our provissioning but we - * do need at least one "port" with which to work ... - */ - if (adapter->sge.max_ethqsets < adapter->params.nports) { - dev_warn(adapter->pdev_dev, "only using %d of %d available" - " virtual interfaces (too few Queue Sets)\n", - adapter->sge.max_ethqsets, adapter->params.nports); - adapter->params.nports = adapter->sge.max_ethqsets; - } - if (adapter->params.nports == 0) { - dev_err(adapter->pdev_dev, "no virtual interfaces configured/" - "usable!\n"); - return -EINVAL; - } - return 0; -} - -static inline void init_rspq(struct sge_rspq *rspq, u8 timer_idx, - u8 pkt_cnt_idx, unsigned int size, - unsigned int iqe_size) -{ - rspq->intr_params = (QINTR_TIMER_IDX(timer_idx) | - (pkt_cnt_idx < SGE_NCOUNTERS ? QINTR_CNT_EN : 0)); - rspq->pktcnt_idx = (pkt_cnt_idx < SGE_NCOUNTERS - ? pkt_cnt_idx - : 0); - rspq->iqe_len = iqe_size; - rspq->size = size; -} - -/* - * Perform default configuration of DMA queues depending on the number and - * type of ports we found and the number of available CPUs. Most settings can - * be modified by the admin via ethtool and cxgbtool prior to the adapter - * being brought up for the first time. - */ -static void __devinit cfg_queues(struct adapter *adapter) -{ - struct sge *s = &adapter->sge; - int q10g, n10g, qidx, pidx, qs; - size_t iqe_size; - - /* - * We should not be called till we know how many Queue Sets we can - * support. In particular, this means that we need to know what kind - * of interrupts we'll be using ... - */ - BUG_ON((adapter->flags & (USING_MSIX|USING_MSI)) == 0); - - /* - * Count the number of 10GbE Virtual Interfaces that we have. - */ - n10g = 0; - for_each_port(adapter, pidx) - n10g += is_10g_port(&adap2pinfo(adapter, pidx)->link_cfg); - - /* - * We default to 1 queue per non-10G port and up to # of cores queues - * per 10G port. - */ - if (n10g == 0) - q10g = 0; - else { - int n1g = (adapter->params.nports - n10g); - q10g = (adapter->sge.max_ethqsets - n1g) / n10g; - if (q10g > num_online_cpus()) - q10g = num_online_cpus(); - } - - /* - * Allocate the "Queue Sets" to the various Virtual Interfaces. - * The layout will be established in setup_sge_queues() when the - * adapter is brough up for the first time. - */ - qidx = 0; - for_each_port(adapter, pidx) { - struct port_info *pi = adap2pinfo(adapter, pidx); - - pi->first_qset = qidx; - pi->nqsets = is_10g_port(&pi->link_cfg) ? q10g : 1; - qidx += pi->nqsets; - } - s->ethqsets = qidx; - - /* - * The Ingress Queue Entry Size for our various Response Queues needs - * to be big enough to accommodate the largest message we can receive - * from the chip/firmware; which is 64 bytes ... - */ - iqe_size = 64; - - /* - * Set up default Queue Set parameters ... Start off with the - * shortest interrupt holdoff timer. - */ - for (qs = 0; qs < s->max_ethqsets; qs++) { - struct sge_eth_rxq *rxq = &s->ethrxq[qs]; - struct sge_eth_txq *txq = &s->ethtxq[qs]; - - init_rspq(&rxq->rspq, 0, 0, 1024, iqe_size); - rxq->fl.size = 72; - txq->q.size = 1024; - } - - /* - * The firmware event queue is used for link state changes and - * notifications of TX DMA completions. - */ - init_rspq(&s->fw_evtq, SGE_TIMER_RSTRT_CNTR, 0, 512, iqe_size); - - /* - * The forwarded interrupt queue is used when we're in MSI interrupt - * mode. In this mode all interrupts associated with RX queues will - * be forwarded to a single queue which we'll associate with our MSI - * interrupt vector. The messages dropped in the forwarded interrupt - * queue will indicate which ingress queue needs servicing ... This - * queue needs to be large enough to accommodate all of the ingress - * queues which are forwarding their interrupt (+1 to prevent the PIDX - * from equalling the CIDX if every ingress queue has an outstanding - * interrupt). The queue doesn't need to be any larger because no - * ingress queue will ever have more than one outstanding interrupt at - * any time ... - */ - init_rspq(&s->intrq, SGE_TIMER_RSTRT_CNTR, 0, MSIX_ENTRIES + 1, - iqe_size); -} - -/* - * Reduce the number of Ethernet queues across all ports to at most n. - * n provides at least one queue per port. - */ -static void __devinit reduce_ethqs(struct adapter *adapter, int n) -{ - int i; - struct port_info *pi; - - /* - * While we have too many active Ether Queue Sets, interate across the - * "ports" and reduce their individual Queue Set allocations. - */ - BUG_ON(n < adapter->params.nports); - while (n < adapter->sge.ethqsets) - for_each_port(adapter, i) { - pi = adap2pinfo(adapter, i); - if (pi->nqsets > 1) { - pi->nqsets--; - adapter->sge.ethqsets--; - if (adapter->sge.ethqsets <= n) - break; - } - } - - /* - * Reassign the starting Queue Sets for each of the "ports" ... - */ - n = 0; - for_each_port(adapter, i) { - pi = adap2pinfo(adapter, i); - pi->first_qset = n; - n += pi->nqsets; - } -} - -/* - * We need to grab enough MSI-X vectors to cover our interrupt needs. Ideally - * we get a separate MSI-X vector for every "Queue Set" plus any extras we - * need. Minimally we need one for every Virtual Interface plus those needed - * for our "extras". Note that this process may lower the maximum number of - * allowed Queue Sets ... - */ -static int __devinit enable_msix(struct adapter *adapter) -{ - int i, err, want, need; - struct msix_entry entries[MSIX_ENTRIES]; - struct sge *s = &adapter->sge; - - for (i = 0; i < MSIX_ENTRIES; ++i) - entries[i].entry = i; - - /* - * We _want_ enough MSI-X interrupts to cover all of our "Queue Sets" - * plus those needed for our "extras" (for example, the firmware - * message queue). We _need_ at least one "Queue Set" per Virtual - * Interface plus those needed for our "extras". So now we get to see - * if the song is right ... - */ - want = s->max_ethqsets + MSIX_EXTRAS; - need = adapter->params.nports + MSIX_EXTRAS; - while ((err = pci_enable_msix(adapter->pdev, entries, want)) >= need) - want = err; - - if (err == 0) { - int nqsets = want - MSIX_EXTRAS; - if (nqsets < s->max_ethqsets) { - dev_warn(adapter->pdev_dev, "only enough MSI-X vectors" - " for %d Queue Sets\n", nqsets); - s->max_ethqsets = nqsets; - if (nqsets < s->ethqsets) - reduce_ethqs(adapter, nqsets); - } - for (i = 0; i < want; ++i) - adapter->msix_info[i].vec = entries[i].vector; - } else if (err > 0) { - pci_disable_msix(adapter->pdev); - dev_info(adapter->pdev_dev, "only %d MSI-X vectors left," - " not using MSI-X\n", err); - } - return err; -} - -static const struct net_device_ops cxgb4vf_netdev_ops = { - .ndo_open = cxgb4vf_open, - .ndo_stop = cxgb4vf_stop, - .ndo_start_xmit = t4vf_eth_xmit, - .ndo_get_stats = cxgb4vf_get_stats, - .ndo_set_rx_mode = cxgb4vf_set_rxmode, - .ndo_set_mac_address = cxgb4vf_set_mac_addr, - .ndo_validate_addr = eth_validate_addr, - .ndo_do_ioctl = cxgb4vf_do_ioctl, - .ndo_change_mtu = cxgb4vf_change_mtu, - .ndo_fix_features = cxgb4vf_fix_features, - .ndo_set_features = cxgb4vf_set_features, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = cxgb4vf_poll_controller, -#endif -}; - -/* - * "Probe" a device: initialize a device and construct all kernel and driver - * state needed to manage the device. This routine is called "init_one" in - * the PF Driver ... - */ -static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - static int version_printed; - - int pci_using_dac; - int err, pidx; - unsigned int pmask; - struct adapter *adapter; - struct port_info *pi; - struct net_device *netdev; - - /* - * Print our driver banner the first time we're called to initialize a - * device. - */ - if (version_printed == 0) { - printk(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION); - version_printed = 1; - } - - /* - * Initialize generic PCI device state. - */ - err = pci_enable_device(pdev); - if (err) { - dev_err(&pdev->dev, "cannot enable PCI device\n"); - return err; - } - - /* - * Reserve PCI resources for the device. If we can't get them some - * other driver may have already claimed the device ... - */ - err = pci_request_regions(pdev, KBUILD_MODNAME); - if (err) { - dev_err(&pdev->dev, "cannot obtain PCI resources\n"); - goto err_disable_device; - } - - /* - * Set up our DMA mask: try for 64-bit address masking first and - * fall back to 32-bit if we can't get 64 bits ... - */ - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); - if (err == 0) { - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); - if (err) { - dev_err(&pdev->dev, "unable to obtain 64-bit DMA for" - " coherent allocations\n"); - goto err_release_regions; - } - pci_using_dac = 1; - } else { - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (err != 0) { - dev_err(&pdev->dev, "no usable DMA configuration\n"); - goto err_release_regions; - } - pci_using_dac = 0; - } - - /* - * Enable bus mastering for the device ... - */ - pci_set_master(pdev); - - /* - * Allocate our adapter data structure and attach it to the device. - */ - adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); - if (!adapter) { - err = -ENOMEM; - goto err_release_regions; - } - pci_set_drvdata(pdev, adapter); - adapter->pdev = pdev; - adapter->pdev_dev = &pdev->dev; - - /* - * Initialize SMP data synchronization resources. - */ - spin_lock_init(&adapter->stats_lock); - - /* - * Map our I/O registers in BAR0. - */ - adapter->regs = pci_ioremap_bar(pdev, 0); - if (!adapter->regs) { - dev_err(&pdev->dev, "cannot map device registers\n"); - err = -ENOMEM; - goto err_free_adapter; - } - - /* - * Initialize adapter level features. - */ - adapter->name = pci_name(pdev); - adapter->msg_enable = dflt_msg_enable; - err = adap_init0(adapter); - if (err) - goto err_unmap_bar; - - /* - * Allocate our "adapter ports" and stitch everything together. - */ - pmask = adapter->params.vfres.pmask; - for_each_port(adapter, pidx) { - int port_id, viid; - - /* - * We simplistically allocate our virtual interfaces - * sequentially across the port numbers to which we have - * access rights. This should be configurable in some manner - * ... - */ - if (pmask == 0) - break; - port_id = ffs(pmask) - 1; - pmask &= ~(1 << port_id); - viid = t4vf_alloc_vi(adapter, port_id); - if (viid < 0) { - dev_err(&pdev->dev, "cannot allocate VI for port %d:" - " err=%d\n", port_id, viid); - err = viid; - goto err_free_dev; - } - - /* - * Allocate our network device and stitch things together. - */ - netdev = alloc_etherdev_mq(sizeof(struct port_info), - MAX_PORT_QSETS); - if (netdev == NULL) { - dev_err(&pdev->dev, "cannot allocate netdev for" - " port %d\n", port_id); - t4vf_free_vi(adapter, viid); - err = -ENOMEM; - goto err_free_dev; - } - adapter->port[pidx] = netdev; - SET_NETDEV_DEV(netdev, &pdev->dev); - pi = netdev_priv(netdev); - pi->adapter = adapter; - pi->pidx = pidx; - pi->port_id = port_id; - pi->viid = viid; - - /* - * Initialize the starting state of our "port" and register - * it. - */ - pi->xact_addr_filt = -1; - netif_carrier_off(netdev); - netdev->irq = pdev->irq; - - netdev->hw_features = NETIF_F_SG | TSO_FLAGS | - NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_HW_VLAN_RX | NETIF_F_RXCSUM; - netdev->vlan_features = NETIF_F_SG | TSO_FLAGS | - NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_HIGHDMA; - netdev->features = netdev->hw_features | NETIF_F_HW_VLAN_TX; - if (pci_using_dac) - netdev->features |= NETIF_F_HIGHDMA; - - netdev->netdev_ops = &cxgb4vf_netdev_ops; - SET_ETHTOOL_OPS(netdev, &cxgb4vf_ethtool_ops); - - /* - * Initialize the hardware/software state for the port. - */ - err = t4vf_port_init(adapter, pidx); - if (err) { - dev_err(&pdev->dev, "cannot initialize port %d\n", - pidx); - goto err_free_dev; - } - } - - /* - * The "card" is now ready to go. If any errors occur during device - * registration we do not fail the whole "card" but rather proceed - * only with the ports we manage to register successfully. However we - * must register at least one net device. - */ - for_each_port(adapter, pidx) { - netdev = adapter->port[pidx]; - if (netdev == NULL) - continue; - - err = register_netdev(netdev); - if (err) { - dev_warn(&pdev->dev, "cannot register net device %s," - " skipping\n", netdev->name); - continue; - } - - set_bit(pidx, &adapter->registered_device_map); - } - if (adapter->registered_device_map == 0) { - dev_err(&pdev->dev, "could not register any net devices\n"); - goto err_free_dev; - } - - /* - * Set up our debugfs entries. - */ - if (!IS_ERR_OR_NULL(cxgb4vf_debugfs_root)) { - adapter->debugfs_root = - debugfs_create_dir(pci_name(pdev), - cxgb4vf_debugfs_root); - if (IS_ERR_OR_NULL(adapter->debugfs_root)) - dev_warn(&pdev->dev, "could not create debugfs" - " directory"); - else - setup_debugfs(adapter); - } - - /* - * See what interrupts we'll be using. If we've been configured to - * use MSI-X interrupts, try to enable them but fall back to using - * MSI interrupts if we can't enable MSI-X interrupts. If we can't - * get MSI interrupts we bail with the error. - */ - if (msi == MSI_MSIX && enable_msix(adapter) == 0) - adapter->flags |= USING_MSIX; - else { - err = pci_enable_msi(pdev); - if (err) { - dev_err(&pdev->dev, "Unable to allocate %s interrupts;" - " err=%d\n", - msi == MSI_MSIX ? "MSI-X or MSI" : "MSI", err); - goto err_free_debugfs; - } - adapter->flags |= USING_MSI; - } - - /* - * Now that we know how many "ports" we have and what their types are, - * and how many Queue Sets we can support, we can configure our queue - * resources. - */ - cfg_queues(adapter); - - /* - * Print a short notice on the existence and configuration of the new - * VF network device ... - */ - for_each_port(adapter, pidx) { - dev_info(adapter->pdev_dev, "%s: Chelsio VF NIC PCIe %s\n", - adapter->port[pidx]->name, - (adapter->flags & USING_MSIX) ? "MSI-X" : - (adapter->flags & USING_MSI) ? "MSI" : ""); - } - - /* - * Return success! - */ - return 0; - - /* - * Error recovery and exit code. Unwind state that's been created - * so far and return the error. - */ - -err_free_debugfs: - if (!IS_ERR_OR_NULL(adapter->debugfs_root)) { - cleanup_debugfs(adapter); - debugfs_remove_recursive(adapter->debugfs_root); - } - -err_free_dev: - for_each_port(adapter, pidx) { - netdev = adapter->port[pidx]; - if (netdev == NULL) - continue; - pi = netdev_priv(netdev); - t4vf_free_vi(adapter, pi->viid); - if (test_bit(pidx, &adapter->registered_device_map)) - unregister_netdev(netdev); - free_netdev(netdev); - } - -err_unmap_bar: - iounmap(adapter->regs); - -err_free_adapter: - kfree(adapter); - pci_set_drvdata(pdev, NULL); - -err_release_regions: - pci_release_regions(pdev); - pci_set_drvdata(pdev, NULL); - pci_clear_master(pdev); - -err_disable_device: - pci_disable_device(pdev); - - return err; -} - -/* - * "Remove" a device: tear down all kernel and driver state created in the - * "probe" routine and quiesce the device (disable interrupts, etc.). (Note - * that this is called "remove_one" in the PF Driver.) - */ -static void __devexit cxgb4vf_pci_remove(struct pci_dev *pdev) -{ - struct adapter *adapter = pci_get_drvdata(pdev); - - /* - * Tear down driver state associated with device. - */ - if (adapter) { - int pidx; - - /* - * Stop all of our activity. Unregister network port, - * disable interrupts, etc. - */ - for_each_port(adapter, pidx) - if (test_bit(pidx, &adapter->registered_device_map)) - unregister_netdev(adapter->port[pidx]); - t4vf_sge_stop(adapter); - if (adapter->flags & USING_MSIX) { - pci_disable_msix(adapter->pdev); - adapter->flags &= ~USING_MSIX; - } else if (adapter->flags & USING_MSI) { - pci_disable_msi(adapter->pdev); - adapter->flags &= ~USING_MSI; - } - - /* - * Tear down our debugfs entries. - */ - if (!IS_ERR_OR_NULL(adapter->debugfs_root)) { - cleanup_debugfs(adapter); - debugfs_remove_recursive(adapter->debugfs_root); - } - - /* - * Free all of the various resources which we've acquired ... - */ - t4vf_free_sge_resources(adapter); - for_each_port(adapter, pidx) { - struct net_device *netdev = adapter->port[pidx]; - struct port_info *pi; - - if (netdev == NULL) - continue; - - pi = netdev_priv(netdev); - t4vf_free_vi(adapter, pi->viid); - free_netdev(netdev); - } - iounmap(adapter->regs); - kfree(adapter); - pci_set_drvdata(pdev, NULL); - } - - /* - * Disable the device and release its PCI resources. - */ - pci_disable_device(pdev); - pci_clear_master(pdev); - pci_release_regions(pdev); -} - -/* - * "Shutdown" quiesce the device, stopping Ingress Packet and Interrupt - * delivery. - */ -static void __devexit cxgb4vf_pci_shutdown(struct pci_dev *pdev) -{ - struct adapter *adapter; - int pidx; - - adapter = pci_get_drvdata(pdev); - if (!adapter) - return; - - /* - * Disable all Virtual Interfaces. This will shut down the - * delivery of all ingress packets into the chip for these - * Virtual Interfaces. - */ - for_each_port(adapter, pidx) { - struct net_device *netdev; - struct port_info *pi; - - if (!test_bit(pidx, &adapter->registered_device_map)) - continue; - - netdev = adapter->port[pidx]; - if (!netdev) - continue; - - pi = netdev_priv(netdev); - t4vf_enable_vi(adapter, pi->viid, false, false); - } - - /* - * Free up all Queues which will prevent further DMA and - * Interrupts allowing various internal pathways to drain. - */ - t4vf_free_sge_resources(adapter); -} - -/* - * PCI Device registration data structures. - */ -#define CH_DEVICE(devid, idx) \ - { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, PCI_ANY_ID, 0, 0, idx } - -static struct pci_device_id cxgb4vf_pci_tbl[] = { - CH_DEVICE(0xb000, 0), /* PE10K FPGA */ - CH_DEVICE(0x4800, 0), /* T440-dbg */ - CH_DEVICE(0x4801, 0), /* T420-cr */ - CH_DEVICE(0x4802, 0), /* T422-cr */ - CH_DEVICE(0x4803, 0), /* T440-cr */ - CH_DEVICE(0x4804, 0), /* T420-bch */ - CH_DEVICE(0x4805, 0), /* T440-bch */ - CH_DEVICE(0x4806, 0), /* T460-ch */ - CH_DEVICE(0x4807, 0), /* T420-so */ - CH_DEVICE(0x4808, 0), /* T420-cx */ - CH_DEVICE(0x4809, 0), /* T420-bt */ - CH_DEVICE(0x480a, 0), /* T404-bt */ - { 0, } -}; - -MODULE_DESCRIPTION(DRV_DESC); -MODULE_AUTHOR("Chelsio Communications"); -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_VERSION(DRV_VERSION); -MODULE_DEVICE_TABLE(pci, cxgb4vf_pci_tbl); - -static struct pci_driver cxgb4vf_driver = { - .name = KBUILD_MODNAME, - .id_table = cxgb4vf_pci_tbl, - .probe = cxgb4vf_pci_probe, - .remove = __devexit_p(cxgb4vf_pci_remove), - .shutdown = __devexit_p(cxgb4vf_pci_shutdown), -}; - -/* - * Initialize global driver state. - */ -static int __init cxgb4vf_module_init(void) -{ - int ret; - - /* - * Vet our module parameters. - */ - if (msi != MSI_MSIX && msi != MSI_MSI) { - printk(KERN_WARNING KBUILD_MODNAME - ": bad module parameter msi=%d; must be %d" - " (MSI-X or MSI) or %d (MSI)\n", - msi, MSI_MSIX, MSI_MSI); - return -EINVAL; - } - - /* Debugfs support is optional, just warn if this fails */ - cxgb4vf_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (IS_ERR_OR_NULL(cxgb4vf_debugfs_root)) - printk(KERN_WARNING KBUILD_MODNAME ": could not create" - " debugfs entry, continuing\n"); - - ret = pci_register_driver(&cxgb4vf_driver); - if (ret < 0 && !IS_ERR_OR_NULL(cxgb4vf_debugfs_root)) - debugfs_remove(cxgb4vf_debugfs_root); - return ret; -} - -/* - * Tear down global driver state. - */ -static void __exit cxgb4vf_module_exit(void) -{ - pci_unregister_driver(&cxgb4vf_driver); - debugfs_remove(cxgb4vf_debugfs_root); -} - -module_init(cxgb4vf_module_init); -module_exit(cxgb4vf_module_exit); diff --git a/drivers/net/cxgb4vf/sge.c b/drivers/net/cxgb4vf/sge.c deleted file mode 100644 index cffb328c46c3..000000000000 --- a/drivers/net/cxgb4vf/sge.c +++ /dev/null @@ -1,2465 +0,0 @@ -/* - * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet - * driver for Linux. - * - * Copyright (c) 2009-2010 Chelsio Communications, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "t4vf_common.h" -#include "t4vf_defs.h" - -#include "../cxgb4/t4_regs.h" -#include "../cxgb4/t4fw_api.h" -#include "../cxgb4/t4_msg.h" - -/* - * Decoded Adapter Parameters. - */ -static u32 FL_PG_ORDER; /* large page allocation size */ -static u32 STAT_LEN; /* length of status page at ring end */ -static u32 PKTSHIFT; /* padding between CPL and packet data */ -static u32 FL_ALIGN; /* response queue message alignment */ - -/* - * Constants ... - */ -enum { - /* - * Egress Queue sizes, producer and consumer indices are all in units - * of Egress Context Units bytes. Note that as far as the hardware is - * concerned, the free list is an Egress Queue (the host produces free - * buffers which the hardware consumes) and free list entries are - * 64-bit PCI DMA addresses. - */ - EQ_UNIT = SGE_EQ_IDXSIZE, - FL_PER_EQ_UNIT = EQ_UNIT / sizeof(__be64), - TXD_PER_EQ_UNIT = EQ_UNIT / sizeof(__be64), - - /* - * Max number of TX descriptors we clean up at a time. Should be - * modest as freeing skbs isn't cheap and it happens while holding - * locks. We just need to free packets faster than they arrive, we - * eventually catch up and keep the amortized cost reasonable. - */ - MAX_TX_RECLAIM = 16, - - /* - * Max number of Rx buffers we replenish at a time. Again keep this - * modest, allocating buffers isn't cheap either. - */ - MAX_RX_REFILL = 16, - - /* - * Period of the Rx queue check timer. This timer is infrequent as it - * has something to do only when the system experiences severe memory - * shortage. - */ - RX_QCHECK_PERIOD = (HZ / 2), - - /* - * Period of the TX queue check timer and the maximum number of TX - * descriptors to be reclaimed by the TX timer. - */ - TX_QCHECK_PERIOD = (HZ / 2), - MAX_TIMER_TX_RECLAIM = 100, - - /* - * An FL with <= FL_STARVE_THRES buffers is starving and a periodic - * timer will attempt to refill it. - */ - FL_STARVE_THRES = 4, - - /* - * Suspend an Ethernet TX queue with fewer available descriptors than - * this. We always want to have room for a maximum sized packet: - * inline immediate data + MAX_SKB_FRAGS. This is the same as - * calc_tx_flits() for a TSO packet with nr_frags == MAX_SKB_FRAGS - * (see that function and its helpers for a description of the - * calculation). - */ - ETHTXQ_MAX_FRAGS = MAX_SKB_FRAGS + 1, - ETHTXQ_MAX_SGL_LEN = ((3 * (ETHTXQ_MAX_FRAGS-1))/2 + - ((ETHTXQ_MAX_FRAGS-1) & 1) + - 2), - ETHTXQ_MAX_HDR = (sizeof(struct fw_eth_tx_pkt_vm_wr) + - sizeof(struct cpl_tx_pkt_lso_core) + - sizeof(struct cpl_tx_pkt_core)) / sizeof(__be64), - ETHTXQ_MAX_FLITS = ETHTXQ_MAX_SGL_LEN + ETHTXQ_MAX_HDR, - - ETHTXQ_STOP_THRES = 1 + DIV_ROUND_UP(ETHTXQ_MAX_FLITS, TXD_PER_EQ_UNIT), - - /* - * Max TX descriptor space we allow for an Ethernet packet to be - * inlined into a WR. This is limited by the maximum value which - * we can specify for immediate data in the firmware Ethernet TX - * Work Request. - */ - MAX_IMM_TX_PKT_LEN = FW_WR_IMMDLEN_MASK, - - /* - * Max size of a WR sent through a control TX queue. - */ - MAX_CTRL_WR_LEN = 256, - - /* - * Maximum amount of data which we'll ever need to inline into a - * TX ring: max(MAX_IMM_TX_PKT_LEN, MAX_CTRL_WR_LEN). - */ - MAX_IMM_TX_LEN = (MAX_IMM_TX_PKT_LEN > MAX_CTRL_WR_LEN - ? MAX_IMM_TX_PKT_LEN - : MAX_CTRL_WR_LEN), - - /* - * For incoming packets less than RX_COPY_THRES, we copy the data into - * an skb rather than referencing the data. We allocate enough - * in-line room in skb's to accommodate pulling in RX_PULL_LEN bytes - * of the data (header). - */ - RX_COPY_THRES = 256, - RX_PULL_LEN = 128, - - /* - * Main body length for sk_buffs used for RX Ethernet packets with - * fragments. Should be >= RX_PULL_LEN but possibly bigger to give - * pskb_may_pull() some room. - */ - RX_SKB_LEN = 512, -}; - -/* - * Software state per TX descriptor. - */ -struct tx_sw_desc { - struct sk_buff *skb; /* socket buffer of TX data source */ - struct ulptx_sgl *sgl; /* scatter/gather list in TX Queue */ -}; - -/* - * Software state per RX Free List descriptor. We keep track of the allocated - * FL page, its size, and its PCI DMA address (if the page is mapped). The FL - * page size and its PCI DMA mapped state are stored in the low bits of the - * PCI DMA address as per below. - */ -struct rx_sw_desc { - struct page *page; /* Free List page buffer */ - dma_addr_t dma_addr; /* PCI DMA address (if mapped) */ - /* and flags (see below) */ -}; - -/* - * The low bits of rx_sw_desc.dma_addr have special meaning. Note that the - * SGE also uses the low 4 bits to determine the size of the buffer. It uses - * those bits to index into the SGE_FL_BUFFER_SIZE[index] register array. - * Since we only use SGE_FL_BUFFER_SIZE0 and SGE_FL_BUFFER_SIZE1, these low 4 - * bits can only contain a 0 or a 1 to indicate which size buffer we're giving - * to the SGE. Thus, our software state of "is the buffer mapped for DMA" is - * maintained in an inverse sense so the hardware never sees that bit high. - */ -enum { - RX_LARGE_BUF = 1 << 0, /* buffer is SGE_FL_BUFFER_SIZE[1] */ - RX_UNMAPPED_BUF = 1 << 1, /* buffer is not mapped */ -}; - -/** - * get_buf_addr - return DMA buffer address of software descriptor - * @sdesc: pointer to the software buffer descriptor - * - * Return the DMA buffer address of a software descriptor (stripping out - * our low-order flag bits). - */ -static inline dma_addr_t get_buf_addr(const struct rx_sw_desc *sdesc) -{ - return sdesc->dma_addr & ~(dma_addr_t)(RX_LARGE_BUF | RX_UNMAPPED_BUF); -} - -/** - * is_buf_mapped - is buffer mapped for DMA? - * @sdesc: pointer to the software buffer descriptor - * - * Determine whether the buffer associated with a software descriptor in - * mapped for DMA or not. - */ -static inline bool is_buf_mapped(const struct rx_sw_desc *sdesc) -{ - return !(sdesc->dma_addr & RX_UNMAPPED_BUF); -} - -/** - * need_skb_unmap - does the platform need unmapping of sk_buffs? - * - * Returns true if the platform needs sk_buff unmapping. The compiler - * optimizes away unnecessary code if this returns true. - */ -static inline int need_skb_unmap(void) -{ -#ifdef CONFIG_NEED_DMA_MAP_STATE - return 1; -#else - return 0; -#endif -} - -/** - * txq_avail - return the number of available slots in a TX queue - * @tq: the TX queue - * - * Returns the number of available descriptors in a TX queue. - */ -static inline unsigned int txq_avail(const struct sge_txq *tq) -{ - return tq->size - 1 - tq->in_use; -} - -/** - * fl_cap - return the capacity of a Free List - * @fl: the Free List - * - * Returns the capacity of a Free List. The capacity is less than the - * size because an Egress Queue Index Unit worth of descriptors needs to - * be left unpopulated, otherwise the Producer and Consumer indices PIDX - * and CIDX will match and the hardware will think the FL is empty. - */ -static inline unsigned int fl_cap(const struct sge_fl *fl) -{ - return fl->size - FL_PER_EQ_UNIT; -} - -/** - * fl_starving - return whether a Free List is starving. - * @fl: the Free List - * - * Tests specified Free List to see whether the number of buffers - * available to the hardware has falled below our "starvation" - * threshold. - */ -static inline bool fl_starving(const struct sge_fl *fl) -{ - return fl->avail - fl->pend_cred <= FL_STARVE_THRES; -} - -/** - * map_skb - map an skb for DMA to the device - * @dev: the egress net device - * @skb: the packet to map - * @addr: a pointer to the base of the DMA mapping array - * - * Map an skb for DMA to the device and return an array of DMA addresses. - */ -static int map_skb(struct device *dev, const struct sk_buff *skb, - dma_addr_t *addr) -{ - const skb_frag_t *fp, *end; - const struct skb_shared_info *si; - - *addr = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); - if (dma_mapping_error(dev, *addr)) - goto out_err; - - si = skb_shinfo(skb); - end = &si->frags[si->nr_frags]; - for (fp = si->frags; fp < end; fp++) { - *++addr = dma_map_page(dev, fp->page, fp->page_offset, fp->size, - DMA_TO_DEVICE); - if (dma_mapping_error(dev, *addr)) - goto unwind; - } - return 0; - -unwind: - while (fp-- > si->frags) - dma_unmap_page(dev, *--addr, fp->size, DMA_TO_DEVICE); - dma_unmap_single(dev, addr[-1], skb_headlen(skb), DMA_TO_DEVICE); - -out_err: - return -ENOMEM; -} - -static void unmap_sgl(struct device *dev, const struct sk_buff *skb, - const struct ulptx_sgl *sgl, const struct sge_txq *tq) -{ - const struct ulptx_sge_pair *p; - unsigned int nfrags = skb_shinfo(skb)->nr_frags; - - if (likely(skb_headlen(skb))) - dma_unmap_single(dev, be64_to_cpu(sgl->addr0), - be32_to_cpu(sgl->len0), DMA_TO_DEVICE); - else { - dma_unmap_page(dev, be64_to_cpu(sgl->addr0), - be32_to_cpu(sgl->len0), DMA_TO_DEVICE); - nfrags--; - } - - /* - * the complexity below is because of the possibility of a wrap-around - * in the middle of an SGL - */ - for (p = sgl->sge; nfrags >= 2; nfrags -= 2) { - if (likely((u8 *)(p + 1) <= (u8 *)tq->stat)) { -unmap: - dma_unmap_page(dev, be64_to_cpu(p->addr[0]), - be32_to_cpu(p->len[0]), DMA_TO_DEVICE); - dma_unmap_page(dev, be64_to_cpu(p->addr[1]), - be32_to_cpu(p->len[1]), DMA_TO_DEVICE); - p++; - } else if ((u8 *)p == (u8 *)tq->stat) { - p = (const struct ulptx_sge_pair *)tq->desc; - goto unmap; - } else if ((u8 *)p + 8 == (u8 *)tq->stat) { - const __be64 *addr = (const __be64 *)tq->desc; - - dma_unmap_page(dev, be64_to_cpu(addr[0]), - be32_to_cpu(p->len[0]), DMA_TO_DEVICE); - dma_unmap_page(dev, be64_to_cpu(addr[1]), - be32_to_cpu(p->len[1]), DMA_TO_DEVICE); - p = (const struct ulptx_sge_pair *)&addr[2]; - } else { - const __be64 *addr = (const __be64 *)tq->desc; - - dma_unmap_page(dev, be64_to_cpu(p->addr[0]), - be32_to_cpu(p->len[0]), DMA_TO_DEVICE); - dma_unmap_page(dev, be64_to_cpu(addr[0]), - be32_to_cpu(p->len[1]), DMA_TO_DEVICE); - p = (const struct ulptx_sge_pair *)&addr[1]; - } - } - if (nfrags) { - __be64 addr; - - if ((u8 *)p == (u8 *)tq->stat) - p = (const struct ulptx_sge_pair *)tq->desc; - addr = ((u8 *)p + 16 <= (u8 *)tq->stat - ? p->addr[0] - : *(const __be64 *)tq->desc); - dma_unmap_page(dev, be64_to_cpu(addr), be32_to_cpu(p->len[0]), - DMA_TO_DEVICE); - } -} - -/** - * free_tx_desc - reclaims TX descriptors and their buffers - * @adapter: the adapter - * @tq: the TX queue to reclaim descriptors from - * @n: the number of descriptors to reclaim - * @unmap: whether the buffers should be unmapped for DMA - * - * Reclaims TX descriptors from an SGE TX queue and frees the associated - * TX buffers. Called with the TX queue lock held. - */ -static void free_tx_desc(struct adapter *adapter, struct sge_txq *tq, - unsigned int n, bool unmap) -{ - struct tx_sw_desc *sdesc; - unsigned int cidx = tq->cidx; - struct device *dev = adapter->pdev_dev; - - const int need_unmap = need_skb_unmap() && unmap; - - sdesc = &tq->sdesc[cidx]; - while (n--) { - /* - * If we kept a reference to the original TX skb, we need to - * unmap it from PCI DMA space (if required) and free it. - */ - if (sdesc->skb) { - if (need_unmap) - unmap_sgl(dev, sdesc->skb, sdesc->sgl, tq); - kfree_skb(sdesc->skb); - sdesc->skb = NULL; - } - - sdesc++; - if (++cidx == tq->size) { - cidx = 0; - sdesc = tq->sdesc; - } - } - tq->cidx = cidx; -} - -/* - * Return the number of reclaimable descriptors in a TX queue. - */ -static inline int reclaimable(const struct sge_txq *tq) -{ - int hw_cidx = be16_to_cpu(tq->stat->cidx); - int reclaimable = hw_cidx - tq->cidx; - if (reclaimable < 0) - reclaimable += tq->size; - return reclaimable; -} - -/** - * reclaim_completed_tx - reclaims completed TX descriptors - * @adapter: the adapter - * @tq: the TX queue to reclaim completed descriptors from - * @unmap: whether the buffers should be unmapped for DMA - * - * Reclaims TX descriptors that the SGE has indicated it has processed, - * and frees the associated buffers if possible. Called with the TX - * queue locked. - */ -static inline void reclaim_completed_tx(struct adapter *adapter, - struct sge_txq *tq, - bool unmap) -{ - int avail = reclaimable(tq); - - if (avail) { - /* - * Limit the amount of clean up work we do at a time to keep - * the TX lock hold time O(1). - */ - if (avail > MAX_TX_RECLAIM) - avail = MAX_TX_RECLAIM; - - free_tx_desc(adapter, tq, avail, unmap); - tq->in_use -= avail; - } -} - -/** - * get_buf_size - return the size of an RX Free List buffer. - * @sdesc: pointer to the software buffer descriptor - */ -static inline int get_buf_size(const struct rx_sw_desc *sdesc) -{ - return FL_PG_ORDER > 0 && (sdesc->dma_addr & RX_LARGE_BUF) - ? (PAGE_SIZE << FL_PG_ORDER) - : PAGE_SIZE; -} - -/** - * free_rx_bufs - free RX buffers on an SGE Free List - * @adapter: the adapter - * @fl: the SGE Free List to free buffers from - * @n: how many buffers to free - * - * Release the next @n buffers on an SGE Free List RX queue. The - * buffers must be made inaccessible to hardware before calling this - * function. - */ -static void free_rx_bufs(struct adapter *adapter, struct sge_fl *fl, int n) -{ - while (n--) { - struct rx_sw_desc *sdesc = &fl->sdesc[fl->cidx]; - - if (is_buf_mapped(sdesc)) - dma_unmap_page(adapter->pdev_dev, get_buf_addr(sdesc), - get_buf_size(sdesc), PCI_DMA_FROMDEVICE); - put_page(sdesc->page); - sdesc->page = NULL; - if (++fl->cidx == fl->size) - fl->cidx = 0; - fl->avail--; - } -} - -/** - * unmap_rx_buf - unmap the current RX buffer on an SGE Free List - * @adapter: the adapter - * @fl: the SGE Free List - * - * Unmap the current buffer on an SGE Free List RX queue. The - * buffer must be made inaccessible to HW before calling this function. - * - * This is similar to @free_rx_bufs above but does not free the buffer. - * Do note that the FL still loses any further access to the buffer. - * This is used predominantly to "transfer ownership" of an FL buffer - * to another entity (typically an skb's fragment list). - */ -static void unmap_rx_buf(struct adapter *adapter, struct sge_fl *fl) -{ - struct rx_sw_desc *sdesc = &fl->sdesc[fl->cidx]; - - if (is_buf_mapped(sdesc)) - dma_unmap_page(adapter->pdev_dev, get_buf_addr(sdesc), - get_buf_size(sdesc), PCI_DMA_FROMDEVICE); - sdesc->page = NULL; - if (++fl->cidx == fl->size) - fl->cidx = 0; - fl->avail--; -} - -/** - * ring_fl_db - righ doorbell on free list - * @adapter: the adapter - * @fl: the Free List whose doorbell should be rung ... - * - * Tell the Scatter Gather Engine that there are new free list entries - * available. - */ -static inline void ring_fl_db(struct adapter *adapter, struct sge_fl *fl) -{ - /* - * The SGE keeps track of its Producer and Consumer Indices in terms - * of Egress Queue Units so we can only tell it about integral numbers - * of multiples of Free List Entries per Egress Queue Units ... - */ - if (fl->pend_cred >= FL_PER_EQ_UNIT) { - wmb(); - t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_KDOORBELL, - DBPRIO | - QID(fl->cntxt_id) | - PIDX(fl->pend_cred / FL_PER_EQ_UNIT)); - fl->pend_cred %= FL_PER_EQ_UNIT; - } -} - -/** - * set_rx_sw_desc - initialize software RX buffer descriptor - * @sdesc: pointer to the softwore RX buffer descriptor - * @page: pointer to the page data structure backing the RX buffer - * @dma_addr: PCI DMA address (possibly with low-bit flags) - */ -static inline void set_rx_sw_desc(struct rx_sw_desc *sdesc, struct page *page, - dma_addr_t dma_addr) -{ - sdesc->page = page; - sdesc->dma_addr = dma_addr; -} - -/* - * Support for poisoning RX buffers ... - */ -#define POISON_BUF_VAL -1 - -static inline void poison_buf(struct page *page, size_t sz) -{ -#if POISON_BUF_VAL >= 0 - memset(page_address(page), POISON_BUF_VAL, sz); -#endif -} - -/** - * refill_fl - refill an SGE RX buffer ring - * @adapter: the adapter - * @fl: the Free List ring to refill - * @n: the number of new buffers to allocate - * @gfp: the gfp flags for the allocations - * - * (Re)populate an SGE free-buffer queue with up to @n new packet buffers, - * allocated with the supplied gfp flags. The caller must assure that - * @n does not exceed the queue's capacity -- i.e. (cidx == pidx) _IN - * EGRESS QUEUE UNITS_ indicates an empty Free List! Returns the number - * of buffers allocated. If afterwards the queue is found critically low, - * mark it as starving in the bitmap of starving FLs. - */ -static unsigned int refill_fl(struct adapter *adapter, struct sge_fl *fl, - int n, gfp_t gfp) -{ - struct page *page; - dma_addr_t dma_addr; - unsigned int cred = fl->avail; - __be64 *d = &fl->desc[fl->pidx]; - struct rx_sw_desc *sdesc = &fl->sdesc[fl->pidx]; - - /* - * Sanity: ensure that the result of adding n Free List buffers - * won't result in wrapping the SGE's Producer Index around to - * it's Consumer Index thereby indicating an empty Free List ... - */ - BUG_ON(fl->avail + n > fl->size - FL_PER_EQ_UNIT); - - /* - * If we support large pages, prefer large buffers and fail over to - * small pages if we can't allocate large pages to satisfy the refill. - * If we don't support large pages, drop directly into the small page - * allocation code. - */ - if (FL_PG_ORDER == 0) - goto alloc_small_pages; - - while (n) { - page = alloc_pages(gfp | __GFP_COMP | __GFP_NOWARN, - FL_PG_ORDER); - if (unlikely(!page)) { - /* - * We've failed inour attempt to allocate a "large - * page". Fail over to the "small page" allocation - * below. - */ - fl->large_alloc_failed++; - break; - } - poison_buf(page, PAGE_SIZE << FL_PG_ORDER); - - dma_addr = dma_map_page(adapter->pdev_dev, page, 0, - PAGE_SIZE << FL_PG_ORDER, - PCI_DMA_FROMDEVICE); - if (unlikely(dma_mapping_error(adapter->pdev_dev, dma_addr))) { - /* - * We've run out of DMA mapping space. Free up the - * buffer and return with what we've managed to put - * into the free list. We don't want to fail over to - * the small page allocation below in this case - * because DMA mapping resources are typically - * critical resources once they become scarse. - */ - __free_pages(page, FL_PG_ORDER); - goto out; - } - dma_addr |= RX_LARGE_BUF; - *d++ = cpu_to_be64(dma_addr); - - set_rx_sw_desc(sdesc, page, dma_addr); - sdesc++; - - fl->avail++; - if (++fl->pidx == fl->size) { - fl->pidx = 0; - sdesc = fl->sdesc; - d = fl->desc; - } - n--; - } - -alloc_small_pages: - while (n--) { - page = __netdev_alloc_page(adapter->port[0], - gfp | __GFP_NOWARN); - if (unlikely(!page)) { - fl->alloc_failed++; - break; - } - poison_buf(page, PAGE_SIZE); - - dma_addr = dma_map_page(adapter->pdev_dev, page, 0, PAGE_SIZE, - PCI_DMA_FROMDEVICE); - if (unlikely(dma_mapping_error(adapter->pdev_dev, dma_addr))) { - netdev_free_page(adapter->port[0], page); - break; - } - *d++ = cpu_to_be64(dma_addr); - - set_rx_sw_desc(sdesc, page, dma_addr); - sdesc++; - - fl->avail++; - if (++fl->pidx == fl->size) { - fl->pidx = 0; - sdesc = fl->sdesc; - d = fl->desc; - } - } - -out: - /* - * Update our accounting state to incorporate the new Free List - * buffers, tell the hardware about them and return the number of - * bufers which we were able to allocate. - */ - cred = fl->avail - cred; - fl->pend_cred += cred; - ring_fl_db(adapter, fl); - - if (unlikely(fl_starving(fl))) { - smp_wmb(); - set_bit(fl->cntxt_id, adapter->sge.starving_fl); - } - - return cred; -} - -/* - * Refill a Free List to its capacity or the Maximum Refill Increment, - * whichever is smaller ... - */ -static inline void __refill_fl(struct adapter *adapter, struct sge_fl *fl) -{ - refill_fl(adapter, fl, - min((unsigned int)MAX_RX_REFILL, fl_cap(fl) - fl->avail), - GFP_ATOMIC); -} - -/** - * alloc_ring - allocate resources for an SGE descriptor ring - * @dev: the PCI device's core device - * @nelem: the number of descriptors - * @hwsize: the size of each hardware descriptor - * @swsize: the size of each software descriptor - * @busaddrp: the physical PCI bus address of the allocated ring - * @swringp: return address pointer for software ring - * @stat_size: extra space in hardware ring for status information - * - * Allocates resources for an SGE descriptor ring, such as TX queues, - * free buffer lists, response queues, etc. Each SGE ring requires - * space for its hardware descriptors plus, optionally, space for software - * state associated with each hardware entry (the metadata). The function - * returns three values: the virtual address for the hardware ring (the - * return value of the function), the PCI bus address of the hardware - * ring (in *busaddrp), and the address of the software ring (in swringp). - * Both the hardware and software rings are returned zeroed out. - */ -static void *alloc_ring(struct device *dev, size_t nelem, size_t hwsize, - size_t swsize, dma_addr_t *busaddrp, void *swringp, - size_t stat_size) -{ - /* - * Allocate the hardware ring and PCI DMA bus address space for said. - */ - size_t hwlen = nelem * hwsize + stat_size; - void *hwring = dma_alloc_coherent(dev, hwlen, busaddrp, GFP_KERNEL); - - if (!hwring) - return NULL; - - /* - * If the caller wants a software ring, allocate it and return a - * pointer to it in *swringp. - */ - BUG_ON((swsize != 0) != (swringp != NULL)); - if (swsize) { - void *swring = kcalloc(nelem, swsize, GFP_KERNEL); - - if (!swring) { - dma_free_coherent(dev, hwlen, hwring, *busaddrp); - return NULL; - } - *(void **)swringp = swring; - } - - /* - * Zero out the hardware ring and return its address as our function - * value. - */ - memset(hwring, 0, hwlen); - return hwring; -} - -/** - * sgl_len - calculates the size of an SGL of the given capacity - * @n: the number of SGL entries - * - * Calculates the number of flits (8-byte units) needed for a Direct - * Scatter/Gather List that can hold the given number of entries. - */ -static inline unsigned int sgl_len(unsigned int n) -{ - /* - * A Direct Scatter Gather List uses 32-bit lengths and 64-bit PCI DMA - * addresses. The DSGL Work Request starts off with a 32-bit DSGL - * ULPTX header, then Length0, then Address0, then, for 1 <= i <= N, - * repeated sequences of { Length[i], Length[i+1], Address[i], - * Address[i+1] } (this ensures that all addresses are on 64-bit - * boundaries). If N is even, then Length[N+1] should be set to 0 and - * Address[N+1] is omitted. - * - * The following calculation incorporates all of the above. It's - * somewhat hard to follow but, briefly: the "+2" accounts for the - * first two flits which include the DSGL header, Length0 and - * Address0; the "(3*(n-1))/2" covers the main body of list entries (3 - * flits for every pair of the remaining N) +1 if (n-1) is odd; and - * finally the "+((n-1)&1)" adds the one remaining flit needed if - * (n-1) is odd ... - */ - n--; - return (3 * n) / 2 + (n & 1) + 2; -} - -/** - * flits_to_desc - returns the num of TX descriptors for the given flits - * @flits: the number of flits - * - * Returns the number of TX descriptors needed for the supplied number - * of flits. - */ -static inline unsigned int flits_to_desc(unsigned int flits) -{ - BUG_ON(flits > SGE_MAX_WR_LEN / sizeof(__be64)); - return DIV_ROUND_UP(flits, TXD_PER_EQ_UNIT); -} - -/** - * is_eth_imm - can an Ethernet packet be sent as immediate data? - * @skb: the packet - * - * Returns whether an Ethernet packet is small enough to fit completely as - * immediate data. - */ -static inline int is_eth_imm(const struct sk_buff *skb) -{ - /* - * The VF Driver uses the FW_ETH_TX_PKT_VM_WR firmware Work Request - * which does not accommodate immediate data. We could dike out all - * of the support code for immediate data but that would tie our hands - * too much if we ever want to enhace the firmware. It would also - * create more differences between the PF and VF Drivers. - */ - return false; -} - -/** - * calc_tx_flits - calculate the number of flits for a packet TX WR - * @skb: the packet - * - * Returns the number of flits needed for a TX Work Request for the - * given Ethernet packet, including the needed WR and CPL headers. - */ -static inline unsigned int calc_tx_flits(const struct sk_buff *skb) -{ - unsigned int flits; - - /* - * If the skb is small enough, we can pump it out as a work request - * with only immediate data. In that case we just have to have the - * TX Packet header plus the skb data in the Work Request. - */ - if (is_eth_imm(skb)) - return DIV_ROUND_UP(skb->len + sizeof(struct cpl_tx_pkt), - sizeof(__be64)); - - /* - * Otherwise, we're going to have to construct a Scatter gather list - * of the skb body and fragments. We also include the flits necessary - * for the TX Packet Work Request and CPL. We always have a firmware - * Write Header (incorporated as part of the cpl_tx_pkt_lso and - * cpl_tx_pkt structures), followed by either a TX Packet Write CPL - * message or, if we're doing a Large Send Offload, an LSO CPL message - * with an embeded TX Packet Write CPL message. - */ - flits = sgl_len(skb_shinfo(skb)->nr_frags + 1); - if (skb_shinfo(skb)->gso_size) - flits += (sizeof(struct fw_eth_tx_pkt_vm_wr) + - sizeof(struct cpl_tx_pkt_lso_core) + - sizeof(struct cpl_tx_pkt_core)) / sizeof(__be64); - else - flits += (sizeof(struct fw_eth_tx_pkt_vm_wr) + - sizeof(struct cpl_tx_pkt_core)) / sizeof(__be64); - return flits; -} - -/** - * write_sgl - populate a Scatter/Gather List for a packet - * @skb: the packet - * @tq: the TX queue we are writing into - * @sgl: starting location for writing the SGL - * @end: points right after the end of the SGL - * @start: start offset into skb main-body data to include in the SGL - * @addr: the list of DMA bus addresses for the SGL elements - * - * Generates a Scatter/Gather List for the buffers that make up a packet. - * The caller must provide adequate space for the SGL that will be written. - * The SGL includes all of the packet's page fragments and the data in its - * main body except for the first @start bytes. @pos must be 16-byte - * aligned and within a TX descriptor with available space. @end points - * write after the end of the SGL but does not account for any potential - * wrap around, i.e., @end > @tq->stat. - */ -static void write_sgl(const struct sk_buff *skb, struct sge_txq *tq, - struct ulptx_sgl *sgl, u64 *end, unsigned int start, - const dma_addr_t *addr) -{ - unsigned int i, len; - struct ulptx_sge_pair *to; - const struct skb_shared_info *si = skb_shinfo(skb); - unsigned int nfrags = si->nr_frags; - struct ulptx_sge_pair buf[MAX_SKB_FRAGS / 2 + 1]; - - len = skb_headlen(skb) - start; - if (likely(len)) { - sgl->len0 = htonl(len); - sgl->addr0 = cpu_to_be64(addr[0] + start); - nfrags++; - } else { - sgl->len0 = htonl(si->frags[0].size); - sgl->addr0 = cpu_to_be64(addr[1]); - } - - sgl->cmd_nsge = htonl(ULPTX_CMD(ULP_TX_SC_DSGL) | - ULPTX_NSGE(nfrags)); - if (likely(--nfrags == 0)) - return; - /* - * Most of the complexity below deals with the possibility we hit the - * end of the queue in the middle of writing the SGL. For this case - * only we create the SGL in a temporary buffer and then copy it. - */ - to = (u8 *)end > (u8 *)tq->stat ? buf : sgl->sge; - - for (i = (nfrags != si->nr_frags); nfrags >= 2; nfrags -= 2, to++) { - to->len[0] = cpu_to_be32(si->frags[i].size); - to->len[1] = cpu_to_be32(si->frags[++i].size); - to->addr[0] = cpu_to_be64(addr[i]); - to->addr[1] = cpu_to_be64(addr[++i]); - } - if (nfrags) { - to->len[0] = cpu_to_be32(si->frags[i].size); - to->len[1] = cpu_to_be32(0); - to->addr[0] = cpu_to_be64(addr[i + 1]); - } - if (unlikely((u8 *)end > (u8 *)tq->stat)) { - unsigned int part0 = (u8 *)tq->stat - (u8 *)sgl->sge, part1; - - if (likely(part0)) - memcpy(sgl->sge, buf, part0); - part1 = (u8 *)end - (u8 *)tq->stat; - memcpy(tq->desc, (u8 *)buf + part0, part1); - end = (void *)tq->desc + part1; - } - if ((uintptr_t)end & 8) /* 0-pad to multiple of 16 */ - *(u64 *)end = 0; -} - -/** - * check_ring_tx_db - check and potentially ring a TX queue's doorbell - * @adapter: the adapter - * @tq: the TX queue - * @n: number of new descriptors to give to HW - * - * Ring the doorbel for a TX queue. - */ -static inline void ring_tx_db(struct adapter *adapter, struct sge_txq *tq, - int n) -{ - /* - * Warn if we write doorbells with the wrong priority and write - * descriptors before telling HW. - */ - WARN_ON((QID(tq->cntxt_id) | PIDX(n)) & DBPRIO); - wmb(); - t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_KDOORBELL, - QID(tq->cntxt_id) | PIDX(n)); -} - -/** - * inline_tx_skb - inline a packet's data into TX descriptors - * @skb: the packet - * @tq: the TX queue where the packet will be inlined - * @pos: starting position in the TX queue to inline the packet - * - * Inline a packet's contents directly into TX descriptors, starting at - * the given position within the TX DMA ring. - * Most of the complexity of this operation is dealing with wrap arounds - * in the middle of the packet we want to inline. - */ -static void inline_tx_skb(const struct sk_buff *skb, const struct sge_txq *tq, - void *pos) -{ - u64 *p; - int left = (void *)tq->stat - pos; - - if (likely(skb->len <= left)) { - if (likely(!skb->data_len)) - skb_copy_from_linear_data(skb, pos, skb->len); - else - skb_copy_bits(skb, 0, pos, skb->len); - pos += skb->len; - } else { - skb_copy_bits(skb, 0, pos, left); - skb_copy_bits(skb, left, tq->desc, skb->len - left); - pos = (void *)tq->desc + (skb->len - left); - } - - /* 0-pad to multiple of 16 */ - p = PTR_ALIGN(pos, 8); - if ((uintptr_t)p & 8) - *p = 0; -} - -/* - * Figure out what HW csum a packet wants and return the appropriate control - * bits. - */ -static u64 hwcsum(const struct sk_buff *skb) -{ - int csum_type; - const struct iphdr *iph = ip_hdr(skb); - - if (iph->version == 4) { - if (iph->protocol == IPPROTO_TCP) - csum_type = TX_CSUM_TCPIP; - else if (iph->protocol == IPPROTO_UDP) - csum_type = TX_CSUM_UDPIP; - else { -nocsum: - /* - * unknown protocol, disable HW csum - * and hope a bad packet is detected - */ - return TXPKT_L4CSUM_DIS; - } - } else { - /* - * this doesn't work with extension headers - */ - const struct ipv6hdr *ip6h = (const struct ipv6hdr *)iph; - - if (ip6h->nexthdr == IPPROTO_TCP) - csum_type = TX_CSUM_TCPIP6; - else if (ip6h->nexthdr == IPPROTO_UDP) - csum_type = TX_CSUM_UDPIP6; - else - goto nocsum; - } - - if (likely(csum_type >= TX_CSUM_TCPIP)) - return TXPKT_CSUM_TYPE(csum_type) | - TXPKT_IPHDR_LEN(skb_network_header_len(skb)) | - TXPKT_ETHHDR_LEN(skb_network_offset(skb) - ETH_HLEN); - else { - int start = skb_transport_offset(skb); - - return TXPKT_CSUM_TYPE(csum_type) | - TXPKT_CSUM_START(start) | - TXPKT_CSUM_LOC(start + skb->csum_offset); - } -} - -/* - * Stop an Ethernet TX queue and record that state change. - */ -static void txq_stop(struct sge_eth_txq *txq) -{ - netif_tx_stop_queue(txq->txq); - txq->q.stops++; -} - -/* - * Advance our software state for a TX queue by adding n in use descriptors. - */ -static inline void txq_advance(struct sge_txq *tq, unsigned int n) -{ - tq->in_use += n; - tq->pidx += n; - if (tq->pidx >= tq->size) - tq->pidx -= tq->size; -} - -/** - * t4vf_eth_xmit - add a packet to an Ethernet TX queue - * @skb: the packet - * @dev: the egress net device - * - * Add a packet to an SGE Ethernet TX queue. Runs with softirqs disabled. - */ -int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev) -{ - u32 wr_mid; - u64 cntrl, *end; - int qidx, credits; - unsigned int flits, ndesc; - struct adapter *adapter; - struct sge_eth_txq *txq; - const struct port_info *pi; - struct fw_eth_tx_pkt_vm_wr *wr; - struct cpl_tx_pkt_core *cpl; - const struct skb_shared_info *ssi; - dma_addr_t addr[MAX_SKB_FRAGS + 1]; - const size_t fw_hdr_copy_len = (sizeof(wr->ethmacdst) + - sizeof(wr->ethmacsrc) + - sizeof(wr->ethtype) + - sizeof(wr->vlantci)); - - /* - * The chip minimum packet length is 10 octets but the firmware - * command that we are using requires that we copy the Ethernet header - * (including the VLAN tag) into the header so we reject anything - * smaller than that ... - */ - if (unlikely(skb->len < fw_hdr_copy_len)) - goto out_free; - - /* - * Figure out which TX Queue we're going to use. - */ - pi = netdev_priv(dev); - adapter = pi->adapter; - qidx = skb_get_queue_mapping(skb); - BUG_ON(qidx >= pi->nqsets); - txq = &adapter->sge.ethtxq[pi->first_qset + qidx]; - - /* - * Take this opportunity to reclaim any TX Descriptors whose DMA - * transfers have completed. - */ - reclaim_completed_tx(adapter, &txq->q, true); - - /* - * Calculate the number of flits and TX Descriptors we're going to - * need along with how many TX Descriptors will be left over after - * we inject our Work Request. - */ - flits = calc_tx_flits(skb); - ndesc = flits_to_desc(flits); - credits = txq_avail(&txq->q) - ndesc; - - if (unlikely(credits < 0)) { - /* - * Not enough room for this packet's Work Request. Stop the - * TX Queue and return a "busy" condition. The queue will get - * started later on when the firmware informs us that space - * has opened up. - */ - txq_stop(txq); - dev_err(adapter->pdev_dev, - "%s: TX ring %u full while queue awake!\n", - dev->name, qidx); - return NETDEV_TX_BUSY; - } - - if (!is_eth_imm(skb) && - unlikely(map_skb(adapter->pdev_dev, skb, addr) < 0)) { - /* - * We need to map the skb into PCI DMA space (because it can't - * be in-lined directly into the Work Request) and the mapping - * operation failed. Record the error and drop the packet. - */ - txq->mapping_err++; - goto out_free; - } - - wr_mid = FW_WR_LEN16(DIV_ROUND_UP(flits, 2)); - if (unlikely(credits < ETHTXQ_STOP_THRES)) { - /* - * After we're done injecting the Work Request for this - * packet, we'll be below our "stop threshold" so stop the TX - * Queue now and schedule a request for an SGE Egress Queue - * Update message. The queue will get started later on when - * the firmware processes this Work Request and sends us an - * Egress Queue Status Update message indicating that space - * has opened up. - */ - txq_stop(txq); - wr_mid |= FW_WR_EQUEQ | FW_WR_EQUIQ; - } - - /* - * Start filling in our Work Request. Note that we do _not_ handle - * the WR Header wrapping around the TX Descriptor Ring. If our - * maximum header size ever exceeds one TX Descriptor, we'll need to - * do something else here. - */ - BUG_ON(DIV_ROUND_UP(ETHTXQ_MAX_HDR, TXD_PER_EQ_UNIT) > 1); - wr = (void *)&txq->q.desc[txq->q.pidx]; - wr->equiq_to_len16 = cpu_to_be32(wr_mid); - wr->r3[0] = cpu_to_be64(0); - wr->r3[1] = cpu_to_be64(0); - skb_copy_from_linear_data(skb, (void *)wr->ethmacdst, fw_hdr_copy_len); - end = (u64 *)wr + flits; - - /* - * If this is a Large Send Offload packet we'll put in an LSO CPL - * message with an encapsulated TX Packet CPL message. Otherwise we - * just use a TX Packet CPL message. - */ - ssi = skb_shinfo(skb); - if (ssi->gso_size) { - struct cpl_tx_pkt_lso_core *lso = (void *)(wr + 1); - bool v6 = (ssi->gso_type & SKB_GSO_TCPV6) != 0; - int l3hdr_len = skb_network_header_len(skb); - int eth_xtra_len = skb_network_offset(skb) - ETH_HLEN; - - wr->op_immdlen = - cpu_to_be32(FW_WR_OP(FW_ETH_TX_PKT_VM_WR) | - FW_WR_IMMDLEN(sizeof(*lso) + - sizeof(*cpl))); - /* - * Fill in the LSO CPL message. - */ - lso->lso_ctrl = - cpu_to_be32(LSO_OPCODE(CPL_TX_PKT_LSO) | - LSO_FIRST_SLICE | - LSO_LAST_SLICE | - LSO_IPV6(v6) | - LSO_ETHHDR_LEN(eth_xtra_len/4) | - LSO_IPHDR_LEN(l3hdr_len/4) | - LSO_TCPHDR_LEN(tcp_hdr(skb)->doff)); - lso->ipid_ofst = cpu_to_be16(0); - lso->mss = cpu_to_be16(ssi->gso_size); - lso->seqno_offset = cpu_to_be32(0); - lso->len = cpu_to_be32(skb->len); - - /* - * Set up TX Packet CPL pointer, control word and perform - * accounting. - */ - cpl = (void *)(lso + 1); - cntrl = (TXPKT_CSUM_TYPE(v6 ? TX_CSUM_TCPIP6 : TX_CSUM_TCPIP) | - TXPKT_IPHDR_LEN(l3hdr_len) | - TXPKT_ETHHDR_LEN(eth_xtra_len)); - txq->tso++; - txq->tx_cso += ssi->gso_segs; - } else { - int len; - - len = is_eth_imm(skb) ? skb->len + sizeof(*cpl) : sizeof(*cpl); - wr->op_immdlen = - cpu_to_be32(FW_WR_OP(FW_ETH_TX_PKT_VM_WR) | - FW_WR_IMMDLEN(len)); - - /* - * Set up TX Packet CPL pointer, control word and perform - * accounting. - */ - cpl = (void *)(wr + 1); - if (skb->ip_summed == CHECKSUM_PARTIAL) { - cntrl = hwcsum(skb) | TXPKT_IPCSUM_DIS; - txq->tx_cso++; - } else - cntrl = TXPKT_L4CSUM_DIS | TXPKT_IPCSUM_DIS; - } - - /* - * If there's a VLAN tag present, add that to the list of things to - * do in this Work Request. - */ - if (vlan_tx_tag_present(skb)) { - txq->vlan_ins++; - cntrl |= TXPKT_VLAN_VLD | TXPKT_VLAN(vlan_tx_tag_get(skb)); - } - - /* - * Fill in the TX Packet CPL message header. - */ - cpl->ctrl0 = cpu_to_be32(TXPKT_OPCODE(CPL_TX_PKT_XT) | - TXPKT_INTF(pi->port_id) | - TXPKT_PF(0)); - cpl->pack = cpu_to_be16(0); - cpl->len = cpu_to_be16(skb->len); - cpl->ctrl1 = cpu_to_be64(cntrl); - -#ifdef T4_TRACE - T4_TRACE5(adapter->tb[txq->q.cntxt_id & 7], - "eth_xmit: ndesc %u, credits %u, pidx %u, len %u, frags %u", - ndesc, credits, txq->q.pidx, skb->len, ssi->nr_frags); -#endif - - /* - * Fill in the body of the TX Packet CPL message with either in-lined - * data or a Scatter/Gather List. - */ - if (is_eth_imm(skb)) { - /* - * In-line the packet's data and free the skb since we don't - * need it any longer. - */ - inline_tx_skb(skb, &txq->q, cpl + 1); - dev_kfree_skb(skb); - } else { - /* - * Write the skb's Scatter/Gather list into the TX Packet CPL - * message and retain a pointer to the skb so we can free it - * later when its DMA completes. (We store the skb pointer - * in the Software Descriptor corresponding to the last TX - * Descriptor used by the Work Request.) - * - * The retained skb will be freed when the corresponding TX - * Descriptors are reclaimed after their DMAs complete. - * However, this could take quite a while since, in general, - * the hardware is set up to be lazy about sending DMA - * completion notifications to us and we mostly perform TX - * reclaims in the transmit routine. - * - * This is good for performamce but means that we rely on new - * TX packets arriving to run the destructors of completed - * packets, which open up space in their sockets' send queues. - * Sometimes we do not get such new packets causing TX to - * stall. A single UDP transmitter is a good example of this - * situation. We have a clean up timer that periodically - * reclaims completed packets but it doesn't run often enough - * (nor do we want it to) to prevent lengthy stalls. A - * solution to this problem is to run the destructor early, - * after the packet is queued but before it's DMAd. A con is - * that we lie to socket memory accounting, but the amount of - * extra memory is reasonable (limited by the number of TX - * descriptors), the packets do actually get freed quickly by - * new packets almost always, and for protocols like TCP that - * wait for acks to really free up the data the extra memory - * is even less. On the positive side we run the destructors - * on the sending CPU rather than on a potentially different - * completing CPU, usually a good thing. - * - * Run the destructor before telling the DMA engine about the - * packet to make sure it doesn't complete and get freed - * prematurely. - */ - struct ulptx_sgl *sgl = (struct ulptx_sgl *)(cpl + 1); - struct sge_txq *tq = &txq->q; - int last_desc; - - /* - * If the Work Request header was an exact multiple of our TX - * Descriptor length, then it's possible that the starting SGL - * pointer lines up exactly with the end of our TX Descriptor - * ring. If that's the case, wrap around to the beginning - * here ... - */ - if (unlikely((void *)sgl == (void *)tq->stat)) { - sgl = (void *)tq->desc; - end = (void *)((void *)tq->desc + - ((void *)end - (void *)tq->stat)); - } - - write_sgl(skb, tq, sgl, end, 0, addr); - skb_orphan(skb); - - last_desc = tq->pidx + ndesc - 1; - if (last_desc >= tq->size) - last_desc -= tq->size; - tq->sdesc[last_desc].skb = skb; - tq->sdesc[last_desc].sgl = sgl; - } - - /* - * Advance our internal TX Queue state, tell the hardware about - * the new TX descriptors and return success. - */ - txq_advance(&txq->q, ndesc); - dev->trans_start = jiffies; - ring_tx_db(adapter, &txq->q, ndesc); - return NETDEV_TX_OK; - -out_free: - /* - * An error of some sort happened. Free the TX skb and tell the - * OS that we've "dealt" with the packet ... - */ - dev_kfree_skb(skb); - return NETDEV_TX_OK; -} - -/** - * t4vf_pktgl_to_skb - build an sk_buff from a packet gather list - * @gl: the gather list - * @skb_len: size of sk_buff main body if it carries fragments - * @pull_len: amount of data to move to the sk_buff's main body - * - * Builds an sk_buff from the given packet gather list. Returns the - * sk_buff or %NULL if sk_buff allocation failed. - */ -struct sk_buff *t4vf_pktgl_to_skb(const struct pkt_gl *gl, - unsigned int skb_len, unsigned int pull_len) -{ - struct sk_buff *skb; - struct skb_shared_info *ssi; - - /* - * If the ingress packet is small enough, allocate an skb large enough - * for all of the data and copy it inline. Otherwise, allocate an skb - * with enough room to pull in the header and reference the rest of - * the data via the skb fragment list. - * - * Below we rely on RX_COPY_THRES being less than the smallest Rx - * buff! size, which is expected since buffers are at least - * PAGE_SIZEd. In this case packets up to RX_COPY_THRES have only one - * fragment. - */ - if (gl->tot_len <= RX_COPY_THRES) { - /* small packets have only one fragment */ - skb = alloc_skb(gl->tot_len, GFP_ATOMIC); - if (unlikely(!skb)) - goto out; - __skb_put(skb, gl->tot_len); - skb_copy_to_linear_data(skb, gl->va, gl->tot_len); - } else { - skb = alloc_skb(skb_len, GFP_ATOMIC); - if (unlikely(!skb)) - goto out; - __skb_put(skb, pull_len); - skb_copy_to_linear_data(skb, gl->va, pull_len); - - ssi = skb_shinfo(skb); - ssi->frags[0].page = gl->frags[0].page; - ssi->frags[0].page_offset = gl->frags[0].page_offset + pull_len; - ssi->frags[0].size = gl->frags[0].size - pull_len; - if (gl->nfrags > 1) - memcpy(&ssi->frags[1], &gl->frags[1], - (gl->nfrags-1) * sizeof(skb_frag_t)); - ssi->nr_frags = gl->nfrags; - - skb->len = gl->tot_len; - skb->data_len = skb->len - pull_len; - skb->truesize += skb->data_len; - - /* Get a reference for the last page, we don't own it */ - get_page(gl->frags[gl->nfrags - 1].page); - } - -out: - return skb; -} - -/** - * t4vf_pktgl_free - free a packet gather list - * @gl: the gather list - * - * Releases the pages of a packet gather list. We do not own the last - * page on the list and do not free it. - */ -void t4vf_pktgl_free(const struct pkt_gl *gl) -{ - int frag; - - frag = gl->nfrags - 1; - while (frag--) - put_page(gl->frags[frag].page); -} - -/** - * copy_frags - copy fragments from gather list into skb_shared_info - * @si: destination skb shared info structure - * @gl: source internal packet gather list - * @offset: packet start offset in first page - * - * Copy an internal packet gather list into a Linux skb_shared_info - * structure. - */ -static inline void copy_frags(struct skb_shared_info *si, - const struct pkt_gl *gl, - unsigned int offset) -{ - unsigned int n; - - /* usually there's just one frag */ - si->frags[0].page = gl->frags[0].page; - si->frags[0].page_offset = gl->frags[0].page_offset + offset; - si->frags[0].size = gl->frags[0].size - offset; - si->nr_frags = gl->nfrags; - - n = gl->nfrags - 1; - if (n) - memcpy(&si->frags[1], &gl->frags[1], n * sizeof(skb_frag_t)); - - /* get a reference to the last page, we don't own it */ - get_page(gl->frags[n].page); -} - -/** - * do_gro - perform Generic Receive Offload ingress packet processing - * @rxq: ingress RX Ethernet Queue - * @gl: gather list for ingress packet - * @pkt: CPL header for last packet fragment - * - * Perform Generic Receive Offload (GRO) ingress packet processing. - * We use the standard Linux GRO interfaces for this. - */ -static void do_gro(struct sge_eth_rxq *rxq, const struct pkt_gl *gl, - const struct cpl_rx_pkt *pkt) -{ - int ret; - struct sk_buff *skb; - - skb = napi_get_frags(&rxq->rspq.napi); - if (unlikely(!skb)) { - t4vf_pktgl_free(gl); - rxq->stats.rx_drops++; - return; - } - - copy_frags(skb_shinfo(skb), gl, PKTSHIFT); - skb->len = gl->tot_len - PKTSHIFT; - skb->data_len = skb->len; - skb->truesize += skb->data_len; - skb->ip_summed = CHECKSUM_UNNECESSARY; - skb_record_rx_queue(skb, rxq->rspq.idx); - - if (pkt->vlan_ex) - __vlan_hwaccel_put_tag(skb, be16_to_cpu(pkt->vlan)); - ret = napi_gro_frags(&rxq->rspq.napi); - - if (ret == GRO_HELD) - rxq->stats.lro_pkts++; - else if (ret == GRO_MERGED || ret == GRO_MERGED_FREE) - rxq->stats.lro_merged++; - rxq->stats.pkts++; - rxq->stats.rx_cso++; -} - -/** - * t4vf_ethrx_handler - process an ingress ethernet packet - * @rspq: the response queue that received the packet - * @rsp: the response queue descriptor holding the RX_PKT message - * @gl: the gather list of packet fragments - * - * Process an ingress ethernet packet and deliver it to the stack. - */ -int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp, - const struct pkt_gl *gl) -{ - struct sk_buff *skb; - const struct cpl_rx_pkt *pkt = (void *)&rsp[1]; - bool csum_ok = pkt->csum_calc && !pkt->err_vec; - struct sge_eth_rxq *rxq = container_of(rspq, struct sge_eth_rxq, rspq); - - /* - * If this is a good TCP packet and we have Generic Receive Offload - * enabled, handle the packet in the GRO path. - */ - if ((pkt->l2info & cpu_to_be32(RXF_TCP)) && - (rspq->netdev->features & NETIF_F_GRO) && csum_ok && - !pkt->ip_frag) { - do_gro(rxq, gl, pkt); - return 0; - } - - /* - * Convert the Packet Gather List into an skb. - */ - skb = t4vf_pktgl_to_skb(gl, RX_SKB_LEN, RX_PULL_LEN); - if (unlikely(!skb)) { - t4vf_pktgl_free(gl); - rxq->stats.rx_drops++; - return 0; - } - __skb_pull(skb, PKTSHIFT); - skb->protocol = eth_type_trans(skb, rspq->netdev); - skb_record_rx_queue(skb, rspq->idx); - rxq->stats.pkts++; - - if (csum_ok && (rspq->netdev->features & NETIF_F_RXCSUM) && - !pkt->err_vec && (be32_to_cpu(pkt->l2info) & (RXF_UDP|RXF_TCP))) { - if (!pkt->ip_frag) - skb->ip_summed = CHECKSUM_UNNECESSARY; - else { - __sum16 c = (__force __sum16)pkt->csum; - skb->csum = csum_unfold(c); - skb->ip_summed = CHECKSUM_COMPLETE; - } - rxq->stats.rx_cso++; - } else - skb_checksum_none_assert(skb); - - if (pkt->vlan_ex) { - rxq->stats.vlan_ex++; - __vlan_hwaccel_put_tag(skb, be16_to_cpu(pkt->vlan)); - } - - netif_receive_skb(skb); - - return 0; -} - -/** - * is_new_response - check if a response is newly written - * @rc: the response control descriptor - * @rspq: the response queue - * - * Returns true if a response descriptor contains a yet unprocessed - * response. - */ -static inline bool is_new_response(const struct rsp_ctrl *rc, - const struct sge_rspq *rspq) -{ - return RSPD_GEN(rc->type_gen) == rspq->gen; -} - -/** - * restore_rx_bufs - put back a packet's RX buffers - * @gl: the packet gather list - * @fl: the SGE Free List - * @nfrags: how many fragments in @si - * - * Called when we find out that the current packet, @si, can't be - * processed right away for some reason. This is a very rare event and - * there's no effort to make this suspension/resumption process - * particularly efficient. - * - * We implement the suspension by putting all of the RX buffers associated - * with the current packet back on the original Free List. The buffers - * have already been unmapped and are left unmapped, we mark them as - * unmapped in order to prevent further unmapping attempts. (Effectively - * this function undoes the series of @unmap_rx_buf calls which were done - * to create the current packet's gather list.) This leaves us ready to - * restart processing of the packet the next time we start processing the - * RX Queue ... - */ -static void restore_rx_bufs(const struct pkt_gl *gl, struct sge_fl *fl, - int frags) -{ - struct rx_sw_desc *sdesc; - - while (frags--) { - if (fl->cidx == 0) - fl->cidx = fl->size - 1; - else - fl->cidx--; - sdesc = &fl->sdesc[fl->cidx]; - sdesc->page = gl->frags[frags].page; - sdesc->dma_addr |= RX_UNMAPPED_BUF; - fl->avail++; - } -} - -/** - * rspq_next - advance to the next entry in a response queue - * @rspq: the queue - * - * Updates the state of a response queue to advance it to the next entry. - */ -static inline void rspq_next(struct sge_rspq *rspq) -{ - rspq->cur_desc = (void *)rspq->cur_desc + rspq->iqe_len; - if (unlikely(++rspq->cidx == rspq->size)) { - rspq->cidx = 0; - rspq->gen ^= 1; - rspq->cur_desc = rspq->desc; - } -} - -/** - * process_responses - process responses from an SGE response queue - * @rspq: the ingress response queue to process - * @budget: how many responses can be processed in this round - * - * Process responses from a Scatter Gather Engine response queue up to - * the supplied budget. Responses include received packets as well as - * control messages from firmware or hardware. - * - * Additionally choose the interrupt holdoff time for the next interrupt - * on this queue. If the system is under memory shortage use a fairly - * long delay to help recovery. - */ -int process_responses(struct sge_rspq *rspq, int budget) -{ - struct sge_eth_rxq *rxq = container_of(rspq, struct sge_eth_rxq, rspq); - int budget_left = budget; - - while (likely(budget_left)) { - int ret, rsp_type; - const struct rsp_ctrl *rc; - - rc = (void *)rspq->cur_desc + (rspq->iqe_len - sizeof(*rc)); - if (!is_new_response(rc, rspq)) - break; - - /* - * Figure out what kind of response we've received from the - * SGE. - */ - rmb(); - rsp_type = RSPD_TYPE(rc->type_gen); - if (likely(rsp_type == RSP_TYPE_FLBUF)) { - skb_frag_t *fp; - struct pkt_gl gl; - const struct rx_sw_desc *sdesc; - u32 bufsz, frag; - u32 len = be32_to_cpu(rc->pldbuflen_qid); - - /* - * If we get a "new buffer" message from the SGE we - * need to move on to the next Free List buffer. - */ - if (len & RSPD_NEWBUF) { - /* - * We get one "new buffer" message when we - * first start up a queue so we need to ignore - * it when our offset into the buffer is 0. - */ - if (likely(rspq->offset > 0)) { - free_rx_bufs(rspq->adapter, &rxq->fl, - 1); - rspq->offset = 0; - } - len = RSPD_LEN(len); - } - gl.tot_len = len; - - /* - * Gather packet fragments. - */ - for (frag = 0, fp = gl.frags; /**/; frag++, fp++) { - BUG_ON(frag >= MAX_SKB_FRAGS); - BUG_ON(rxq->fl.avail == 0); - sdesc = &rxq->fl.sdesc[rxq->fl.cidx]; - bufsz = get_buf_size(sdesc); - fp->page = sdesc->page; - fp->page_offset = rspq->offset; - fp->size = min(bufsz, len); - len -= fp->size; - if (!len) - break; - unmap_rx_buf(rspq->adapter, &rxq->fl); - } - gl.nfrags = frag+1; - - /* - * Last buffer remains mapped so explicitly make it - * coherent for CPU access and start preloading first - * cache line ... - */ - dma_sync_single_for_cpu(rspq->adapter->pdev_dev, - get_buf_addr(sdesc), - fp->size, DMA_FROM_DEVICE); - gl.va = (page_address(gl.frags[0].page) + - gl.frags[0].page_offset); - prefetch(gl.va); - - /* - * Hand the new ingress packet to the handler for - * this Response Queue. - */ - ret = rspq->handler(rspq, rspq->cur_desc, &gl); - if (likely(ret == 0)) - rspq->offset += ALIGN(fp->size, FL_ALIGN); - else - restore_rx_bufs(&gl, &rxq->fl, frag); - } else if (likely(rsp_type == RSP_TYPE_CPL)) { - ret = rspq->handler(rspq, rspq->cur_desc, NULL); - } else { - WARN_ON(rsp_type > RSP_TYPE_CPL); - ret = 0; - } - - if (unlikely(ret)) { - /* - * Couldn't process descriptor, back off for recovery. - * We use the SGE's last timer which has the longest - * interrupt coalescing value ... - */ - const int NOMEM_TIMER_IDX = SGE_NTIMERS-1; - rspq->next_intr_params = - QINTR_TIMER_IDX(NOMEM_TIMER_IDX); - break; - } - - rspq_next(rspq); - budget_left--; - } - - /* - * If this is a Response Queue with an associated Free List and - * at least two Egress Queue units available in the Free List - * for new buffer pointers, refill the Free List. - */ - if (rspq->offset >= 0 && - rxq->fl.size - rxq->fl.avail >= 2*FL_PER_EQ_UNIT) - __refill_fl(rspq->adapter, &rxq->fl); - return budget - budget_left; -} - -/** - * napi_rx_handler - the NAPI handler for RX processing - * @napi: the napi instance - * @budget: how many packets we can process in this round - * - * Handler for new data events when using NAPI. This does not need any - * locking or protection from interrupts as data interrupts are off at - * this point and other adapter interrupts do not interfere (the latter - * in not a concern at all with MSI-X as non-data interrupts then have - * a separate handler). - */ -static int napi_rx_handler(struct napi_struct *napi, int budget) -{ - unsigned int intr_params; - struct sge_rspq *rspq = container_of(napi, struct sge_rspq, napi); - int work_done = process_responses(rspq, budget); - - if (likely(work_done < budget)) { - napi_complete(napi); - intr_params = rspq->next_intr_params; - rspq->next_intr_params = rspq->intr_params; - } else - intr_params = QINTR_TIMER_IDX(SGE_TIMER_UPD_CIDX); - - if (unlikely(work_done == 0)) - rspq->unhandled_irqs++; - - t4_write_reg(rspq->adapter, - T4VF_SGE_BASE_ADDR + SGE_VF_GTS, - CIDXINC(work_done) | - INGRESSQID((u32)rspq->cntxt_id) | - SEINTARM(intr_params)); - return work_done; -} - -/* - * The MSI-X interrupt handler for an SGE response queue for the NAPI case - * (i.e., response queue serviced by NAPI polling). - */ -irqreturn_t t4vf_sge_intr_msix(int irq, void *cookie) -{ - struct sge_rspq *rspq = cookie; - - napi_schedule(&rspq->napi); - return IRQ_HANDLED; -} - -/* - * Process the indirect interrupt entries in the interrupt queue and kick off - * NAPI for each queue that has generated an entry. - */ -static unsigned int process_intrq(struct adapter *adapter) -{ - struct sge *s = &adapter->sge; - struct sge_rspq *intrq = &s->intrq; - unsigned int work_done; - - spin_lock(&adapter->sge.intrq_lock); - for (work_done = 0; ; work_done++) { - const struct rsp_ctrl *rc; - unsigned int qid, iq_idx; - struct sge_rspq *rspq; - - /* - * Grab the next response from the interrupt queue and bail - * out if it's not a new response. - */ - rc = (void *)intrq->cur_desc + (intrq->iqe_len - sizeof(*rc)); - if (!is_new_response(rc, intrq)) - break; - - /* - * If the response isn't a forwarded interrupt message issue a - * error and go on to the next response message. This should - * never happen ... - */ - rmb(); - if (unlikely(RSPD_TYPE(rc->type_gen) != RSP_TYPE_INTR)) { - dev_err(adapter->pdev_dev, - "Unexpected INTRQ response type %d\n", - RSPD_TYPE(rc->type_gen)); - continue; - } - - /* - * Extract the Queue ID from the interrupt message and perform - * sanity checking to make sure it really refers to one of our - * Ingress Queues which is active and matches the queue's ID. - * None of these error conditions should ever happen so we may - * want to either make them fatal and/or conditionalized under - * DEBUG. - */ - qid = RSPD_QID(be32_to_cpu(rc->pldbuflen_qid)); - iq_idx = IQ_IDX(s, qid); - if (unlikely(iq_idx >= MAX_INGQ)) { - dev_err(adapter->pdev_dev, - "Ingress QID %d out of range\n", qid); - continue; - } - rspq = s->ingr_map[iq_idx]; - if (unlikely(rspq == NULL)) { - dev_err(adapter->pdev_dev, - "Ingress QID %d RSPQ=NULL\n", qid); - continue; - } - if (unlikely(rspq->abs_id != qid)) { - dev_err(adapter->pdev_dev, - "Ingress QID %d refers to RSPQ %d\n", - qid, rspq->abs_id); - continue; - } - - /* - * Schedule NAPI processing on the indicated Response Queue - * and move on to the next entry in the Forwarded Interrupt - * Queue. - */ - napi_schedule(&rspq->napi); - rspq_next(intrq); - } - - t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS, - CIDXINC(work_done) | - INGRESSQID(intrq->cntxt_id) | - SEINTARM(intrq->intr_params)); - - spin_unlock(&adapter->sge.intrq_lock); - - return work_done; -} - -/* - * The MSI interrupt handler handles data events from SGE response queues as - * well as error and other async events as they all use the same MSI vector. - */ -irqreturn_t t4vf_intr_msi(int irq, void *cookie) -{ - struct adapter *adapter = cookie; - - process_intrq(adapter); - return IRQ_HANDLED; -} - -/** - * t4vf_intr_handler - select the top-level interrupt handler - * @adapter: the adapter - * - * Selects the top-level interrupt handler based on the type of interrupts - * (MSI-X or MSI). - */ -irq_handler_t t4vf_intr_handler(struct adapter *adapter) -{ - BUG_ON((adapter->flags & (USING_MSIX|USING_MSI)) == 0); - if (adapter->flags & USING_MSIX) - return t4vf_sge_intr_msix; - else - return t4vf_intr_msi; -} - -/** - * sge_rx_timer_cb - perform periodic maintenance of SGE RX queues - * @data: the adapter - * - * Runs periodically from a timer to perform maintenance of SGE RX queues. - * - * a) 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 schedule NAPI to do - * the actual refill. - */ -static void sge_rx_timer_cb(unsigned long data) -{ - struct adapter *adapter = (struct adapter *)data; - struct sge *s = &adapter->sge; - unsigned int i; - - /* - * Scan the "Starving Free Lists" flag array looking for any Free - * Lists in need of more free buffers. If we find one and it's not - * being actively polled, then bump its "starving" counter and attempt - * to refill it. If we're successful in adding enough buffers to push - * the Free List over the starving threshold, then we can clear its - * "starving" status. - */ - for (i = 0; i < ARRAY_SIZE(s->starving_fl); i++) { - unsigned long m; - - for (m = s->starving_fl[i]; m; m &= m - 1) { - unsigned int id = __ffs(m) + i * BITS_PER_LONG; - struct sge_fl *fl = s->egr_map[id]; - - clear_bit(id, s->starving_fl); - smp_mb__after_clear_bit(); - - /* - * Since we are accessing fl without a lock there's a - * small probability of a false positive where we - * schedule napi but the FL is no longer starving. - * No biggie. - */ - if (fl_starving(fl)) { - struct sge_eth_rxq *rxq; - - rxq = container_of(fl, struct sge_eth_rxq, fl); - if (napi_reschedule(&rxq->rspq.napi)) - fl->starving++; - else - set_bit(id, s->starving_fl); - } - } - } - - /* - * Reschedule the next scan for starving Free Lists ... - */ - mod_timer(&s->rx_timer, jiffies + RX_QCHECK_PERIOD); -} - -/** - * sge_tx_timer_cb - perform periodic maintenance of SGE Tx queues - * @data: the adapter - * - * Runs periodically from a timer to perform maintenance of SGE TX queues. - * - * b) Reclaims completed Tx packets for the Ethernet queues. Normally - * packets are cleaned up by new Tx packets, this timer cleans up packets - * when no new packets are being submitted. This is essential for pktgen, - * at least. - */ -static void sge_tx_timer_cb(unsigned long data) -{ - struct adapter *adapter = (struct adapter *)data; - struct sge *s = &adapter->sge; - unsigned int i, budget; - - budget = MAX_TIMER_TX_RECLAIM; - i = s->ethtxq_rover; - do { - struct sge_eth_txq *txq = &s->ethtxq[i]; - - if (reclaimable(&txq->q) && __netif_tx_trylock(txq->txq)) { - int avail = reclaimable(&txq->q); - - if (avail > budget) - avail = budget; - - free_tx_desc(adapter, &txq->q, avail, true); - txq->q.in_use -= avail; - __netif_tx_unlock(txq->txq); - - budget -= avail; - if (!budget) - break; - } - - i++; - if (i >= s->ethqsets) - i = 0; - } while (i != s->ethtxq_rover); - s->ethtxq_rover = i; - - /* - * If we found too many reclaimable packets schedule a timer in the - * near future to continue where we left off. Otherwise the next timer - * will be at its normal interval. - */ - mod_timer(&s->tx_timer, jiffies + (budget ? TX_QCHECK_PERIOD : 2)); -} - -/** - * t4vf_sge_alloc_rxq - allocate an SGE RX Queue - * @adapter: the adapter - * @rspq: pointer to to the new rxq's Response Queue to be filled in - * @iqasynch: if 0, a normal rspq; if 1, an asynchronous event queue - * @dev: the network device associated with the new rspq - * @intr_dest: MSI-X vector index (overriden in MSI mode) - * @fl: pointer to the new rxq's Free List to be filled in - * @hnd: the interrupt handler to invoke for the rspq - */ -int t4vf_sge_alloc_rxq(struct adapter *adapter, struct sge_rspq *rspq, - bool iqasynch, struct net_device *dev, - int intr_dest, - struct sge_fl *fl, rspq_handler_t hnd) -{ - struct port_info *pi = netdev_priv(dev); - struct fw_iq_cmd cmd, rpl; - int ret, iqandst, flsz = 0; - - /* - * If we're using MSI interrupts and we're not initializing the - * Forwarded Interrupt Queue itself, then set up this queue for - * indirect interrupts to the Forwarded Interrupt Queue. Obviously - * the Forwarded Interrupt Queue must be set up before any other - * ingress queue ... - */ - if ((adapter->flags & USING_MSI) && rspq != &adapter->sge.intrq) { - iqandst = SGE_INTRDST_IQ; - intr_dest = adapter->sge.intrq.abs_id; - } else - iqandst = SGE_INTRDST_PCI; - - /* - * Allocate the hardware ring for the Response Queue. The size needs - * to be a multiple of 16 which includes the mandatory status entry - * (regardless of whether the Status Page capabilities are enabled or - * not). - */ - rspq->size = roundup(rspq->size, 16); - rspq->desc = alloc_ring(adapter->pdev_dev, rspq->size, rspq->iqe_len, - 0, &rspq->phys_addr, NULL, 0); - if (!rspq->desc) - return -ENOMEM; - - /* - * Fill in the Ingress Queue Command. Note: Ideally this code would - * be in t4vf_hw.c but there are so many parameters and dependencies - * on our Linux SGE state that we would end up having to pass tons of - * parameters. We'll have to think about how this might be migrated - * into OS-independent common code ... - */ - memset(&cmd, 0, sizeof(cmd)); - cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_IQ_CMD) | - FW_CMD_REQUEST | - FW_CMD_WRITE | - FW_CMD_EXEC); - cmd.alloc_to_len16 = cpu_to_be32(FW_IQ_CMD_ALLOC | - FW_IQ_CMD_IQSTART(1) | - FW_LEN16(cmd)); - cmd.type_to_iqandstindex = - cpu_to_be32(FW_IQ_CMD_TYPE(FW_IQ_TYPE_FL_INT_CAP) | - FW_IQ_CMD_IQASYNCH(iqasynch) | - FW_IQ_CMD_VIID(pi->viid) | - FW_IQ_CMD_IQANDST(iqandst) | - FW_IQ_CMD_IQANUS(1) | - FW_IQ_CMD_IQANUD(SGE_UPDATEDEL_INTR) | - FW_IQ_CMD_IQANDSTINDEX(intr_dest)); - cmd.iqdroprss_to_iqesize = - cpu_to_be16(FW_IQ_CMD_IQPCIECH(pi->port_id) | - FW_IQ_CMD_IQGTSMODE | - FW_IQ_CMD_IQINTCNTTHRESH(rspq->pktcnt_idx) | - FW_IQ_CMD_IQESIZE(ilog2(rspq->iqe_len) - 4)); - cmd.iqsize = cpu_to_be16(rspq->size); - cmd.iqaddr = cpu_to_be64(rspq->phys_addr); - - if (fl) { - /* - * Allocate the ring for the hardware free list (with space - * for its status page) along with the associated software - * descriptor ring. The free list size needs to be a multiple - * of the Egress Queue Unit. - */ - fl->size = roundup(fl->size, FL_PER_EQ_UNIT); - fl->desc = alloc_ring(adapter->pdev_dev, fl->size, - sizeof(__be64), sizeof(struct rx_sw_desc), - &fl->addr, &fl->sdesc, STAT_LEN); - if (!fl->desc) { - ret = -ENOMEM; - goto err; - } - - /* - * Calculate the size of the hardware free list ring plus - * Status Page (which the SGE will place after the end of the - * free list ring) in Egress Queue Units. - */ - flsz = (fl->size / FL_PER_EQ_UNIT + - STAT_LEN / EQ_UNIT); - - /* - * Fill in all the relevant firmware Ingress Queue Command - * fields for the free list. - */ - cmd.iqns_to_fl0congen = - cpu_to_be32( - FW_IQ_CMD_FL0HOSTFCMODE(SGE_HOSTFCMODE_NONE) | - FW_IQ_CMD_FL0PACKEN | - FW_IQ_CMD_FL0PADEN); - cmd.fl0dcaen_to_fl0cidxfthresh = - cpu_to_be16( - FW_IQ_CMD_FL0FBMIN(SGE_FETCHBURSTMIN_64B) | - FW_IQ_CMD_FL0FBMAX(SGE_FETCHBURSTMAX_512B)); - cmd.fl0size = cpu_to_be16(flsz); - cmd.fl0addr = cpu_to_be64(fl->addr); - } - - /* - * Issue the firmware Ingress Queue Command and extract the results if - * it completes successfully. - */ - ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); - if (ret) - goto err; - - netif_napi_add(dev, &rspq->napi, napi_rx_handler, 64); - rspq->cur_desc = rspq->desc; - rspq->cidx = 0; - rspq->gen = 1; - rspq->next_intr_params = rspq->intr_params; - rspq->cntxt_id = be16_to_cpu(rpl.iqid); - rspq->abs_id = be16_to_cpu(rpl.physiqid); - rspq->size--; /* subtract status entry */ - rspq->adapter = adapter; - rspq->netdev = dev; - rspq->handler = hnd; - - /* set offset to -1 to distinguish ingress queues without FL */ - rspq->offset = fl ? 0 : -1; - - if (fl) { - fl->cntxt_id = be16_to_cpu(rpl.fl0id); - fl->avail = 0; - fl->pend_cred = 0; - fl->pidx = 0; - fl->cidx = 0; - fl->alloc_failed = 0; - fl->large_alloc_failed = 0; - fl->starving = 0; - refill_fl(adapter, fl, fl_cap(fl), GFP_KERNEL); - } - - return 0; - -err: - /* - * An error occurred. Clean up our partial allocation state and - * return the error. - */ - if (rspq->desc) { - dma_free_coherent(adapter->pdev_dev, rspq->size * rspq->iqe_len, - rspq->desc, rspq->phys_addr); - rspq->desc = NULL; - } - if (fl && fl->desc) { - kfree(fl->sdesc); - fl->sdesc = NULL; - dma_free_coherent(adapter->pdev_dev, flsz * EQ_UNIT, - fl->desc, fl->addr); - fl->desc = NULL; - } - return ret; -} - -/** - * t4vf_sge_alloc_eth_txq - allocate an SGE Ethernet TX Queue - * @adapter: the adapter - * @txq: pointer to the new txq to be filled in - * @devq: the network TX queue associated with the new txq - * @iqid: the relative ingress queue ID to which events relating to - * the new txq should be directed - */ -int t4vf_sge_alloc_eth_txq(struct adapter *adapter, struct sge_eth_txq *txq, - struct net_device *dev, struct netdev_queue *devq, - unsigned int iqid) -{ - int ret, nentries; - struct fw_eq_eth_cmd cmd, rpl; - struct port_info *pi = netdev_priv(dev); - - /* - * Calculate the size of the hardware TX Queue (including the Status - * Page on the end of the TX Queue) in units of TX Descriptors. - */ - nentries = txq->q.size + STAT_LEN / sizeof(struct tx_desc); - - /* - * Allocate the hardware ring for the TX ring (with space for its - * status page) along with the associated software descriptor ring. - */ - txq->q.desc = alloc_ring(adapter->pdev_dev, txq->q.size, - sizeof(struct tx_desc), - sizeof(struct tx_sw_desc), - &txq->q.phys_addr, &txq->q.sdesc, STAT_LEN); - if (!txq->q.desc) - return -ENOMEM; - - /* - * Fill in the Egress Queue Command. Note: As with the direct use of - * the firmware Ingress Queue COmmand above in our RXQ allocation - * routine, ideally, this code would be in t4vf_hw.c. Again, we'll - * have to see if there's some reasonable way to parameterize it - * into the common code ... - */ - memset(&cmd, 0, sizeof(cmd)); - cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_EQ_ETH_CMD) | - FW_CMD_REQUEST | - FW_CMD_WRITE | - FW_CMD_EXEC); - cmd.alloc_to_len16 = cpu_to_be32(FW_EQ_ETH_CMD_ALLOC | - FW_EQ_ETH_CMD_EQSTART | - FW_LEN16(cmd)); - cmd.viid_pkd = cpu_to_be32(FW_EQ_ETH_CMD_VIID(pi->viid)); - cmd.fetchszm_to_iqid = - cpu_to_be32(FW_EQ_ETH_CMD_HOSTFCMODE(SGE_HOSTFCMODE_STPG) | - FW_EQ_ETH_CMD_PCIECHN(pi->port_id) | - FW_EQ_ETH_CMD_IQID(iqid)); - cmd.dcaen_to_eqsize = - cpu_to_be32(FW_EQ_ETH_CMD_FBMIN(SGE_FETCHBURSTMIN_64B) | - FW_EQ_ETH_CMD_FBMAX(SGE_FETCHBURSTMAX_512B) | - FW_EQ_ETH_CMD_CIDXFTHRESH(SGE_CIDXFLUSHTHRESH_32) | - FW_EQ_ETH_CMD_EQSIZE(nentries)); - cmd.eqaddr = cpu_to_be64(txq->q.phys_addr); - - /* - * Issue the firmware Egress Queue Command and extract the results if - * it completes successfully. - */ - ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); - if (ret) { - /* - * The girmware Ingress Queue Command failed for some reason. - * Free up our partial allocation state and return the error. - */ - kfree(txq->q.sdesc); - txq->q.sdesc = NULL; - dma_free_coherent(adapter->pdev_dev, - nentries * sizeof(struct tx_desc), - txq->q.desc, txq->q.phys_addr); - txq->q.desc = NULL; - return ret; - } - - txq->q.in_use = 0; - txq->q.cidx = 0; - txq->q.pidx = 0; - txq->q.stat = (void *)&txq->q.desc[txq->q.size]; - txq->q.cntxt_id = FW_EQ_ETH_CMD_EQID_GET(be32_to_cpu(rpl.eqid_pkd)); - txq->q.abs_id = - FW_EQ_ETH_CMD_PHYSEQID_GET(be32_to_cpu(rpl.physeqid_pkd)); - txq->txq = devq; - txq->tso = 0; - txq->tx_cso = 0; - txq->vlan_ins = 0; - txq->q.stops = 0; - txq->q.restarts = 0; - txq->mapping_err = 0; - return 0; -} - -/* - * Free the DMA map resources associated with a TX queue. - */ -static void free_txq(struct adapter *adapter, struct sge_txq *tq) -{ - dma_free_coherent(adapter->pdev_dev, - tq->size * sizeof(*tq->desc) + STAT_LEN, - tq->desc, tq->phys_addr); - tq->cntxt_id = 0; - tq->sdesc = NULL; - tq->desc = NULL; -} - -/* - * Free the resources associated with a response queue (possibly including a - * free list). - */ -static void free_rspq_fl(struct adapter *adapter, struct sge_rspq *rspq, - struct sge_fl *fl) -{ - unsigned int flid = fl ? fl->cntxt_id : 0xffff; - - t4vf_iq_free(adapter, FW_IQ_TYPE_FL_INT_CAP, - rspq->cntxt_id, flid, 0xffff); - dma_free_coherent(adapter->pdev_dev, (rspq->size + 1) * rspq->iqe_len, - rspq->desc, rspq->phys_addr); - netif_napi_del(&rspq->napi); - rspq->netdev = NULL; - rspq->cntxt_id = 0; - rspq->abs_id = 0; - rspq->desc = NULL; - - if (fl) { - free_rx_bufs(adapter, fl, fl->avail); - dma_free_coherent(adapter->pdev_dev, - fl->size * sizeof(*fl->desc) + STAT_LEN, - fl->desc, fl->addr); - kfree(fl->sdesc); - fl->sdesc = NULL; - fl->cntxt_id = 0; - fl->desc = NULL; - } -} - -/** - * t4vf_free_sge_resources - free SGE resources - * @adapter: the adapter - * - * Frees resources used by the SGE queue sets. - */ -void t4vf_free_sge_resources(struct adapter *adapter) -{ - struct sge *s = &adapter->sge; - struct sge_eth_rxq *rxq = s->ethrxq; - struct sge_eth_txq *txq = s->ethtxq; - struct sge_rspq *evtq = &s->fw_evtq; - struct sge_rspq *intrq = &s->intrq; - int qs; - - for (qs = 0; qs < adapter->sge.ethqsets; qs++, rxq++, txq++) { - if (rxq->rspq.desc) - free_rspq_fl(adapter, &rxq->rspq, &rxq->fl); - if (txq->q.desc) { - t4vf_eth_eq_free(adapter, txq->q.cntxt_id); - free_tx_desc(adapter, &txq->q, txq->q.in_use, true); - kfree(txq->q.sdesc); - free_txq(adapter, &txq->q); - } - } - if (evtq->desc) - free_rspq_fl(adapter, evtq, NULL); - if (intrq->desc) - free_rspq_fl(adapter, intrq, NULL); -} - -/** - * t4vf_sge_start - enable SGE operation - * @adapter: the adapter - * - * Start tasklets and timers associated with the DMA engine. - */ -void t4vf_sge_start(struct adapter *adapter) -{ - adapter->sge.ethtxq_rover = 0; - mod_timer(&adapter->sge.rx_timer, jiffies + RX_QCHECK_PERIOD); - mod_timer(&adapter->sge.tx_timer, jiffies + TX_QCHECK_PERIOD); -} - -/** - * t4vf_sge_stop - disable SGE operation - * @adapter: the adapter - * - * Stop tasklets and timers associated with the DMA engine. Note that - * this is effective only if measures have been taken to disable any HW - * events that may restart them. - */ -void t4vf_sge_stop(struct adapter *adapter) -{ - struct sge *s = &adapter->sge; - - if (s->rx_timer.function) - del_timer_sync(&s->rx_timer); - if (s->tx_timer.function) - del_timer_sync(&s->tx_timer); -} - -/** - * t4vf_sge_init - initialize SGE - * @adapter: the adapter - * - * Performs SGE initialization needed every time after a chip reset. - * We do not initialize any of the queue sets here, instead the driver - * top-level must request those individually. We also do not enable DMA - * here, that should be done after the queues have been set up. - */ -int t4vf_sge_init(struct adapter *adapter) -{ - struct sge_params *sge_params = &adapter->params.sge; - u32 fl0 = sge_params->sge_fl_buffer_size[0]; - u32 fl1 = sge_params->sge_fl_buffer_size[1]; - struct sge *s = &adapter->sge; - - /* - * Start by vetting the basic SGE parameters which have been set up by - * the Physical Function Driver. Ideally we should be able to deal - * with _any_ configuration. Practice is different ... - */ - if (fl0 != PAGE_SIZE || (fl1 != 0 && fl1 <= fl0)) { - dev_err(adapter->pdev_dev, "bad SGE FL buffer sizes [%d, %d]\n", - fl0, fl1); - return -EINVAL; - } - if ((sge_params->sge_control & RXPKTCPLMODE) == 0) { - dev_err(adapter->pdev_dev, "bad SGE CPL MODE\n"); - return -EINVAL; - } - - /* - * Now translate the adapter parameters into our internal forms. - */ - if (fl1) - FL_PG_ORDER = ilog2(fl1) - PAGE_SHIFT; - STAT_LEN = ((sge_params->sge_control & EGRSTATUSPAGESIZE) ? 128 : 64); - PKTSHIFT = PKTSHIFT_GET(sge_params->sge_control); - FL_ALIGN = 1 << (INGPADBOUNDARY_GET(sge_params->sge_control) + - SGE_INGPADBOUNDARY_SHIFT); - - /* - * Set up tasklet timers. - */ - setup_timer(&s->rx_timer, sge_rx_timer_cb, (unsigned long)adapter); - setup_timer(&s->tx_timer, sge_tx_timer_cb, (unsigned long)adapter); - - /* - * Initialize Forwarded Interrupt Queue lock. - */ - spin_lock_init(&s->intrq_lock); - - return 0; -} diff --git a/drivers/net/cxgb4vf/t4vf_common.h b/drivers/net/cxgb4vf/t4vf_common.h deleted file mode 100644 index a65c80aed1f2..000000000000 --- a/drivers/net/cxgb4vf/t4vf_common.h +++ /dev/null @@ -1,274 +0,0 @@ -/* - * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet - * driver for Linux. - * - * Copyright (c) 2009-2010 Chelsio Communications, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef __T4VF_COMMON_H__ -#define __T4VF_COMMON_H__ - -#include "../cxgb4/t4fw_api.h" - -/* - * The "len16" field of a Firmware Command Structure ... - */ -#define FW_LEN16(fw_struct) FW_CMD_LEN16(sizeof(fw_struct) / 16) - -/* - * Per-VF statistics. - */ -struct t4vf_port_stats { - /* - * TX statistics. - */ - u64 tx_bcast_bytes; /* broadcast */ - u64 tx_bcast_frames; - u64 tx_mcast_bytes; /* multicast */ - u64 tx_mcast_frames; - u64 tx_ucast_bytes; /* unicast */ - u64 tx_ucast_frames; - u64 tx_drop_frames; /* TX dropped frames */ - u64 tx_offload_bytes; /* offload */ - u64 tx_offload_frames; - - /* - * RX statistics. - */ - u64 rx_bcast_bytes; /* broadcast */ - u64 rx_bcast_frames; - u64 rx_mcast_bytes; /* multicast */ - u64 rx_mcast_frames; - u64 rx_ucast_bytes; - u64 rx_ucast_frames; /* unicast */ - - u64 rx_err_frames; /* RX error frames */ -}; - -/* - * Per-"port" (Virtual Interface) link configuration ... - */ -struct link_config { - unsigned int supported; /* link capabilities */ - unsigned int advertising; /* advertised capabilities */ - unsigned short requested_speed; /* speed user has requested */ - unsigned short speed; /* actual link speed */ - unsigned char requested_fc; /* flow control user has requested */ - unsigned char fc; /* actual link flow control */ - unsigned char autoneg; /* autonegotiating? */ - unsigned char link_ok; /* link up? */ -}; - -enum { - PAUSE_RX = 1 << 0, - PAUSE_TX = 1 << 1, - PAUSE_AUTONEG = 1 << 2 -}; - -/* - * General device parameters ... - */ -struct dev_params { - u32 fwrev; /* firmware version */ - u32 tprev; /* TP Microcode Version */ -}; - -/* - * Scatter Gather Engine parameters. These are almost all determined by the - * Physical Function Driver. We just need to grab them to see within which - * environment we're playing ... - */ -struct sge_params { - u32 sge_control; /* padding, boundaries, lengths, etc. */ - u32 sge_host_page_size; /* RDMA page sizes */ - u32 sge_queues_per_page; /* RDMA queues/page */ - u32 sge_user_mode_limits; /* limits for BAR2 user mode accesses */ - u32 sge_fl_buffer_size[16]; /* free list buffer sizes */ - u32 sge_ingress_rx_threshold; /* RX counter interrupt threshold[4] */ - u32 sge_timer_value_0_and_1; /* interrupt coalescing timer values */ - u32 sge_timer_value_2_and_3; - u32 sge_timer_value_4_and_5; -}; - -/* - * Vital Product Data parameters. - */ -struct vpd_params { - u32 cclk; /* Core Clock (KHz) */ -}; - -/* - * Global Receive Side Scaling (RSS) parameters in host-native format. - */ -struct rss_params { - unsigned int mode; /* RSS mode */ - union { - struct { - unsigned int synmapen:1; /* SYN Map Enable */ - unsigned int syn4tupenipv6:1; /* enable hashing 4-tuple IPv6 SYNs */ - unsigned int syn2tupenipv6:1; /* enable hashing 2-tuple IPv6 SYNs */ - unsigned int syn4tupenipv4:1; /* enable hashing 4-tuple IPv4 SYNs */ - unsigned int syn2tupenipv4:1; /* enable hashing 2-tuple IPv4 SYNs */ - unsigned int ofdmapen:1; /* Offload Map Enable */ - unsigned int tnlmapen:1; /* Tunnel Map Enable */ - unsigned int tnlalllookup:1; /* Tunnel All Lookup */ - unsigned int hashtoeplitz:1; /* use Toeplitz hash */ - } basicvirtual; - } u; -}; - -/* - * Virtual Interface RSS Configuration in host-native format. - */ -union rss_vi_config { - struct { - u16 defaultq; /* Ingress Queue ID for !tnlalllookup */ - unsigned int ip6fourtupen:1; /* hash 4-tuple IPv6 ingress packets */ - unsigned int ip6twotupen:1; /* hash 2-tuple IPv6 ingress packets */ - unsigned int ip4fourtupen:1; /* hash 4-tuple IPv4 ingress packets */ - unsigned int ip4twotupen:1; /* hash 2-tuple IPv4 ingress packets */ - int udpen; /* hash 4-tuple UDP ingress packets */ - } basicvirtual; -}; - -/* - * Maximum resources provisioned for a PCI VF. - */ -struct vf_resources { - unsigned int nvi; /* N virtual interfaces */ - unsigned int neq; /* N egress Qs */ - unsigned int nethctrl; /* N egress ETH or CTRL Qs */ - unsigned int niqflint; /* N ingress Qs/w free list(s) & intr */ - unsigned int niq; /* N ingress Qs */ - unsigned int tc; /* PCI-E traffic class */ - unsigned int pmask; /* port access rights mask */ - unsigned int nexactf; /* N exact MPS filters */ - unsigned int r_caps; /* read capabilities */ - unsigned int wx_caps; /* write/execute capabilities */ -}; - -/* - * Per-"adapter" (Virtual Function) parameters. - */ -struct adapter_params { - struct dev_params dev; /* general device parameters */ - struct sge_params sge; /* Scatter Gather Engine */ - struct vpd_params vpd; /* Vital Product Data */ - struct rss_params rss; /* Receive Side Scaling */ - struct vf_resources vfres; /* Virtual Function Resource limits */ - u8 nports; /* # of Ethernet "ports" */ -}; - -#include "adapter.h" - -#ifndef PCI_VENDOR_ID_CHELSIO -# define PCI_VENDOR_ID_CHELSIO 0x1425 -#endif - -#define for_each_port(adapter, iter) \ - for (iter = 0; iter < (adapter)->params.nports; iter++) - -static inline bool is_10g_port(const struct link_config *lc) -{ - return (lc->supported & SUPPORTED_10000baseT_Full) != 0; -} - -static inline unsigned int core_ticks_per_usec(const struct adapter *adapter) -{ - return adapter->params.vpd.cclk / 1000; -} - -static inline unsigned int us_to_core_ticks(const struct adapter *adapter, - unsigned int us) -{ - return (us * adapter->params.vpd.cclk) / 1000; -} - -static inline unsigned int core_ticks_to_us(const struct adapter *adapter, - unsigned int ticks) -{ - return (ticks * 1000) / adapter->params.vpd.cclk; -} - -int t4vf_wr_mbox_core(struct adapter *, const void *, int, void *, bool); - -static inline int t4vf_wr_mbox(struct adapter *adapter, const void *cmd, - int size, void *rpl) -{ - return t4vf_wr_mbox_core(adapter, cmd, size, rpl, true); -} - -static inline int t4vf_wr_mbox_ns(struct adapter *adapter, const void *cmd, - int size, void *rpl) -{ - return t4vf_wr_mbox_core(adapter, cmd, size, rpl, false); -} - -int __devinit t4vf_wait_dev_ready(struct adapter *); -int __devinit t4vf_port_init(struct adapter *, int); - -int t4vf_fw_reset(struct adapter *); -int t4vf_query_params(struct adapter *, unsigned int, const u32 *, u32 *); -int t4vf_set_params(struct adapter *, unsigned int, const u32 *, const u32 *); - -int t4vf_get_sge_params(struct adapter *); -int t4vf_get_vpd_params(struct adapter *); -int t4vf_get_dev_params(struct adapter *); -int t4vf_get_rss_glb_config(struct adapter *); -int t4vf_get_vfres(struct adapter *); - -int t4vf_read_rss_vi_config(struct adapter *, unsigned int, - union rss_vi_config *); -int t4vf_write_rss_vi_config(struct adapter *, unsigned int, - union rss_vi_config *); -int t4vf_config_rss_range(struct adapter *, unsigned int, int, int, - const u16 *, int); - -int t4vf_alloc_vi(struct adapter *, int); -int t4vf_free_vi(struct adapter *, int); -int t4vf_enable_vi(struct adapter *, unsigned int, bool, bool); -int t4vf_identify_port(struct adapter *, unsigned int, unsigned int); - -int t4vf_set_rxmode(struct adapter *, unsigned int, int, int, int, int, int, - bool); -int t4vf_alloc_mac_filt(struct adapter *, unsigned int, bool, unsigned int, - const u8 **, u16 *, u64 *, bool); -int t4vf_change_mac(struct adapter *, unsigned int, int, const u8 *, bool); -int t4vf_set_addr_hash(struct adapter *, unsigned int, bool, u64, bool); -int t4vf_get_port_stats(struct adapter *, int, struct t4vf_port_stats *); - -int t4vf_iq_free(struct adapter *, unsigned int, unsigned int, unsigned int, - unsigned int); -int t4vf_eth_eq_free(struct adapter *, unsigned int); - -int t4vf_handle_fw_rpl(struct adapter *, const __be64 *); - -#endif /* __T4VF_COMMON_H__ */ diff --git a/drivers/net/cxgb4vf/t4vf_defs.h b/drivers/net/cxgb4vf/t4vf_defs.h deleted file mode 100644 index c7b127d93767..000000000000 --- a/drivers/net/cxgb4vf/t4vf_defs.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet - * driver for Linux. - * - * Copyright (c) 2009-2010 Chelsio Communications, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef __T4VF_DEFS_H__ -#define __T4VF_DEFS_H__ - -#include "../cxgb4/t4_regs.h" - -/* - * The VF Register Map. - * - * The Scatter Gather Engine (SGE), Multiport Support module (MPS), PIO Local - * bus module (PL) and CPU Interface Module (CIM) components are mapped via - * the Slice to Module Map Table (see below) in the Physical Function Register - * Map. The Mail Box Data (MBDATA) range is mapped via the PCI-E Mailbox Base - * and Offset registers in the PF Register Map. The MBDATA base address is - * quite constrained as it determines the Mailbox Data addresses for both PFs - * and VFs, and therefore must fit in both the VF and PF Register Maps without - * overlapping other registers. - */ -#define T4VF_SGE_BASE_ADDR 0x0000 -#define T4VF_MPS_BASE_ADDR 0x0100 -#define T4VF_PL_BASE_ADDR 0x0200 -#define T4VF_MBDATA_BASE_ADDR 0x0240 -#define T4VF_CIM_BASE_ADDR 0x0300 - -#define T4VF_REGMAP_START 0x0000 -#define T4VF_REGMAP_SIZE 0x0400 - -/* - * There's no hardware limitation which requires that the addresses of the - * Mailbox Data in the fixed CIM PF map and the programmable VF map must - * match. However, it's a useful convention ... - */ -#if T4VF_MBDATA_BASE_ADDR != CIM_PF_MAILBOX_DATA -#error T4VF_MBDATA_BASE_ADDR must match CIM_PF_MAILBOX_DATA! -#endif - -/* - * Virtual Function "Slice to Module Map Table" definitions. - * - * This table allows us to map subsets of the various module register sets - * into the T4VF Register Map. Each table entry identifies the index of the - * module whose registers are being mapped, the offset within the module's - * register set that the mapping should start at, the limit of the mapping, - * and the offset within the T4VF Register Map to which the module's registers - * are being mapped. All addresses and qualtities are in terms of 32-bit - * words. The "limit" value is also in terms of 32-bit words and is equal to - * the last address mapped in the T4VF Register Map 1 (i.e. it's a "<=" - * relation rather than a "<"). - */ -#define T4VF_MOD_MAP(module, index, first, last) \ - T4VF_MOD_MAP_##module##_INDEX = (index), \ - T4VF_MOD_MAP_##module##_FIRST = (first), \ - T4VF_MOD_MAP_##module##_LAST = (last), \ - T4VF_MOD_MAP_##module##_OFFSET = ((first)/4), \ - T4VF_MOD_MAP_##module##_BASE = \ - (T4VF_##module##_BASE_ADDR/4 + (first)/4), \ - T4VF_MOD_MAP_##module##_LIMIT = \ - (T4VF_##module##_BASE_ADDR/4 + (last)/4), - -#define SGE_VF_KDOORBELL 0x0 -#define SGE_VF_GTS 0x4 -#define MPS_VF_CTL 0x0 -#define MPS_VF_STAT_RX_VF_ERR_FRAMES_H 0xfc -#define PL_VF_WHOAMI 0x0 -#define CIM_VF_EXT_MAILBOX_CTRL 0x0 -#define CIM_VF_EXT_MAILBOX_STATUS 0x4 - -enum { - T4VF_MOD_MAP(SGE, 2, SGE_VF_KDOORBELL, SGE_VF_GTS) - T4VF_MOD_MAP(MPS, 0, MPS_VF_CTL, MPS_VF_STAT_RX_VF_ERR_FRAMES_H) - T4VF_MOD_MAP(PL, 3, PL_VF_WHOAMI, PL_VF_WHOAMI) - T4VF_MOD_MAP(CIM, 1, CIM_VF_EXT_MAILBOX_CTRL, CIM_VF_EXT_MAILBOX_STATUS) -}; - -/* - * There isn't a Slice to Module Map Table entry for the Mailbox Data - * registers, but it's convenient to use similar names as above. There are 8 - * little-endian 64-bit Mailbox Data registers. Note that the "instances" - * value below is in terms of 32-bit words which matches the "word" addressing - * space we use above for the Slice to Module Map Space. - */ -#define NUM_CIM_VF_MAILBOX_DATA_INSTANCES 16 - -#define T4VF_MBDATA_FIRST 0 -#define T4VF_MBDATA_LAST ((NUM_CIM_VF_MAILBOX_DATA_INSTANCES-1)*4) - -#endif /* __T4T4VF_DEFS_H__ */ diff --git a/drivers/net/cxgb4vf/t4vf_hw.c b/drivers/net/cxgb4vf/t4vf_hw.c deleted file mode 100644 index fe3fd3dad6f7..000000000000 --- a/drivers/net/cxgb4vf/t4vf_hw.c +++ /dev/null @@ -1,1387 +0,0 @@ -/* - * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet - * driver for Linux. - * - * Copyright (c) 2009-2010 Chelsio Communications, Inc. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include - -#include "t4vf_common.h" -#include "t4vf_defs.h" - -#include "../cxgb4/t4_regs.h" -#include "../cxgb4/t4fw_api.h" - -/* - * Wait for the device to become ready (signified by our "who am I" register - * returning a value other than all 1's). Return an error if it doesn't - * become ready ... - */ -int __devinit t4vf_wait_dev_ready(struct adapter *adapter) -{ - const u32 whoami = T4VF_PL_BASE_ADDR + PL_VF_WHOAMI; - const u32 notready1 = 0xffffffff; - const u32 notready2 = 0xeeeeeeee; - u32 val; - - val = t4_read_reg(adapter, whoami); - if (val != notready1 && val != notready2) - return 0; - msleep(500); - val = t4_read_reg(adapter, whoami); - if (val != notready1 && val != notready2) - return 0; - else - return -EIO; -} - -/* - * Get the reply to a mailbox command and store it in @rpl in big-endian order - * (since the firmware data structures are specified in a big-endian layout). - */ -static void get_mbox_rpl(struct adapter *adapter, __be64 *rpl, int size, - u32 mbox_data) -{ - for ( ; size; size -= 8, mbox_data += 8) - *rpl++ = cpu_to_be64(t4_read_reg64(adapter, mbox_data)); -} - -/* - * Dump contents of mailbox with a leading tag. - */ -static void dump_mbox(struct adapter *adapter, const char *tag, u32 mbox_data) -{ - dev_err(adapter->pdev_dev, - "mbox %s: %llx %llx %llx %llx %llx %llx %llx %llx\n", tag, - (unsigned long long)t4_read_reg64(adapter, mbox_data + 0), - (unsigned long long)t4_read_reg64(adapter, mbox_data + 8), - (unsigned long long)t4_read_reg64(adapter, mbox_data + 16), - (unsigned long long)t4_read_reg64(adapter, mbox_data + 24), - (unsigned long long)t4_read_reg64(adapter, mbox_data + 32), - (unsigned long long)t4_read_reg64(adapter, mbox_data + 40), - (unsigned long long)t4_read_reg64(adapter, mbox_data + 48), - (unsigned long long)t4_read_reg64(adapter, mbox_data + 56)); -} - -/** - * t4vf_wr_mbox_core - send a command to FW through the mailbox - * @adapter: the adapter - * @cmd: the command to write - * @size: command length in bytes - * @rpl: where to optionally store the reply - * @sleep_ok: if true we may sleep while awaiting command completion - * - * Sends the given command to FW through the mailbox and waits for the - * FW to execute the command. If @rpl is not %NULL it is used to store - * the FW's reply to the command. The command and its optional reply - * are of the same length. FW can take up to 500 ms to respond. - * @sleep_ok determines whether we may sleep while awaiting the response. - * If sleeping is allowed we use progressive backoff otherwise we spin. - * - * The return value is 0 on success or a negative errno on failure. A - * failure can happen either because we are not able to execute the - * command or FW executes it but signals an error. In the latter case - * the return value is the error code indicated by FW (negated). - */ -int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size, - void *rpl, bool sleep_ok) -{ - static const int delay[] = { - 1, 1, 3, 5, 10, 10, 20, 50, 100 - }; - - u32 v; - int i, ms, delay_idx; - const __be64 *p; - u32 mbox_data = T4VF_MBDATA_BASE_ADDR; - u32 mbox_ctl = T4VF_CIM_BASE_ADDR + CIM_VF_EXT_MAILBOX_CTRL; - - /* - * Commands must be multiples of 16 bytes in length and may not be - * larger than the size of the Mailbox Data register array. - */ - if ((size % 16) != 0 || - size > NUM_CIM_VF_MAILBOX_DATA_INSTANCES * 4) - return -EINVAL; - - /* - * Loop trying to get ownership of the mailbox. Return an error - * if we can't gain ownership. - */ - v = MBOWNER_GET(t4_read_reg(adapter, mbox_ctl)); - for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++) - v = MBOWNER_GET(t4_read_reg(adapter, mbox_ctl)); - if (v != MBOX_OWNER_DRV) - return v == MBOX_OWNER_FW ? -EBUSY : -ETIMEDOUT; - - /* - * Write the command array into the Mailbox Data register array and - * transfer ownership of the mailbox to the firmware. - * - * For the VFs, the Mailbox Data "registers" are actually backed by - * T4's "MA" interface rather than PL Registers (as is the case for - * the PFs). Because these are in different coherency domains, the - * write to the VF's PL-register-backed Mailbox Control can race in - * front of the writes to the MA-backed VF Mailbox Data "registers". - * So we need to do a read-back on at least one byte of the VF Mailbox - * Data registers before doing the write to the VF Mailbox Control - * register. - */ - for (i = 0, p = cmd; i < size; i += 8) - t4_write_reg64(adapter, mbox_data + i, be64_to_cpu(*p++)); - t4_read_reg(adapter, mbox_data); /* flush write */ - - t4_write_reg(adapter, mbox_ctl, - MBMSGVALID | MBOWNER(MBOX_OWNER_FW)); - t4_read_reg(adapter, mbox_ctl); /* flush write */ - - /* - * Spin waiting for firmware to acknowledge processing our command. - */ - delay_idx = 0; - ms = delay[0]; - - for (i = 0; i < FW_CMD_MAX_TIMEOUT; i += ms) { - if (sleep_ok) { - ms = delay[delay_idx]; - if (delay_idx < ARRAY_SIZE(delay) - 1) - delay_idx++; - msleep(ms); - } else - mdelay(ms); - - /* - * If we're the owner, see if this is the reply we wanted. - */ - v = t4_read_reg(adapter, mbox_ctl); - if (MBOWNER_GET(v) == MBOX_OWNER_DRV) { - /* - * If the Message Valid bit isn't on, revoke ownership - * of the mailbox and continue waiting for our reply. - */ - if ((v & MBMSGVALID) == 0) { - t4_write_reg(adapter, mbox_ctl, - MBOWNER(MBOX_OWNER_NONE)); - continue; - } - - /* - * We now have our reply. Extract the command return - * value, copy the reply back to our caller's buffer - * (if specified) and revoke ownership of the mailbox. - * We return the (negated) firmware command return - * code (this depends on FW_SUCCESS == 0). - */ - - /* return value in low-order little-endian word */ - v = t4_read_reg(adapter, mbox_data); - if (FW_CMD_RETVAL_GET(v)) - dump_mbox(adapter, "FW Error", mbox_data); - - if (rpl) { - /* request bit in high-order BE word */ - WARN_ON((be32_to_cpu(*(const u32 *)cmd) - & FW_CMD_REQUEST) == 0); - get_mbox_rpl(adapter, rpl, size, mbox_data); - WARN_ON((be32_to_cpu(*(u32 *)rpl) - & FW_CMD_REQUEST) != 0); - } - t4_write_reg(adapter, mbox_ctl, - MBOWNER(MBOX_OWNER_NONE)); - return -FW_CMD_RETVAL_GET(v); - } - } - - /* - * We timed out. Return the error ... - */ - dump_mbox(adapter, "FW Timeout", mbox_data); - return -ETIMEDOUT; -} - -/** - * hash_mac_addr - return the hash value of a MAC address - * @addr: the 48-bit Ethernet MAC address - * - * Hashes a MAC address according to the hash function used by hardware - * inexact (hash) address matching. - */ -static int hash_mac_addr(const u8 *addr) -{ - u32 a = ((u32)addr[0] << 16) | ((u32)addr[1] << 8) | addr[2]; - u32 b = ((u32)addr[3] << 16) | ((u32)addr[4] << 8) | addr[5]; - a ^= b; - a ^= (a >> 12); - a ^= (a >> 6); - return a & 0x3f; -} - -/** - * init_link_config - initialize a link's SW state - * @lc: structure holding the link state - * @caps: link capabilities - * - * Initializes the SW state maintained for each link, including the link's - * capabilities and default speed/flow-control/autonegotiation settings. - */ -static void __devinit init_link_config(struct link_config *lc, - unsigned int caps) -{ - lc->supported = caps; - lc->requested_speed = 0; - lc->speed = 0; - lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX; - if (lc->supported & SUPPORTED_Autoneg) { - lc->advertising = lc->supported; - lc->autoneg = AUTONEG_ENABLE; - lc->requested_fc |= PAUSE_AUTONEG; - } else { - lc->advertising = 0; - lc->autoneg = AUTONEG_DISABLE; - } -} - -/** - * t4vf_port_init - initialize port hardware/software state - * @adapter: the adapter - * @pidx: the adapter port index - */ -int __devinit t4vf_port_init(struct adapter *adapter, int pidx) -{ - struct port_info *pi = adap2pinfo(adapter, pidx); - struct fw_vi_cmd vi_cmd, vi_rpl; - struct fw_port_cmd port_cmd, port_rpl; - int v; - u32 word; - - /* - * Execute a VI Read command to get our Virtual Interface information - * like MAC address, etc. - */ - memset(&vi_cmd, 0, sizeof(vi_cmd)); - vi_cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_VI_CMD) | - FW_CMD_REQUEST | - FW_CMD_READ); - vi_cmd.alloc_to_len16 = cpu_to_be32(FW_LEN16(vi_cmd)); - vi_cmd.type_viid = cpu_to_be16(FW_VI_CMD_VIID(pi->viid)); - v = t4vf_wr_mbox(adapter, &vi_cmd, sizeof(vi_cmd), &vi_rpl); - if (v) - return v; - - BUG_ON(pi->port_id != FW_VI_CMD_PORTID_GET(vi_rpl.portid_pkd)); - pi->rss_size = FW_VI_CMD_RSSSIZE_GET(be16_to_cpu(vi_rpl.rsssize_pkd)); - t4_os_set_hw_addr(adapter, pidx, vi_rpl.mac); - - /* - * If we don't have read access to our port information, we're done - * now. Otherwise, execute a PORT Read command to get it ... - */ - if (!(adapter->params.vfres.r_caps & FW_CMD_CAP_PORT)) - return 0; - - memset(&port_cmd, 0, sizeof(port_cmd)); - port_cmd.op_to_portid = cpu_to_be32(FW_CMD_OP(FW_PORT_CMD) | - FW_CMD_REQUEST | - FW_CMD_READ | - FW_PORT_CMD_PORTID(pi->port_id)); - port_cmd.action_to_len16 = - cpu_to_be32(FW_PORT_CMD_ACTION(FW_PORT_ACTION_GET_PORT_INFO) | - FW_LEN16(port_cmd)); - v = t4vf_wr_mbox(adapter, &port_cmd, sizeof(port_cmd), &port_rpl); - if (v) - return v; - - v = 0; - word = be16_to_cpu(port_rpl.u.info.pcap); - if (word & FW_PORT_CAP_SPEED_100M) - v |= SUPPORTED_100baseT_Full; - if (word & FW_PORT_CAP_SPEED_1G) - v |= SUPPORTED_1000baseT_Full; - if (word & FW_PORT_CAP_SPEED_10G) - v |= SUPPORTED_10000baseT_Full; - if (word & FW_PORT_CAP_ANEG) - v |= SUPPORTED_Autoneg; - init_link_config(&pi->link_cfg, v); - - return 0; -} - -/** - * t4vf_fw_reset - issue a reset to FW - * @adapter: the adapter - * - * Issues a reset command to FW. For a Physical Function this would - * result in the Firmware reseting all of its state. For a Virtual - * Function this just resets the state associated with the VF. - */ -int t4vf_fw_reset(struct adapter *adapter) -{ - struct fw_reset_cmd cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.op_to_write = cpu_to_be32(FW_CMD_OP(FW_RESET_CMD) | - FW_CMD_WRITE); - cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); - return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL); -} - -/** - * t4vf_query_params - query FW or device parameters - * @adapter: the adapter - * @nparams: the number of parameters - * @params: the parameter names - * @vals: the parameter values - * - * Reads the values of firmware or device parameters. Up to 7 parameters - * can be queried at once. - */ -int t4vf_query_params(struct adapter *adapter, unsigned int nparams, - const u32 *params, u32 *vals) -{ - int i, ret; - struct fw_params_cmd cmd, rpl; - struct fw_params_param *p; - size_t len16; - - if (nparams > 7) - return -EINVAL; - - memset(&cmd, 0, sizeof(cmd)); - cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_PARAMS_CMD) | - FW_CMD_REQUEST | - FW_CMD_READ); - len16 = DIV_ROUND_UP(offsetof(struct fw_params_cmd, - param[nparams].mnem), 16); - cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16(len16)); - for (i = 0, p = &cmd.param[0]; i < nparams; i++, p++) - p->mnem = htonl(*params++); - - ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); - if (ret == 0) - for (i = 0, p = &rpl.param[0]; i < nparams; i++, p++) - *vals++ = be32_to_cpu(p->val); - return ret; -} - -/** - * t4vf_set_params - sets FW or device parameters - * @adapter: the adapter - * @nparams: the number of parameters - * @params: the parameter names - * @vals: the parameter values - * - * Sets the values of firmware or device parameters. Up to 7 parameters - * can be specified at once. - */ -int t4vf_set_params(struct adapter *adapter, unsigned int nparams, - const u32 *params, const u32 *vals) -{ - int i; - struct fw_params_cmd cmd; - struct fw_params_param *p; - size_t len16; - - if (nparams > 7) - return -EINVAL; - - memset(&cmd, 0, sizeof(cmd)); - cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_PARAMS_CMD) | - FW_CMD_REQUEST | - FW_CMD_WRITE); - len16 = DIV_ROUND_UP(offsetof(struct fw_params_cmd, - param[nparams]), 16); - cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16(len16)); - for (i = 0, p = &cmd.param[0]; i < nparams; i++, p++) { - p->mnem = cpu_to_be32(*params++); - p->val = cpu_to_be32(*vals++); - } - - return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL); -} - -/** - * t4vf_get_sge_params - retrieve adapter Scatter gather Engine parameters - * @adapter: the adapter - * - * Retrieves various core SGE parameters in the form of hardware SGE - * register values. The caller is responsible for decoding these as - * needed. The SGE parameters are stored in @adapter->params.sge. - */ -int t4vf_get_sge_params(struct adapter *adapter) -{ - struct sge_params *sge_params = &adapter->params.sge; - u32 params[7], vals[7]; - int v; - - params[0] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) | - FW_PARAMS_PARAM_XYZ(SGE_CONTROL)); - params[1] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) | - FW_PARAMS_PARAM_XYZ(SGE_HOST_PAGE_SIZE)); - params[2] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) | - FW_PARAMS_PARAM_XYZ(SGE_FL_BUFFER_SIZE0)); - params[3] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) | - FW_PARAMS_PARAM_XYZ(SGE_FL_BUFFER_SIZE1)); - params[4] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) | - FW_PARAMS_PARAM_XYZ(SGE_TIMER_VALUE_0_AND_1)); - params[5] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) | - FW_PARAMS_PARAM_XYZ(SGE_TIMER_VALUE_2_AND_3)); - params[6] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) | - FW_PARAMS_PARAM_XYZ(SGE_TIMER_VALUE_4_AND_5)); - v = t4vf_query_params(adapter, 7, params, vals); - if (v) - return v; - sge_params->sge_control = vals[0]; - sge_params->sge_host_page_size = vals[1]; - sge_params->sge_fl_buffer_size[0] = vals[2]; - sge_params->sge_fl_buffer_size[1] = vals[3]; - sge_params->sge_timer_value_0_and_1 = vals[4]; - sge_params->sge_timer_value_2_and_3 = vals[5]; - sge_params->sge_timer_value_4_and_5 = vals[6]; - - params[0] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) | - FW_PARAMS_PARAM_XYZ(SGE_INGRESS_RX_THRESHOLD)); - v = t4vf_query_params(adapter, 1, params, vals); - if (v) - return v; - sge_params->sge_ingress_rx_threshold = vals[0]; - - return 0; -} - -/** - * t4vf_get_vpd_params - retrieve device VPD paremeters - * @adapter: the adapter - * - * Retrives various device Vital Product Data parameters. The parameters - * are stored in @adapter->params.vpd. - */ -int t4vf_get_vpd_params(struct adapter *adapter) -{ - struct vpd_params *vpd_params = &adapter->params.vpd; - u32 params[7], vals[7]; - int v; - - params[0] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | - FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_CCLK)); - v = t4vf_query_params(adapter, 1, params, vals); - if (v) - return v; - vpd_params->cclk = vals[0]; - - return 0; -} - -/** - * t4vf_get_dev_params - retrieve device paremeters - * @adapter: the adapter - * - * Retrives various device parameters. The parameters are stored in - * @adapter->params.dev. - */ -int t4vf_get_dev_params(struct adapter *adapter) -{ - struct dev_params *dev_params = &adapter->params.dev; - u32 params[7], vals[7]; - int v; - - params[0] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | - FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_FWREV)); - params[1] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | - FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_TPREV)); - v = t4vf_query_params(adapter, 2, params, vals); - if (v) - return v; - dev_params->fwrev = vals[0]; - dev_params->tprev = vals[1]; - - return 0; -} - -/** - * t4vf_get_rss_glb_config - retrieve adapter RSS Global Configuration - * @adapter: the adapter - * - * Retrieves global RSS mode and parameters with which we have to live - * and stores them in the @adapter's RSS parameters. - */ -int t4vf_get_rss_glb_config(struct adapter *adapter) -{ - struct rss_params *rss = &adapter->params.rss; - struct fw_rss_glb_config_cmd cmd, rpl; - int v; - - /* - * Execute an RSS Global Configuration read command to retrieve - * our RSS configuration. - */ - memset(&cmd, 0, sizeof(cmd)); - cmd.op_to_write = cpu_to_be32(FW_CMD_OP(FW_RSS_GLB_CONFIG_CMD) | - FW_CMD_REQUEST | - FW_CMD_READ); - cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); - v = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); - if (v) - return v; - - /* - * Transate the big-endian RSS Global Configuration into our - * cpu-endian format based on the RSS mode. We also do first level - * filtering at this point to weed out modes which don't support - * VF Drivers ... - */ - rss->mode = FW_RSS_GLB_CONFIG_CMD_MODE_GET( - be32_to_cpu(rpl.u.manual.mode_pkd)); - switch (rss->mode) { - case FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL: { - u32 word = be32_to_cpu( - rpl.u.basicvirtual.synmapen_to_hashtoeplitz); - - rss->u.basicvirtual.synmapen = - ((word & FW_RSS_GLB_CONFIG_CMD_SYNMAPEN) != 0); - rss->u.basicvirtual.syn4tupenipv6 = - ((word & FW_RSS_GLB_CONFIG_CMD_SYN4TUPENIPV6) != 0); - rss->u.basicvirtual.syn2tupenipv6 = - ((word & FW_RSS_GLB_CONFIG_CMD_SYN2TUPENIPV6) != 0); - rss->u.basicvirtual.syn4tupenipv4 = - ((word & FW_RSS_GLB_CONFIG_CMD_SYN4TUPENIPV4) != 0); - rss->u.basicvirtual.syn2tupenipv4 = - ((word & FW_RSS_GLB_CONFIG_CMD_SYN2TUPENIPV4) != 0); - - rss->u.basicvirtual.ofdmapen = - ((word & FW_RSS_GLB_CONFIG_CMD_OFDMAPEN) != 0); - - rss->u.basicvirtual.tnlmapen = - ((word & FW_RSS_GLB_CONFIG_CMD_TNLMAPEN) != 0); - rss->u.basicvirtual.tnlalllookup = - ((word & FW_RSS_GLB_CONFIG_CMD_TNLALLLKP) != 0); - - rss->u.basicvirtual.hashtoeplitz = - ((word & FW_RSS_GLB_CONFIG_CMD_HASHTOEPLITZ) != 0); - - /* we need at least Tunnel Map Enable to be set */ - if (!rss->u.basicvirtual.tnlmapen) - return -EINVAL; - break; - } - - default: - /* all unknown/unsupported RSS modes result in an error */ - return -EINVAL; - } - - return 0; -} - -/** - * t4vf_get_vfres - retrieve VF resource limits - * @adapter: the adapter - * - * Retrieves configured resource limits and capabilities for a virtual - * function. The results are stored in @adapter->vfres. - */ -int t4vf_get_vfres(struct adapter *adapter) -{ - struct vf_resources *vfres = &adapter->params.vfres; - struct fw_pfvf_cmd cmd, rpl; - int v; - u32 word; - - /* - * Execute PFVF Read command to get VF resource limits; bail out early - * with error on command failure. - */ - memset(&cmd, 0, sizeof(cmd)); - cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_PFVF_CMD) | - FW_CMD_REQUEST | - FW_CMD_READ); - cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); - v = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); - if (v) - return v; - - /* - * Extract VF resource limits and return success. - */ - word = be32_to_cpu(rpl.niqflint_niq); - vfres->niqflint = FW_PFVF_CMD_NIQFLINT_GET(word); - vfres->niq = FW_PFVF_CMD_NIQ_GET(word); - - word = be32_to_cpu(rpl.type_to_neq); - vfres->neq = FW_PFVF_CMD_NEQ_GET(word); - vfres->pmask = FW_PFVF_CMD_PMASK_GET(word); - - word = be32_to_cpu(rpl.tc_to_nexactf); - vfres->tc = FW_PFVF_CMD_TC_GET(word); - vfres->nvi = FW_PFVF_CMD_NVI_GET(word); - vfres->nexactf = FW_PFVF_CMD_NEXACTF_GET(word); - - word = be32_to_cpu(rpl.r_caps_to_nethctrl); - vfres->r_caps = FW_PFVF_CMD_R_CAPS_GET(word); - vfres->wx_caps = FW_PFVF_CMD_WX_CAPS_GET(word); - vfres->nethctrl = FW_PFVF_CMD_NETHCTRL_GET(word); - - return 0; -} - -/** - * t4vf_read_rss_vi_config - read a VI's RSS configuration - * @adapter: the adapter - * @viid: Virtual Interface ID - * @config: pointer to host-native VI RSS Configuration buffer - * - * Reads the Virtual Interface's RSS configuration information and - * translates it into CPU-native format. - */ -int t4vf_read_rss_vi_config(struct adapter *adapter, unsigned int viid, - union rss_vi_config *config) -{ - struct fw_rss_vi_config_cmd cmd, rpl; - int v; - - memset(&cmd, 0, sizeof(cmd)); - cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_RSS_VI_CONFIG_CMD) | - FW_CMD_REQUEST | - FW_CMD_READ | - FW_RSS_VI_CONFIG_CMD_VIID(viid)); - cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); - v = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); - if (v) - return v; - - switch (adapter->params.rss.mode) { - case FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL: { - u32 word = be32_to_cpu(rpl.u.basicvirtual.defaultq_to_udpen); - - config->basicvirtual.ip6fourtupen = - ((word & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN) != 0); - config->basicvirtual.ip6twotupen = - ((word & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN) != 0); - config->basicvirtual.ip4fourtupen = - ((word & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN) != 0); - config->basicvirtual.ip4twotupen = - ((word & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN) != 0); - config->basicvirtual.udpen = - ((word & FW_RSS_VI_CONFIG_CMD_UDPEN) != 0); - config->basicvirtual.defaultq = - FW_RSS_VI_CONFIG_CMD_DEFAULTQ_GET(word); - break; - } - - default: - return -EINVAL; - } - - return 0; -} - -/** - * t4vf_write_rss_vi_config - write a VI's RSS configuration - * @adapter: the adapter - * @viid: Virtual Interface ID - * @config: pointer to host-native VI RSS Configuration buffer - * - * Write the Virtual Interface's RSS configuration information - * (translating it into firmware-native format before writing). - */ -int t4vf_write_rss_vi_config(struct adapter *adapter, unsigned int viid, - union rss_vi_config *config) -{ - struct fw_rss_vi_config_cmd cmd, rpl; - - memset(&cmd, 0, sizeof(cmd)); - cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_RSS_VI_CONFIG_CMD) | - FW_CMD_REQUEST | - FW_CMD_WRITE | - FW_RSS_VI_CONFIG_CMD_VIID(viid)); - cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); - switch (adapter->params.rss.mode) { - case FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL: { - u32 word = 0; - - if (config->basicvirtual.ip6fourtupen) - word |= FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN; - if (config->basicvirtual.ip6twotupen) - word |= FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN; - if (config->basicvirtual.ip4fourtupen) - word |= FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN; - if (config->basicvirtual.ip4twotupen) - word |= FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN; - if (config->basicvirtual.udpen) - word |= FW_RSS_VI_CONFIG_CMD_UDPEN; - word |= FW_RSS_VI_CONFIG_CMD_DEFAULTQ( - config->basicvirtual.defaultq); - cmd.u.basicvirtual.defaultq_to_udpen = cpu_to_be32(word); - break; - } - - default: - return -EINVAL; - } - - return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); -} - -/** - * t4vf_config_rss_range - configure a portion of the RSS mapping table - * @adapter: the adapter - * @viid: Virtual Interface of RSS Table Slice - * @start: starting entry in the table to write - * @n: how many table entries to write - * @rspq: values for the "Response Queue" (Ingress Queue) lookup table - * @nrspq: number of values in @rspq - * - * Programs the selected part of the VI's RSS mapping table with the - * provided values. If @nrspq < @n the supplied values are used repeatedly - * until the full table range is populated. - * - * The caller must ensure the values in @rspq are in the range 0..1023. - */ -int t4vf_config_rss_range(struct adapter *adapter, unsigned int viid, - int start, int n, const u16 *rspq, int nrspq) -{ - const u16 *rsp = rspq; - const u16 *rsp_end = rspq+nrspq; - struct fw_rss_ind_tbl_cmd cmd; - - /* - * Initialize firmware command template to write the RSS table. - */ - memset(&cmd, 0, sizeof(cmd)); - cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_RSS_IND_TBL_CMD) | - FW_CMD_REQUEST | - FW_CMD_WRITE | - FW_RSS_IND_TBL_CMD_VIID(viid)); - cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); - - /* - * Each firmware RSS command can accommodate up to 32 RSS Ingress - * Queue Identifiers. These Ingress Queue IDs are packed three to - * a 32-bit word as 10-bit values with the upper remaining 2 bits - * reserved. - */ - while (n > 0) { - __be32 *qp = &cmd.iq0_to_iq2; - int nq = min(n, 32); - int ret; - - /* - * Set up the firmware RSS command header to send the next - * "nq" Ingress Queue IDs to the firmware. - */ - cmd.niqid = cpu_to_be16(nq); - cmd.startidx = cpu_to_be16(start); - - /* - * "nq" more done for the start of the next loop. - */ - start += nq; - n -= nq; - - /* - * While there are still Ingress Queue IDs to stuff into the - * current firmware RSS command, retrieve them from the - * Ingress Queue ID array and insert them into the command. - */ - while (nq > 0) { - /* - * Grab up to the next 3 Ingress Queue IDs (wrapping - * around the Ingress Queue ID array if necessary) and - * insert them into the firmware RSS command at the - * current 3-tuple position within the commad. - */ - u16 qbuf[3]; - u16 *qbp = qbuf; - int nqbuf = min(3, nq); - - nq -= nqbuf; - qbuf[0] = qbuf[1] = qbuf[2] = 0; - while (nqbuf) { - nqbuf--; - *qbp++ = *rsp++; - if (rsp >= rsp_end) - rsp = rspq; - } - *qp++ = cpu_to_be32(FW_RSS_IND_TBL_CMD_IQ0(qbuf[0]) | - FW_RSS_IND_TBL_CMD_IQ1(qbuf[1]) | - FW_RSS_IND_TBL_CMD_IQ2(qbuf[2])); - } - - /* - * Send this portion of the RRS table update to the firmware; - * bail out on any errors. - */ - ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL); - if (ret) - return ret; - } - return 0; -} - -/** - * t4vf_alloc_vi - allocate a virtual interface on a port - * @adapter: the adapter - * @port_id: physical port associated with the VI - * - * Allocate a new Virtual Interface and bind it to the indicated - * physical port. Return the new Virtual Interface Identifier on - * success, or a [negative] error number on failure. - */ -int t4vf_alloc_vi(struct adapter *adapter, int port_id) -{ - struct fw_vi_cmd cmd, rpl; - int v; - - /* - * Execute a VI command to allocate Virtual Interface and return its - * VIID. - */ - memset(&cmd, 0, sizeof(cmd)); - cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_VI_CMD) | - FW_CMD_REQUEST | - FW_CMD_WRITE | - FW_CMD_EXEC); - cmd.alloc_to_len16 = cpu_to_be32(FW_LEN16(cmd) | - FW_VI_CMD_ALLOC); - cmd.portid_pkd = FW_VI_CMD_PORTID(port_id); - v = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); - if (v) - return v; - - return FW_VI_CMD_VIID_GET(be16_to_cpu(rpl.type_viid)); -} - -/** - * t4vf_free_vi -- free a virtual interface - * @adapter: the adapter - * @viid: the virtual interface identifier - * - * Free a previously allocated Virtual Interface. Return an error on - * failure. - */ -int t4vf_free_vi(struct adapter *adapter, int viid) -{ - struct fw_vi_cmd cmd; - - /* - * Execute a VI command to free the Virtual Interface. - */ - memset(&cmd, 0, sizeof(cmd)); - cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_VI_CMD) | - FW_CMD_REQUEST | - FW_CMD_EXEC); - cmd.alloc_to_len16 = cpu_to_be32(FW_LEN16(cmd) | - FW_VI_CMD_FREE); - cmd.type_viid = cpu_to_be16(FW_VI_CMD_VIID(viid)); - return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL); -} - -/** - * t4vf_enable_vi - enable/disable a virtual interface - * @adapter: the adapter - * @viid: the Virtual Interface ID - * @rx_en: 1=enable Rx, 0=disable Rx - * @tx_en: 1=enable Tx, 0=disable Tx - * - * Enables/disables a virtual interface. - */ -int t4vf_enable_vi(struct adapter *adapter, unsigned int viid, - bool rx_en, bool tx_en) -{ - struct fw_vi_enable_cmd cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_ENABLE_CMD) | - FW_CMD_REQUEST | - FW_CMD_EXEC | - FW_VI_ENABLE_CMD_VIID(viid)); - cmd.ien_to_len16 = cpu_to_be32(FW_VI_ENABLE_CMD_IEN(rx_en) | - FW_VI_ENABLE_CMD_EEN(tx_en) | - FW_LEN16(cmd)); - return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL); -} - -/** - * t4vf_identify_port - identify a VI's port by blinking its LED - * @adapter: the adapter - * @viid: the Virtual Interface ID - * @nblinks: how many times to blink LED at 2.5 Hz - * - * Identifies a VI's port by blinking its LED. - */ -int t4vf_identify_port(struct adapter *adapter, unsigned int viid, - unsigned int nblinks) -{ - struct fw_vi_enable_cmd cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_ENABLE_CMD) | - FW_CMD_REQUEST | - FW_CMD_EXEC | - FW_VI_ENABLE_CMD_VIID(viid)); - cmd.ien_to_len16 = cpu_to_be32(FW_VI_ENABLE_CMD_LED | - FW_LEN16(cmd)); - cmd.blinkdur = cpu_to_be16(nblinks); - return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL); -} - -/** - * t4vf_set_rxmode - set Rx properties of a virtual interface - * @adapter: the adapter - * @viid: the VI id - * @mtu: the new MTU or -1 for no change - * @promisc: 1 to enable promiscuous mode, 0 to disable it, -1 no change - * @all_multi: 1 to enable all-multi mode, 0 to disable it, -1 no change - * @bcast: 1 to enable broadcast Rx, 0 to disable it, -1 no change - * @vlanex: 1 to enable hardware VLAN Tag extraction, 0 to disable it, - * -1 no change - * - * Sets Rx properties of a virtual interface. - */ -int t4vf_set_rxmode(struct adapter *adapter, unsigned int viid, - int mtu, int promisc, int all_multi, int bcast, int vlanex, - bool sleep_ok) -{ - struct fw_vi_rxmode_cmd cmd; - - /* convert to FW values */ - if (mtu < 0) - mtu = FW_VI_RXMODE_CMD_MTU_MASK; - if (promisc < 0) - promisc = FW_VI_RXMODE_CMD_PROMISCEN_MASK; - if (all_multi < 0) - all_multi = FW_VI_RXMODE_CMD_ALLMULTIEN_MASK; - if (bcast < 0) - bcast = FW_VI_RXMODE_CMD_BROADCASTEN_MASK; - if (vlanex < 0) - vlanex = FW_VI_RXMODE_CMD_VLANEXEN_MASK; - - memset(&cmd, 0, sizeof(cmd)); - cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_RXMODE_CMD) | - FW_CMD_REQUEST | - FW_CMD_WRITE | - FW_VI_RXMODE_CMD_VIID(viid)); - cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); - cmd.mtu_to_vlanexen = - cpu_to_be32(FW_VI_RXMODE_CMD_MTU(mtu) | - FW_VI_RXMODE_CMD_PROMISCEN(promisc) | - FW_VI_RXMODE_CMD_ALLMULTIEN(all_multi) | - FW_VI_RXMODE_CMD_BROADCASTEN(bcast) | - FW_VI_RXMODE_CMD_VLANEXEN(vlanex)); - return t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), NULL, sleep_ok); -} - -/** - * t4vf_alloc_mac_filt - allocates exact-match filters for MAC addresses - * @adapter: the adapter - * @viid: the Virtual Interface Identifier - * @free: if true any existing filters for this VI id are first removed - * @naddr: the number of MAC addresses to allocate filters for (up to 7) - * @addr: the MAC address(es) - * @idx: where to store the index of each allocated filter - * @hash: pointer to hash address filter bitmap - * @sleep_ok: call is allowed to sleep - * - * Allocates an exact-match filter for each of the supplied addresses and - * sets it to the corresponding address. If @idx is not %NULL it should - * have at least @naddr entries, each of which will be set to the index of - * the filter allocated for the corresponding MAC address. If a filter - * could not be allocated for an address its index is set to 0xffff. - * If @hash is not %NULL addresses that fail to allocate an exact filter - * are hashed and update the hash filter bitmap pointed at by @hash. - * - * Returns a negative error number or the number of filters allocated. - */ -int t4vf_alloc_mac_filt(struct adapter *adapter, unsigned int viid, bool free, - unsigned int naddr, const u8 **addr, u16 *idx, - u64 *hash, bool sleep_ok) -{ - int offset, ret = 0; - unsigned nfilters = 0; - unsigned int rem = naddr; - struct fw_vi_mac_cmd cmd, rpl; - - if (naddr > FW_CLS_TCAM_NUM_ENTRIES) - return -EINVAL; - - for (offset = 0; offset < naddr; /**/) { - unsigned int fw_naddr = (rem < ARRAY_SIZE(cmd.u.exact) - ? rem - : ARRAY_SIZE(cmd.u.exact)); - size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd, - u.exact[fw_naddr]), 16); - struct fw_vi_mac_exact *p; - int i; - - memset(&cmd, 0, sizeof(cmd)); - cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) | - FW_CMD_REQUEST | - FW_CMD_WRITE | - (free ? FW_CMD_EXEC : 0) | - FW_VI_MAC_CMD_VIID(viid)); - cmd.freemacs_to_len16 = - cpu_to_be32(FW_VI_MAC_CMD_FREEMACS(free) | - FW_CMD_LEN16(len16)); - - for (i = 0, p = cmd.u.exact; i < fw_naddr; i++, p++) { - p->valid_to_idx = cpu_to_be16( - FW_VI_MAC_CMD_VALID | - FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC)); - memcpy(p->macaddr, addr[offset+i], sizeof(p->macaddr)); - } - - - ret = t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), &rpl, - sleep_ok); - if (ret && ret != -ENOMEM) - break; - - for (i = 0, p = rpl.u.exact; i < fw_naddr; i++, p++) { - u16 index = FW_VI_MAC_CMD_IDX_GET( - be16_to_cpu(p->valid_to_idx)); - - if (idx) - idx[offset+i] = - (index >= FW_CLS_TCAM_NUM_ENTRIES - ? 0xffff - : index); - if (index < FW_CLS_TCAM_NUM_ENTRIES) - nfilters++; - else if (hash) - *hash |= (1ULL << hash_mac_addr(addr[offset+i])); - } - - free = false; - offset += fw_naddr; - rem -= fw_naddr; - } - - /* - * If there were no errors or we merely ran out of room in our MAC - * address arena, return the number of filters actually written. - */ - if (ret == 0 || ret == -ENOMEM) - ret = nfilters; - return ret; -} - -/** - * t4vf_change_mac - modifies the exact-match filter for a MAC address - * @adapter: the adapter - * @viid: the Virtual Interface ID - * @idx: index of existing filter for old value of MAC address, or -1 - * @addr: the new MAC address value - * @persist: if idx < 0, the new MAC allocation should be persistent - * - * Modifies an exact-match filter and sets it to the new MAC address. - * Note that in general it is not possible to modify the value of a given - * filter so the generic way to modify an address filter is to free the - * one being used by the old address value and allocate a new filter for - * the new address value. @idx can be -1 if the address is a new - * addition. - * - * Returns a negative error number or the index of the filter with the new - * MAC value. - */ -int t4vf_change_mac(struct adapter *adapter, unsigned int viid, - int idx, const u8 *addr, bool persist) -{ - int ret; - struct fw_vi_mac_cmd cmd, rpl; - struct fw_vi_mac_exact *p = &cmd.u.exact[0]; - size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd, - u.exact[1]), 16); - - /* - * If this is a new allocation, determine whether it should be - * persistent (across a "freemacs" operation) or not. - */ - if (idx < 0) - idx = persist ? FW_VI_MAC_ADD_PERSIST_MAC : FW_VI_MAC_ADD_MAC; - - memset(&cmd, 0, sizeof(cmd)); - cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) | - FW_CMD_REQUEST | - FW_CMD_WRITE | - FW_VI_MAC_CMD_VIID(viid)); - cmd.freemacs_to_len16 = cpu_to_be32(FW_CMD_LEN16(len16)); - p->valid_to_idx = cpu_to_be16(FW_VI_MAC_CMD_VALID | - FW_VI_MAC_CMD_IDX(idx)); - memcpy(p->macaddr, addr, sizeof(p->macaddr)); - - ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); - if (ret == 0) { - p = &rpl.u.exact[0]; - ret = FW_VI_MAC_CMD_IDX_GET(be16_to_cpu(p->valid_to_idx)); - if (ret >= FW_CLS_TCAM_NUM_ENTRIES) - ret = -ENOMEM; - } - return ret; -} - -/** - * t4vf_set_addr_hash - program the MAC inexact-match hash filter - * @adapter: the adapter - * @viid: the Virtual Interface Identifier - * @ucast: whether the hash filter should also match unicast addresses - * @vec: the value to be written to the hash filter - * @sleep_ok: call is allowed to sleep - * - * Sets the 64-bit inexact-match hash filter for a virtual interface. - */ -int t4vf_set_addr_hash(struct adapter *adapter, unsigned int viid, - bool ucast, u64 vec, bool sleep_ok) -{ - struct fw_vi_mac_cmd cmd; - size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd, - u.exact[0]), 16); - - memset(&cmd, 0, sizeof(cmd)); - cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) | - FW_CMD_REQUEST | - FW_CMD_WRITE | - FW_VI_ENABLE_CMD_VIID(viid)); - cmd.freemacs_to_len16 = cpu_to_be32(FW_VI_MAC_CMD_HASHVECEN | - FW_VI_MAC_CMD_HASHUNIEN(ucast) | - FW_CMD_LEN16(len16)); - cmd.u.hash.hashvec = cpu_to_be64(vec); - return t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), NULL, sleep_ok); -} - -/** - * t4vf_get_port_stats - collect "port" statistics - * @adapter: the adapter - * @pidx: the port index - * @s: the stats structure to fill - * - * Collect statistics for the "port"'s Virtual Interface. - */ -int t4vf_get_port_stats(struct adapter *adapter, int pidx, - struct t4vf_port_stats *s) -{ - struct port_info *pi = adap2pinfo(adapter, pidx); - struct fw_vi_stats_vf fwstats; - unsigned int rem = VI_VF_NUM_STATS; - __be64 *fwsp = (__be64 *)&fwstats; - - /* - * Grab the Virtual Interface statistics a chunk at a time via mailbox - * commands. We could use a Work Request and get all of them at once - * but that's an asynchronous interface which is awkward to use. - */ - while (rem) { - unsigned int ix = VI_VF_NUM_STATS - rem; - unsigned int nstats = min(6U, rem); - struct fw_vi_stats_cmd cmd, rpl; - size_t len = (offsetof(struct fw_vi_stats_cmd, u) + - sizeof(struct fw_vi_stats_ctl)); - size_t len16 = DIV_ROUND_UP(len, 16); - int ret; - - memset(&cmd, 0, sizeof(cmd)); - cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_STATS_CMD) | - FW_VI_STATS_CMD_VIID(pi->viid) | - FW_CMD_REQUEST | - FW_CMD_READ); - cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16(len16)); - cmd.u.ctl.nstats_ix = - cpu_to_be16(FW_VI_STATS_CMD_IX(ix) | - FW_VI_STATS_CMD_NSTATS(nstats)); - ret = t4vf_wr_mbox_ns(adapter, &cmd, len, &rpl); - if (ret) - return ret; - - memcpy(fwsp, &rpl.u.ctl.stat0, sizeof(__be64) * nstats); - - rem -= nstats; - fwsp += nstats; - } - - /* - * Translate firmware statistics into host native statistics. - */ - s->tx_bcast_bytes = be64_to_cpu(fwstats.tx_bcast_bytes); - s->tx_bcast_frames = be64_to_cpu(fwstats.tx_bcast_frames); - s->tx_mcast_bytes = be64_to_cpu(fwstats.tx_mcast_bytes); - s->tx_mcast_frames = be64_to_cpu(fwstats.tx_mcast_frames); - s->tx_ucast_bytes = be64_to_cpu(fwstats.tx_ucast_bytes); - s->tx_ucast_frames = be64_to_cpu(fwstats.tx_ucast_frames); - s->tx_drop_frames = be64_to_cpu(fwstats.tx_drop_frames); - s->tx_offload_bytes = be64_to_cpu(fwstats.tx_offload_bytes); - s->tx_offload_frames = be64_to_cpu(fwstats.tx_offload_frames); - - s->rx_bcast_bytes = be64_to_cpu(fwstats.rx_bcast_bytes); - s->rx_bcast_frames = be64_to_cpu(fwstats.rx_bcast_frames); - s->rx_mcast_bytes = be64_to_cpu(fwstats.rx_mcast_bytes); - s->rx_mcast_frames = be64_to_cpu(fwstats.rx_mcast_frames); - s->rx_ucast_bytes = be64_to_cpu(fwstats.rx_ucast_bytes); - s->rx_ucast_frames = be64_to_cpu(fwstats.rx_ucast_frames); - - s->rx_err_frames = be64_to_cpu(fwstats.rx_err_frames); - - return 0; -} - -/** - * t4vf_iq_free - free an ingress queue and its free lists - * @adapter: the adapter - * @iqtype: the ingress queue type (FW_IQ_TYPE_FL_INT_CAP, etc.) - * @iqid: ingress queue ID - * @fl0id: FL0 queue ID or 0xffff if no attached FL0 - * @fl1id: FL1 queue ID or 0xffff if no attached FL1 - * - * Frees an ingress queue and its associated free lists, if any. - */ -int t4vf_iq_free(struct adapter *adapter, unsigned int iqtype, - unsigned int iqid, unsigned int fl0id, unsigned int fl1id) -{ - struct fw_iq_cmd cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_IQ_CMD) | - FW_CMD_REQUEST | - FW_CMD_EXEC); - cmd.alloc_to_len16 = cpu_to_be32(FW_IQ_CMD_FREE | - FW_LEN16(cmd)); - cmd.type_to_iqandstindex = - cpu_to_be32(FW_IQ_CMD_TYPE(iqtype)); - - cmd.iqid = cpu_to_be16(iqid); - cmd.fl0id = cpu_to_be16(fl0id); - cmd.fl1id = cpu_to_be16(fl1id); - return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL); -} - -/** - * t4vf_eth_eq_free - free an Ethernet egress queue - * @adapter: the adapter - * @eqid: egress queue ID - * - * Frees an Ethernet egress queue. - */ -int t4vf_eth_eq_free(struct adapter *adapter, unsigned int eqid) -{ - struct fw_eq_eth_cmd cmd; - - memset(&cmd, 0, sizeof(cmd)); - cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_EQ_ETH_CMD) | - FW_CMD_REQUEST | - FW_CMD_EXEC); - cmd.alloc_to_len16 = cpu_to_be32(FW_EQ_ETH_CMD_FREE | - FW_LEN16(cmd)); - cmd.eqid_pkd = cpu_to_be32(FW_EQ_ETH_CMD_EQID(eqid)); - return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL); -} - -/** - * t4vf_handle_fw_rpl - process a firmware reply message - * @adapter: the adapter - * @rpl: start of the firmware message - * - * Processes a firmware message, such as link state change messages. - */ -int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl) -{ - const struct fw_cmd_hdr *cmd_hdr = (const struct fw_cmd_hdr *)rpl; - u8 opcode = FW_CMD_OP_GET(be32_to_cpu(cmd_hdr->hi)); - - switch (opcode) { - case FW_PORT_CMD: { - /* - * Link/module state change message. - */ - const struct fw_port_cmd *port_cmd = - (const struct fw_port_cmd *)rpl; - u32 word; - int action, port_id, link_ok, speed, fc, pidx; - - /* - * Extract various fields from port status change message. - */ - action = FW_PORT_CMD_ACTION_GET( - be32_to_cpu(port_cmd->action_to_len16)); - if (action != FW_PORT_ACTION_GET_PORT_INFO) { - dev_err(adapter->pdev_dev, - "Unknown firmware PORT reply action %x\n", - action); - break; - } - - port_id = FW_PORT_CMD_PORTID_GET( - be32_to_cpu(port_cmd->op_to_portid)); - - word = be32_to_cpu(port_cmd->u.info.lstatus_to_modtype); - link_ok = (word & FW_PORT_CMD_LSTATUS) != 0; - speed = 0; - fc = 0; - if (word & FW_PORT_CMD_RXPAUSE) - fc |= PAUSE_RX; - if (word & FW_PORT_CMD_TXPAUSE) - fc |= PAUSE_TX; - if (word & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100M)) - speed = SPEED_100; - else if (word & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_1G)) - speed = SPEED_1000; - else if (word & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_10G)) - speed = SPEED_10000; - - /* - * Scan all of our "ports" (Virtual Interfaces) looking for - * those bound to the physical port which has changed. If - * our recorded state doesn't match the current state, - * signal that change to the OS code. - */ - for_each_port(adapter, pidx) { - struct port_info *pi = adap2pinfo(adapter, pidx); - struct link_config *lc; - - if (pi->port_id != port_id) - continue; - - lc = &pi->link_cfg; - if (link_ok != lc->link_ok || speed != lc->speed || - fc != lc->fc) { - /* something changed */ - lc->link_ok = link_ok; - lc->speed = speed; - lc->fc = fc; - t4vf_os_link_changed(adapter, pidx, link_ok); - } - } - break; - } - - default: - dev_err(adapter->pdev_dev, "Unknown firmware reply %X\n", - opcode); - } - return 0; -} diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index 772fb49b4b3f..69d6403ec4bd 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -15,5 +15,6 @@ source "drivers/net/ethernet/3com/Kconfig" source "drivers/net/ethernet/8390/Kconfig" source "drivers/net/ethernet/amd/Kconfig" source "drivers/net/ethernet/broadcom/Kconfig" +source "drivers/net/ethernet/chelsio/Kconfig" endif # ETHERNET diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index 3ef49a2bae06..470e5d843013 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_NET_VENDOR_3COM) += 3com/ obj-$(CONFIG_NET_VENDOR_8390) += 8390/ obj-$(CONFIG_NET_VENDOR_AMD) += amd/ obj-$(CONFIG_NET_VENDOR_BROADCOM) += broadcom/ +obj-$(CONFIG_NET_VENDOR_CHELSIO) += chelsio/ diff --git a/drivers/net/ethernet/chelsio/Kconfig b/drivers/net/ethernet/chelsio/Kconfig new file mode 100644 index 000000000000..7b54574107ce --- /dev/null +++ b/drivers/net/ethernet/chelsio/Kconfig @@ -0,0 +1,106 @@ +# +# Chelsio device configuration +# + +config NET_VENDOR_CHELSIO + bool "Chelsio devices" + depends on PCI || INET + ---help--- + If you have a network (Ethernet) card belonging to this class, say Y + and read the Ethernet-HOWTO, available from + . + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about Chelsio devices. If you say Y, you will be asked for + your specific card in the following questions. + +if NET_VENDOR_CHELSIO + +config CHELSIO_T1 + tristate "Chelsio 10Gb Ethernet support" + depends on PCI + select CRC32 + select MDIO + ---help--- + This driver supports Chelsio gigabit and 10-gigabit + Ethernet cards. More information about adapter features and + performance tuning is in . + + For general information about Chelsio and our products, visit + our website at . + + For customer support, please visit our customer support page at + . + + Please send feedback to . + + To compile this driver as a module, choose M here: the module + will be called cxgb. + +config CHELSIO_T1_1G + bool "Chelsio gigabit Ethernet support" + depends on CHELSIO_T1 + ---help--- + Enables support for Chelsio's gigabit Ethernet PCI cards. If you + are using only 10G cards say 'N' here. + +config CHELSIO_T3 + tristate "Chelsio Communications T3 10Gb Ethernet support" + depends on PCI && INET + select FW_LOADER + select MDIO + ---help--- + This driver supports Chelsio T3-based gigabit and 10Gb Ethernet + adapters. + + For general information about Chelsio and our products, visit + our website at . + + For customer support, please visit our customer support page at + . + + Please send feedback to . + + To compile this driver as a module, choose M here: the module + will be called cxgb3. + +config CHELSIO_T4 + tristate "Chelsio Communications T4 Ethernet support" + depends on PCI + select FW_LOADER + select MDIO + ---help--- + This driver supports Chelsio T4-based gigabit and 10Gb Ethernet + adapters. + + For general information about Chelsio and our products, visit + our website at . + + For customer support, please visit our customer support page at + . + + Please send feedback to . + + To compile this driver as a module choose M here; the module + will be called cxgb4. + +config CHELSIO_T4VF + tristate "Chelsio Communications T4 Virtual Function Ethernet support" + depends on PCI + ---help--- + This driver supports Chelsio T4-based gigabit and 10Gb Ethernet + adapters with PCI-E SR-IOV Virtual Functions. + + For general information about Chelsio and our products, visit + our website at . + + For customer support, please visit our customer support page at + . + + Please send feedback to . + + To compile this driver as a module choose M here; the module + will be called cxgb4vf. + +endif # NET_VENDOR_CHELSIO diff --git a/drivers/net/ethernet/chelsio/Makefile b/drivers/net/ethernet/chelsio/Makefile new file mode 100644 index 000000000000..390510b5e90f --- /dev/null +++ b/drivers/net/ethernet/chelsio/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the Chelsio network device drivers. +# + +obj-$(CONFIG_CHELSIO_T1) += cxgb/ +obj-$(CONFIG_CHELSIO_T3) += cxgb3/ +obj-$(CONFIG_CHELSIO_T4) += cxgb4/ +obj-$(CONFIG_CHELSIO_T4VF) += cxgb4vf/ diff --git a/drivers/net/ethernet/chelsio/cxgb/Makefile b/drivers/net/ethernet/chelsio/cxgb/Makefile new file mode 100644 index 000000000000..57a4b262fd3f --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb/Makefile @@ -0,0 +1,9 @@ +# +# Chelsio T1 driver +# + +obj-$(CONFIG_CHELSIO_T1) += cxgb.o + +cxgb-$(CONFIG_CHELSIO_T1_1G) += mv88e1xxx.o vsc7326.o +cxgb-objs := cxgb2.o espi.o tp.o pm3393.o sge.o subr.o \ + mv88x201x.o my3126.o $(cxgb-y) diff --git a/drivers/net/ethernet/chelsio/cxgb/common.h b/drivers/net/ethernet/chelsio/cxgb/common.h new file mode 100644 index 000000000000..5ccbed1784d2 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb/common.h @@ -0,0 +1,353 @@ +/***************************************************************************** + * * + * File: common.h * + * $Revision: 1.21 $ * + * $Date: 2005/06/22 00:43:25 $ * + * Description: * + * part of the Chelsio 10Gb Ethernet Driver. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License, version 2, as * + * published by the Free Software Foundation. * + * * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * + * * + * http://www.chelsio.com * + * * + * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * + * All rights reserved. * + * * + * Maintainers: maintainers@chelsio.com * + * * + * Authors: Dimitrios Michailidis * + * Tina Yang * + * Felix Marti * + * Scott Bardone * + * Kurt Ottaway * + * Frank DiMambro * + * * + * History: * + * * + ****************************************************************************/ + +#define pr_fmt(fmt) "cxgb: " fmt + +#ifndef _CXGB_COMMON_H_ +#define _CXGB_COMMON_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_DESCRIPTION "Chelsio 10Gb Ethernet Driver" +#define DRV_NAME "cxgb" +#define DRV_VERSION "2.2" + +#define CH_DEVICE(devid, ssid, idx) \ + { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, ssid, 0, 0, idx } + +#define SUPPORTED_PAUSE (1 << 13) +#define SUPPORTED_LOOPBACK (1 << 15) + +#define ADVERTISED_PAUSE (1 << 13) +#define ADVERTISED_ASYM_PAUSE (1 << 14) + +typedef struct adapter adapter_t; + +struct t1_rx_mode { + struct net_device *dev; +}; + +#define t1_rx_mode_promisc(rm) (rm->dev->flags & IFF_PROMISC) +#define t1_rx_mode_allmulti(rm) (rm->dev->flags & IFF_ALLMULTI) +#define t1_rx_mode_mc_cnt(rm) (netdev_mc_count(rm->dev)) +#define t1_get_netdev(rm) (rm->dev) + +#define MAX_NPORTS 4 +#define PORT_MASK ((1 << MAX_NPORTS) - 1) +#define NMTUS 8 +#define TCB_SIZE 128 + +#define SPEED_INVALID 0xffff +#define DUPLEX_INVALID 0xff + +enum { + CHBT_BOARD_N110, + CHBT_BOARD_N210, + CHBT_BOARD_7500, + CHBT_BOARD_8000, + CHBT_BOARD_CHT101, + CHBT_BOARD_CHT110, + CHBT_BOARD_CHT210, + CHBT_BOARD_CHT204, + CHBT_BOARD_CHT204V, + CHBT_BOARD_CHT204E, + CHBT_BOARD_CHN204, + CHBT_BOARD_COUGAR, + CHBT_BOARD_6800, + CHBT_BOARD_SIMUL, +}; + +enum { + CHBT_TERM_FPGA, + CHBT_TERM_T1, + CHBT_TERM_T2, + CHBT_TERM_T3 +}; + +enum { + CHBT_MAC_CHELSIO_A, + CHBT_MAC_IXF1010, + CHBT_MAC_PM3393, + CHBT_MAC_VSC7321, + CHBT_MAC_DUMMY +}; + +enum { + CHBT_PHY_88E1041, + CHBT_PHY_88E1111, + CHBT_PHY_88X2010, + CHBT_PHY_XPAK, + CHBT_PHY_MY3126, + CHBT_PHY_8244, + CHBT_PHY_DUMMY +}; + +enum { + PAUSE_RX = 1 << 0, + PAUSE_TX = 1 << 1, + PAUSE_AUTONEG = 1 << 2 +}; + +/* Revisions of T1 chip */ +enum { + TERM_T1A = 0, + TERM_T1B = 1, + TERM_T2 = 3 +}; + +struct sge_params { + unsigned int cmdQ_size[2]; + unsigned int freelQ_size[2]; + unsigned int large_buf_capacity; + unsigned int rx_coalesce_usecs; + unsigned int last_rx_coalesce_raw; + unsigned int default_rx_coalesce_usecs; + unsigned int sample_interval_usecs; + unsigned int coalesce_enable; + unsigned int polling; +}; + +struct chelsio_pci_params { + unsigned short speed; + unsigned char width; + unsigned char is_pcix; +}; + +struct tp_params { + unsigned int pm_size; + unsigned int cm_size; + unsigned int pm_rx_base; + unsigned int pm_tx_base; + unsigned int pm_rx_pg_size; + unsigned int pm_tx_pg_size; + unsigned int pm_rx_num_pgs; + unsigned int pm_tx_num_pgs; + unsigned int rx_coalescing_size; + unsigned int use_5tuple_mode; +}; + +struct mc5_params { + unsigned int mode; /* selects MC5 width */ + unsigned int nservers; /* size of server region */ + unsigned int nroutes; /* size of routing region */ +}; + +/* Default MC5 region sizes */ +#define DEFAULT_SERVER_REGION_LEN 256 +#define DEFAULT_RT_REGION_LEN 1024 + +struct adapter_params { + struct sge_params sge; + struct mc5_params mc5; + struct tp_params tp; + struct chelsio_pci_params pci; + + const struct board_info *brd_info; + + unsigned short mtus[NMTUS]; + unsigned int nports; /* # of ethernet ports */ + unsigned int stats_update_period; + unsigned short chip_revision; + unsigned char chip_version; + unsigned char is_asic; + unsigned char has_msi; +}; + +struct link_config { + unsigned int supported; /* link capabilities */ + unsigned int advertising; /* advertised capabilities */ + unsigned short requested_speed; /* speed user has requested */ + unsigned short speed; /* actual link speed */ + unsigned char requested_duplex; /* duplex user has requested */ + unsigned char duplex; /* actual link duplex */ + unsigned char requested_fc; /* flow control user has requested */ + unsigned char fc; /* actual link flow control */ + unsigned char autoneg; /* autonegotiating? */ +}; + +struct cmac; +struct cphy; + +struct port_info { + struct net_device *dev; + struct cmac *mac; + struct cphy *phy; + struct link_config link_config; + struct net_device_stats netstats; +}; + +struct sge; +struct peespi; + +struct adapter { + u8 __iomem *regs; + struct pci_dev *pdev; + unsigned long registered_device_map; + unsigned long open_device_map; + unsigned long flags; + + const char *name; + int msg_enable; + u32 mmio_len; + + struct work_struct ext_intr_handler_task; + struct adapter_params params; + + /* Terminator modules. */ + struct sge *sge; + struct peespi *espi; + struct petp *tp; + + struct napi_struct napi; + struct port_info port[MAX_NPORTS]; + struct delayed_work stats_update_task; + struct timer_list stats_update_timer; + + spinlock_t tpi_lock; + spinlock_t work_lock; + spinlock_t mac_lock; + + /* guards async operations */ + spinlock_t async_lock ____cacheline_aligned; + u32 slow_intr_mask; + int t1powersave; +}; + +enum { /* adapter flags */ + FULL_INIT_DONE = 1 << 0, +}; + +struct mdio_ops; +struct gmac; +struct gphy; + +struct board_info { + unsigned char board; + unsigned char port_number; + unsigned long caps; + unsigned char chip_term; + unsigned char chip_mac; + unsigned char chip_phy; + unsigned int clock_core; + unsigned int clock_mc3; + unsigned int clock_mc4; + unsigned int espi_nports; + unsigned int clock_elmer0; + unsigned char mdio_mdien; + unsigned char mdio_mdiinv; + unsigned char mdio_mdc; + unsigned char mdio_phybaseaddr; + const struct gmac *gmac; + const struct gphy *gphy; + const struct mdio_ops *mdio_ops; + const char *desc; +}; + +static inline int t1_is_asic(const adapter_t *adapter) +{ + return adapter->params.is_asic; +} + +extern const struct pci_device_id t1_pci_tbl[]; + +static inline int adapter_matches_type(const adapter_t *adapter, + int version, int revision) +{ + return adapter->params.chip_version == version && + adapter->params.chip_revision == revision; +} + +#define t1_is_T1B(adap) adapter_matches_type(adap, CHBT_TERM_T1, TERM_T1B) +#define is_T2(adap) adapter_matches_type(adap, CHBT_TERM_T2, TERM_T2) + +/* Returns true if an adapter supports VLAN acceleration and TSO */ +static inline int vlan_tso_capable(const adapter_t *adapter) +{ + return !t1_is_T1B(adapter); +} + +#define for_each_port(adapter, iter) \ + for (iter = 0; iter < (adapter)->params.nports; ++iter) + +#define board_info(adapter) ((adapter)->params.brd_info) +#define is_10G(adapter) (board_info(adapter)->caps & SUPPORTED_10000baseT_Full) + +static inline unsigned int core_ticks_per_usec(const adapter_t *adap) +{ + return board_info(adap)->clock_core / 1000000; +} + +extern int __t1_tpi_read(adapter_t *adapter, u32 addr, u32 *valp); +extern int __t1_tpi_write(adapter_t *adapter, u32 addr, u32 value); +extern int t1_tpi_write(adapter_t *adapter, u32 addr, u32 value); +extern int t1_tpi_read(adapter_t *adapter, u32 addr, u32 *value); + +extern void t1_interrupts_enable(adapter_t *adapter); +extern void t1_interrupts_disable(adapter_t *adapter); +extern void t1_interrupts_clear(adapter_t *adapter); +extern int t1_elmer0_ext_intr_handler(adapter_t *adapter); +extern void t1_elmer0_ext_intr(adapter_t *adapter); +extern int t1_slow_intr_handler(adapter_t *adapter); + +extern int t1_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc); +extern const struct board_info *t1_get_board_info(unsigned int board_id); +extern const struct board_info *t1_get_board_info_from_ids(unsigned int devid, + unsigned short ssid); +extern int t1_seeprom_read(adapter_t *adapter, u32 addr, __le32 *data); +extern int t1_get_board_rev(adapter_t *adapter, const struct board_info *bi, + struct adapter_params *p); +extern int t1_init_hw_modules(adapter_t *adapter); +extern int t1_init_sw_modules(adapter_t *adapter, const struct board_info *bi); +extern void t1_free_sw_modules(adapter_t *adapter); +extern void t1_fatal_err(adapter_t *adapter); +extern void t1_link_changed(adapter_t *adapter, int port_id); +extern void t1_link_negotiated(adapter_t *adapter, int port_id, int link_stat, + int speed, int duplex, int pause); +#endif /* _CXGB_COMMON_H_ */ diff --git a/drivers/net/ethernet/chelsio/cxgb/cphy.h b/drivers/net/ethernet/chelsio/cxgb/cphy.h new file mode 100644 index 000000000000..1f095a9fc739 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb/cphy.h @@ -0,0 +1,175 @@ +/***************************************************************************** + * * + * File: cphy.h * + * $Revision: 1.7 $ * + * $Date: 2005/06/21 18:29:47 $ * + * Description: * + * part of the Chelsio 10Gb Ethernet Driver. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License, version 2, as * + * published by the Free Software Foundation. * + * * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * + * * + * http://www.chelsio.com * + * * + * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * + * All rights reserved. * + * * + * Maintainers: maintainers@chelsio.com * + * * + * Authors: Dimitrios Michailidis * + * Tina Yang * + * Felix Marti * + * Scott Bardone * + * Kurt Ottaway * + * Frank DiMambro * + * * + * History: * + * * + ****************************************************************************/ + +#ifndef _CXGB_CPHY_H_ +#define _CXGB_CPHY_H_ + +#include "common.h" + +struct mdio_ops { + void (*init)(adapter_t *adapter, const struct board_info *bi); + int (*read)(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr); + int (*write)(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr, u16 val); + unsigned mode_support; +}; + +/* PHY interrupt types */ +enum { + cphy_cause_link_change = 0x1, + cphy_cause_error = 0x2, + cphy_cause_fifo_error = 0x3 +}; + +enum { + PHY_LINK_UP = 0x1, + PHY_AUTONEG_RDY = 0x2, + PHY_AUTONEG_EN = 0x4 +}; + +struct cphy; + +/* PHY operations */ +struct cphy_ops { + void (*destroy)(struct cphy *); + int (*reset)(struct cphy *, int wait); + + int (*interrupt_enable)(struct cphy *); + int (*interrupt_disable)(struct cphy *); + int (*interrupt_clear)(struct cphy *); + int (*interrupt_handler)(struct cphy *); + + int (*autoneg_enable)(struct cphy *); + int (*autoneg_disable)(struct cphy *); + int (*autoneg_restart)(struct cphy *); + + int (*advertise)(struct cphy *phy, unsigned int advertise_map); + int (*set_loopback)(struct cphy *, int on); + int (*set_speed_duplex)(struct cphy *phy, int speed, int duplex); + int (*get_link_status)(struct cphy *phy, int *link_ok, int *speed, + int *duplex, int *fc); + + u32 mmds; +}; + +/* A PHY instance */ +struct cphy { + int state; /* Link status state machine */ + adapter_t *adapter; /* associated adapter */ + + struct delayed_work phy_update; + + u16 bmsr; + int count; + int act_count; + int act_on; + + u32 elmer_gpo; + + const struct cphy_ops *ops; /* PHY operations */ + struct mdio_if_info mdio; + struct cphy_instance *instance; +}; + +/* Convenience MDIO read/write wrappers */ +static inline int cphy_mdio_read(struct cphy *cphy, int mmd, int reg, + unsigned int *valp) +{ + int rc = cphy->mdio.mdio_read(cphy->mdio.dev, cphy->mdio.prtad, mmd, + reg); + *valp = (rc >= 0) ? rc : -1; + return (rc >= 0) ? 0 : rc; +} + +static inline int cphy_mdio_write(struct cphy *cphy, int mmd, int reg, + unsigned int val) +{ + return cphy->mdio.mdio_write(cphy->mdio.dev, cphy->mdio.prtad, mmd, + reg, val); +} + +static inline int simple_mdio_read(struct cphy *cphy, int reg, + unsigned int *valp) +{ + return cphy_mdio_read(cphy, MDIO_DEVAD_NONE, reg, valp); +} + +static inline int simple_mdio_write(struct cphy *cphy, int reg, + unsigned int val) +{ + return cphy_mdio_write(cphy, MDIO_DEVAD_NONE, reg, val); +} + +/* Convenience initializer */ +static inline void cphy_init(struct cphy *phy, struct net_device *dev, + int phy_addr, struct cphy_ops *phy_ops, + const struct mdio_ops *mdio_ops) +{ + struct adapter *adapter = netdev_priv(dev); + phy->adapter = adapter; + phy->ops = phy_ops; + if (mdio_ops) { + phy->mdio.prtad = phy_addr; + phy->mdio.mmds = phy_ops->mmds; + phy->mdio.mode_support = mdio_ops->mode_support; + phy->mdio.mdio_read = mdio_ops->read; + phy->mdio.mdio_write = mdio_ops->write; + } + phy->mdio.dev = dev; +} + +/* Operations of the PHY-instance factory */ +struct gphy { + /* Construct a PHY instance with the given PHY address */ + struct cphy *(*create)(struct net_device *dev, int phy_addr, + const struct mdio_ops *mdio_ops); + + /* + * Reset the PHY chip. This resets the whole PHY chip, not individual + * ports. + */ + int (*reset)(adapter_t *adapter); +}; + +extern const struct gphy t1_my3126_ops; +extern const struct gphy t1_mv88e1xxx_ops; +extern const struct gphy t1_vsc8244_ops; +extern const struct gphy t1_mv88x201x_ops; + +#endif /* _CXGB_CPHY_H_ */ diff --git a/drivers/net/ethernet/chelsio/cxgb/cpl5_cmd.h b/drivers/net/ethernet/chelsio/cxgb/cpl5_cmd.h new file mode 100644 index 000000000000..e36d45b78cc7 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb/cpl5_cmd.h @@ -0,0 +1,639 @@ +/***************************************************************************** + * * + * File: cpl5_cmd.h * + * $Revision: 1.6 $ * + * $Date: 2005/06/21 18:29:47 $ * + * Description: * + * part of the Chelsio 10Gb Ethernet Driver. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License, version 2, as * + * published by the Free Software Foundation. * + * * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * + * * + * http://www.chelsio.com * + * * + * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * + * All rights reserved. * + * * + * Maintainers: maintainers@chelsio.com * + * * + * Authors: Dimitrios Michailidis * + * Tina Yang * + * Felix Marti * + * Scott Bardone * + * Kurt Ottaway * + * Frank DiMambro * + * * + * History: * + * * + ****************************************************************************/ + +#ifndef _CXGB_CPL5_CMD_H_ +#define _CXGB_CPL5_CMD_H_ + +#include + +#if !defined(__LITTLE_ENDIAN_BITFIELD) && !defined(__BIG_ENDIAN_BITFIELD) +#error "Adjust your defines" +#endif + +enum CPL_opcode { + CPL_PASS_OPEN_REQ = 0x1, + CPL_PASS_OPEN_RPL = 0x2, + CPL_PASS_ESTABLISH = 0x3, + CPL_PASS_ACCEPT_REQ = 0xE, + CPL_PASS_ACCEPT_RPL = 0x4, + CPL_ACT_OPEN_REQ = 0x5, + CPL_ACT_OPEN_RPL = 0x6, + CPL_CLOSE_CON_REQ = 0x7, + CPL_CLOSE_CON_RPL = 0x8, + CPL_CLOSE_LISTSRV_REQ = 0x9, + CPL_CLOSE_LISTSRV_RPL = 0xA, + CPL_ABORT_REQ = 0xB, + CPL_ABORT_RPL = 0xC, + CPL_PEER_CLOSE = 0xD, + CPL_ACT_ESTABLISH = 0x17, + + CPL_GET_TCB = 0x24, + CPL_GET_TCB_RPL = 0x25, + CPL_SET_TCB = 0x26, + CPL_SET_TCB_FIELD = 0x27, + CPL_SET_TCB_RPL = 0x28, + CPL_PCMD = 0x29, + + CPL_PCMD_READ = 0x31, + CPL_PCMD_READ_RPL = 0x32, + + + CPL_RX_DATA = 0xA0, + CPL_RX_DATA_DDP = 0xA1, + CPL_RX_DATA_ACK = 0xA3, + CPL_RX_PKT = 0xAD, + CPL_RX_ISCSI_HDR = 0xAF, + CPL_TX_DATA_ACK = 0xB0, + CPL_TX_DATA = 0xB1, + CPL_TX_PKT = 0xB2, + CPL_TX_PKT_LSO = 0xB6, + + CPL_RTE_DELETE_REQ = 0xC0, + CPL_RTE_DELETE_RPL = 0xC1, + CPL_RTE_WRITE_REQ = 0xC2, + CPL_RTE_WRITE_RPL = 0xD3, + CPL_RTE_READ_REQ = 0xC3, + CPL_RTE_READ_RPL = 0xC4, + CPL_L2T_WRITE_REQ = 0xC5, + CPL_L2T_WRITE_RPL = 0xD4, + CPL_L2T_READ_REQ = 0xC6, + CPL_L2T_READ_RPL = 0xC7, + CPL_SMT_WRITE_REQ = 0xC8, + CPL_SMT_WRITE_RPL = 0xD5, + CPL_SMT_READ_REQ = 0xC9, + CPL_SMT_READ_RPL = 0xCA, + CPL_ARP_MISS_REQ = 0xCD, + CPL_ARP_MISS_RPL = 0xCE, + CPL_MIGRATE_C2T_REQ = 0xDC, + CPL_MIGRATE_C2T_RPL = 0xDD, + CPL_ERROR = 0xD7, + + /* internal: driver -> TOM */ + CPL_MSS_CHANGE = 0xE1 +}; + +#define NUM_CPL_CMDS 256 + +enum CPL_error { + CPL_ERR_NONE = 0, + CPL_ERR_TCAM_PARITY = 1, + CPL_ERR_TCAM_FULL = 3, + CPL_ERR_CONN_RESET = 20, + CPL_ERR_CONN_EXIST = 22, + CPL_ERR_ARP_MISS = 23, + CPL_ERR_BAD_SYN = 24, + CPL_ERR_CONN_TIMEDOUT = 30, + CPL_ERR_XMIT_TIMEDOUT = 31, + CPL_ERR_PERSIST_TIMEDOUT = 32, + CPL_ERR_FINWAIT2_TIMEDOUT = 33, + CPL_ERR_KEEPALIVE_TIMEDOUT = 34, + CPL_ERR_ABORT_FAILED = 42, + CPL_ERR_GENERAL = 99 +}; + +enum { + CPL_CONN_POLICY_AUTO = 0, + CPL_CONN_POLICY_ASK = 1, + CPL_CONN_POLICY_DENY = 3 +}; + +enum { + ULP_MODE_NONE = 0, + ULP_MODE_TCPDDP = 1, + ULP_MODE_ISCSI = 2, + ULP_MODE_IWARP = 3, + ULP_MODE_SSL = 4 +}; + +enum { + CPL_PASS_OPEN_ACCEPT, + CPL_PASS_OPEN_REJECT +}; + +enum { + CPL_ABORT_SEND_RST = 0, + CPL_ABORT_NO_RST, + CPL_ABORT_POST_CLOSE_REQ = 2 +}; + +enum { // TX_PKT_LSO ethernet types + CPL_ETH_II, + CPL_ETH_II_VLAN, + CPL_ETH_802_3, + CPL_ETH_802_3_VLAN +}; + +union opcode_tid { + u32 opcode_tid; + u8 opcode; +}; + +#define S_OPCODE 24 +#define V_OPCODE(x) ((x) << S_OPCODE) +#define G_OPCODE(x) (((x) >> S_OPCODE) & 0xFF) +#define G_TID(x) ((x) & 0xFFFFFF) + +/* tid is assumed to be 24-bits */ +#define MK_OPCODE_TID(opcode, tid) (V_OPCODE(opcode) | (tid)) + +#define OPCODE_TID(cmd) ((cmd)->ot.opcode_tid) + +/* extract the TID from a CPL command */ +#define GET_TID(cmd) (G_TID(ntohl(OPCODE_TID(cmd)))) + +struct tcp_options { + u16 mss; + u8 wsf; +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 rsvd:4; + u8 ecn:1; + u8 sack:1; + u8 tstamp:1; +#else + u8 tstamp:1; + u8 sack:1; + u8 ecn:1; + u8 rsvd:4; +#endif +}; + +struct cpl_pass_open_req { + union opcode_tid ot; + u16 local_port; + u16 peer_port; + u32 local_ip; + u32 peer_ip; + u32 opt0h; + u32 opt0l; + u32 peer_netmask; + u32 opt1; +}; + +struct cpl_pass_open_rpl { + union opcode_tid ot; + u16 local_port; + u16 peer_port; + u32 local_ip; + u32 peer_ip; + u8 resvd[7]; + u8 status; +}; + +struct cpl_pass_establish { + union opcode_tid ot; + u16 local_port; + u16 peer_port; + u32 local_ip; + u32 peer_ip; + u32 tos_tid; + u8 l2t_idx; + u8 rsvd[3]; + u32 snd_isn; + u32 rcv_isn; +}; + +struct cpl_pass_accept_req { + union opcode_tid ot; + u16 local_port; + u16 peer_port; + u32 local_ip; + u32 peer_ip; + u32 tos_tid; + struct tcp_options tcp_options; + u8 dst_mac[6]; + u16 vlan_tag; + u8 src_mac[6]; + u8 rsvd[2]; + u32 rcv_isn; + u32 unknown_tcp_options; +}; + +struct cpl_pass_accept_rpl { + union opcode_tid ot; + u32 rsvd0; + u32 rsvd1; + u32 peer_ip; + u32 opt0h; + union { + u32 opt0l; + struct { + u8 rsvd[3]; + u8 status; + }; + }; +}; + +struct cpl_act_open_req { + union opcode_tid ot; + u16 local_port; + u16 peer_port; + u32 local_ip; + u32 peer_ip; + u32 opt0h; + u32 opt0l; + u32 iff_vlantag; + u32 rsvd; +}; + +struct cpl_act_open_rpl { + union opcode_tid ot; + u16 local_port; + u16 peer_port; + u32 local_ip; + u32 peer_ip; + u32 new_tid; + u8 rsvd[3]; + u8 status; +}; + +struct cpl_act_establish { + union opcode_tid ot; + u16 local_port; + u16 peer_port; + u32 local_ip; + u32 peer_ip; + u32 tos_tid; + u32 rsvd; + u32 snd_isn; + u32 rcv_isn; +}; + +struct cpl_get_tcb { + union opcode_tid ot; + u32 rsvd; +}; + +struct cpl_get_tcb_rpl { + union opcode_tid ot; + u16 len; + u8 rsvd; + u8 status; +}; + +struct cpl_set_tcb { + union opcode_tid ot; + u16 len; + u16 rsvd; +}; + +struct cpl_set_tcb_field { + union opcode_tid ot; + u8 rsvd[3]; + u8 offset; + u32 mask; + u32 val; +}; + +struct cpl_set_tcb_rpl { + union opcode_tid ot; + u8 rsvd[3]; + u8 status; +}; + +struct cpl_pcmd { + union opcode_tid ot; + u16 dlen_in; + u16 dlen_out; + u32 pcmd_parm[2]; +}; + +struct cpl_pcmd_read { + union opcode_tid ot; + u32 rsvd1; + u16 rsvd2; + u32 addr; + u16 len; +}; + +struct cpl_pcmd_read_rpl { + union opcode_tid ot; + u16 len; +}; + +struct cpl_close_con_req { + union opcode_tid ot; + u32 rsvd; +}; + +struct cpl_close_con_rpl { + union opcode_tid ot; + u8 rsvd[3]; + u8 status; + u32 snd_nxt; + u32 rcv_nxt; +}; + +struct cpl_close_listserv_req { + union opcode_tid ot; + u32 rsvd; +}; + +struct cpl_close_listserv_rpl { + union opcode_tid ot; + u8 rsvd[3]; + u8 status; +}; + +struct cpl_abort_req { + union opcode_tid ot; + u32 rsvd0; + u8 rsvd1; + u8 cmd; + u8 rsvd2[6]; +}; + +struct cpl_abort_rpl { + union opcode_tid ot; + u32 rsvd0; + u8 rsvd1; + u8 status; + u8 rsvd2[6]; +}; + +struct cpl_peer_close { + union opcode_tid ot; + u32 rsvd; +}; + +struct cpl_tx_data { + union opcode_tid ot; + u32 len; + u32 rsvd0; + u16 urg; + u16 flags; +}; + +struct cpl_tx_data_ack { + union opcode_tid ot; + u32 ack_seq; +}; + +struct cpl_rx_data { + union opcode_tid ot; + u32 len; + u32 seq; + u16 urg; + u8 rsvd; + u8 status; +}; + +struct cpl_rx_data_ack { + union opcode_tid ot; + u32 credit; +}; + +struct cpl_rx_data_ddp { + union opcode_tid ot; + u32 len; + u32 seq; + u32 nxt_seq; + u32 ulp_crc; + u16 ddp_status; + u8 rsvd; + u8 status; +}; + +/* + * We want this header's alignment to be no more stringent than 2-byte aligned. + * All fields are u8 or u16 except for the length. However that field is not + * used so we break it into 2 16-bit parts to easily meet our alignment needs. + */ +struct cpl_tx_pkt { + u8 opcode; +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 iff:4; + u8 ip_csum_dis:1; + u8 l4_csum_dis:1; + u8 vlan_valid:1; + u8 rsvd:1; +#else + u8 rsvd:1; + u8 vlan_valid:1; + u8 l4_csum_dis:1; + u8 ip_csum_dis:1; + u8 iff:4; +#endif + u16 vlan; + u16 len_hi; + u16 len_lo; +}; + +struct cpl_tx_pkt_lso { + u8 opcode; +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 iff:4; + u8 ip_csum_dis:1; + u8 l4_csum_dis:1; + u8 vlan_valid:1; + u8 :1; +#else + u8 :1; + u8 vlan_valid:1; + u8 l4_csum_dis:1; + u8 ip_csum_dis:1; + u8 iff:4; +#endif + u16 vlan; + __be32 len; + + u8 rsvd[5]; +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 tcp_hdr_words:4; + u8 ip_hdr_words:4; +#else + u8 ip_hdr_words:4; + u8 tcp_hdr_words:4; +#endif + __be16 eth_type_mss; +}; + +struct cpl_rx_pkt { + u8 opcode; +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 iff:4; + u8 csum_valid:1; + u8 bad_pkt:1; + u8 vlan_valid:1; + u8 rsvd:1; +#else + u8 rsvd:1; + u8 vlan_valid:1; + u8 bad_pkt:1; + u8 csum_valid:1; + u8 iff:4; +#endif + u16 csum; + u16 vlan; + u16 len; +}; + +struct cpl_l2t_write_req { + union opcode_tid ot; + u32 params; + u8 rsvd1[2]; + u8 dst_mac[6]; +}; + +struct cpl_l2t_write_rpl { + union opcode_tid ot; + u8 status; + u8 rsvd[3]; +}; + +struct cpl_l2t_read_req { + union opcode_tid ot; + u8 rsvd[3]; + u8 l2t_idx; +}; + +struct cpl_l2t_read_rpl { + union opcode_tid ot; + u32 params; + u8 rsvd1[2]; + u8 dst_mac[6]; +}; + +struct cpl_smt_write_req { + union opcode_tid ot; + u8 rsvd0; +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 rsvd1:1; + u8 mtu_idx:3; + u8 iff:4; +#else + u8 iff:4; + u8 mtu_idx:3; + u8 rsvd1:1; +#endif + u16 rsvd2; + u16 rsvd3; + u8 src_mac1[6]; + u16 rsvd4; + u8 src_mac0[6]; +}; + +struct cpl_smt_write_rpl { + union opcode_tid ot; + u8 status; + u8 rsvd[3]; +}; + +struct cpl_smt_read_req { + union opcode_tid ot; + u8 rsvd0; +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 rsvd1:4; + u8 iff:4; +#else + u8 iff:4; + u8 rsvd1:4; +#endif + u16 rsvd2; +}; + +struct cpl_smt_read_rpl { + union opcode_tid ot; + u8 status; +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 rsvd1:1; + u8 mtu_idx:3; + u8 rsvd0:4; +#else + u8 rsvd0:4; + u8 mtu_idx:3; + u8 rsvd1:1; +#endif + u16 rsvd2; + u16 rsvd3; + u8 src_mac1[6]; + u16 rsvd4; + u8 src_mac0[6]; +}; + +struct cpl_rte_delete_req { + union opcode_tid ot; + u32 params; +}; + +struct cpl_rte_delete_rpl { + union opcode_tid ot; + u8 status; + u8 rsvd[3]; +}; + +struct cpl_rte_write_req { + union opcode_tid ot; + u32 params; + u32 netmask; + u32 faddr; +}; + +struct cpl_rte_write_rpl { + union opcode_tid ot; + u8 status; + u8 rsvd[3]; +}; + +struct cpl_rte_read_req { + union opcode_tid ot; + u32 params; +}; + +struct cpl_rte_read_rpl { + union opcode_tid ot; + u8 status; + u8 rsvd0[2]; + u8 l2t_idx; +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 rsvd1:7; + u8 select:1; +#else + u8 select:1; + u8 rsvd1:7; +#endif + u8 rsvd2[3]; + u32 addr; +}; + +struct cpl_mss_change { + union opcode_tid ot; + u32 mss; +}; + +#endif /* _CXGB_CPL5_CMD_H_ */ + diff --git a/drivers/net/ethernet/chelsio/cxgb/cxgb2.c b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c new file mode 100644 index 000000000000..3edbbc4c5112 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c @@ -0,0 +1,1379 @@ +/***************************************************************************** + * * + * File: cxgb2.c * + * $Revision: 1.25 $ * + * $Date: 2005/06/22 00:43:25 $ * + * Description: * + * Chelsio 10Gb Ethernet Driver. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License, version 2, as * + * published by the Free Software Foundation. * + * * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * + * * + * http://www.chelsio.com * + * * + * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * + * All rights reserved. * + * * + * Maintainers: maintainers@chelsio.com * + * * + * Authors: Dimitrios Michailidis * + * Tina Yang * + * Felix Marti * + * Scott Bardone * + * Kurt Ottaway * + * Frank DiMambro * + * * + * History: * + * * + ****************************************************************************/ + +#include "common.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpl5_cmd.h" +#include "regs.h" +#include "gmac.h" +#include "cphy.h" +#include "sge.h" +#include "tp.h" +#include "espi.h" +#include "elmer0.h" + +#include + +static inline void schedule_mac_stats_update(struct adapter *ap, int secs) +{ + schedule_delayed_work(&ap->stats_update_task, secs * HZ); +} + +static inline void cancel_mac_stats_update(struct adapter *ap) +{ + cancel_delayed_work(&ap->stats_update_task); +} + +#define MAX_CMDQ_ENTRIES 16384 +#define MAX_CMDQ1_ENTRIES 1024 +#define MAX_RX_BUFFERS 16384 +#define MAX_RX_JUMBO_BUFFERS 16384 +#define MAX_TX_BUFFERS_HIGH 16384U +#define MAX_TX_BUFFERS_LOW 1536U +#define MAX_TX_BUFFERS 1460U +#define MIN_FL_ENTRIES 32 + +#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \ + NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\ + NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) + +/* + * The EEPROM is actually bigger but only the first few bytes are used so we + * only report those. + */ +#define EEPROM_SIZE 32 + +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_AUTHOR("Chelsio Communications"); +MODULE_LICENSE("GPL"); + +static int dflt_msg_enable = DFLT_MSG_ENABLE; + +module_param(dflt_msg_enable, int, 0); +MODULE_PARM_DESC(dflt_msg_enable, "Chelsio T1 default message enable bitmap"); + +#define HCLOCK 0x0 +#define LCLOCK 0x1 + +/* T1 cards powersave mode */ +static int t1_clock(struct adapter *adapter, int mode); +static int t1powersave = 1; /* HW default is powersave mode. */ + +module_param(t1powersave, int, 0); +MODULE_PARM_DESC(t1powersave, "Enable/Disable T1 powersaving mode"); + +static int disable_msi = 0; +module_param(disable_msi, int, 0); +MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)"); + +static const char pci_speed[][4] = { + "33", "66", "100", "133" +}; + +/* + * Setup MAC to receive the types of packets we want. + */ +static void t1_set_rxmode(struct net_device *dev) +{ + struct adapter *adapter = dev->ml_priv; + struct cmac *mac = adapter->port[dev->if_port].mac; + struct t1_rx_mode rm; + + rm.dev = dev; + mac->ops->set_rx_mode(mac, &rm); +} + +static void link_report(struct port_info *p) +{ + if (!netif_carrier_ok(p->dev)) + printk(KERN_INFO "%s: link down\n", p->dev->name); + else { + const char *s = "10Mbps"; + + switch (p->link_config.speed) { + case SPEED_10000: s = "10Gbps"; break; + case SPEED_1000: s = "1000Mbps"; break; + case SPEED_100: s = "100Mbps"; break; + } + + printk(KERN_INFO "%s: link up, %s, %s-duplex\n", + p->dev->name, s, + p->link_config.duplex == DUPLEX_FULL ? "full" : "half"); + } +} + +void t1_link_negotiated(struct adapter *adapter, int port_id, int link_stat, + int speed, int duplex, int pause) +{ + struct port_info *p = &adapter->port[port_id]; + + if (link_stat != netif_carrier_ok(p->dev)) { + if (link_stat) + netif_carrier_on(p->dev); + else + netif_carrier_off(p->dev); + link_report(p); + + /* multi-ports: inform toe */ + if ((speed > 0) && (adapter->params.nports > 1)) { + unsigned int sched_speed = 10; + switch (speed) { + case SPEED_1000: + sched_speed = 1000; + break; + case SPEED_100: + sched_speed = 100; + break; + case SPEED_10: + sched_speed = 10; + break; + } + t1_sched_update_parms(adapter->sge, port_id, 0, sched_speed); + } + } +} + +static void link_start(struct port_info *p) +{ + struct cmac *mac = p->mac; + + mac->ops->reset(mac); + if (mac->ops->macaddress_set) + mac->ops->macaddress_set(mac, p->dev->dev_addr); + t1_set_rxmode(p->dev); + t1_link_start(p->phy, mac, &p->link_config); + mac->ops->enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); +} + +static void enable_hw_csum(struct adapter *adapter) +{ + if (adapter->port[0].dev->hw_features & NETIF_F_TSO) + t1_tp_set_ip_checksum_offload(adapter->tp, 1); /* for TSO only */ + t1_tp_set_tcp_checksum_offload(adapter->tp, 1); +} + +/* + * Things to do upon first use of a card. + * This must run with the rtnl lock held. + */ +static int cxgb_up(struct adapter *adapter) +{ + int err = 0; + + if (!(adapter->flags & FULL_INIT_DONE)) { + err = t1_init_hw_modules(adapter); + if (err) + goto out_err; + + enable_hw_csum(adapter); + adapter->flags |= FULL_INIT_DONE; + } + + t1_interrupts_clear(adapter); + + adapter->params.has_msi = !disable_msi && !pci_enable_msi(adapter->pdev); + err = request_irq(adapter->pdev->irq, t1_interrupt, + adapter->params.has_msi ? 0 : IRQF_SHARED, + adapter->name, adapter); + if (err) { + if (adapter->params.has_msi) + pci_disable_msi(adapter->pdev); + + goto out_err; + } + + t1_sge_start(adapter->sge); + t1_interrupts_enable(adapter); +out_err: + return err; +} + +/* + * Release resources when all the ports have been stopped. + */ +static void cxgb_down(struct adapter *adapter) +{ + t1_sge_stop(adapter->sge); + t1_interrupts_disable(adapter); + free_irq(adapter->pdev->irq, adapter); + if (adapter->params.has_msi) + pci_disable_msi(adapter->pdev); +} + +static int cxgb_open(struct net_device *dev) +{ + int err; + struct adapter *adapter = dev->ml_priv; + int other_ports = adapter->open_device_map & PORT_MASK; + + napi_enable(&adapter->napi); + if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0) { + napi_disable(&adapter->napi); + return err; + } + + __set_bit(dev->if_port, &adapter->open_device_map); + link_start(&adapter->port[dev->if_port]); + netif_start_queue(dev); + if (!other_ports && adapter->params.stats_update_period) + schedule_mac_stats_update(adapter, + adapter->params.stats_update_period); + + t1_vlan_mode(adapter, dev->features); + return 0; +} + +static int cxgb_close(struct net_device *dev) +{ + struct adapter *adapter = dev->ml_priv; + struct port_info *p = &adapter->port[dev->if_port]; + struct cmac *mac = p->mac; + + netif_stop_queue(dev); + napi_disable(&adapter->napi); + mac->ops->disable(mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX); + netif_carrier_off(dev); + + clear_bit(dev->if_port, &adapter->open_device_map); + if (adapter->params.stats_update_period && + !(adapter->open_device_map & PORT_MASK)) { + /* Stop statistics accumulation. */ + smp_mb__after_clear_bit(); + spin_lock(&adapter->work_lock); /* sync with update task */ + spin_unlock(&adapter->work_lock); + cancel_mac_stats_update(adapter); + } + + if (!adapter->open_device_map) + cxgb_down(adapter); + return 0; +} + +static struct net_device_stats *t1_get_stats(struct net_device *dev) +{ + struct adapter *adapter = dev->ml_priv; + struct port_info *p = &adapter->port[dev->if_port]; + struct net_device_stats *ns = &p->netstats; + const struct cmac_statistics *pstats; + + /* Do a full update of the MAC stats */ + pstats = p->mac->ops->statistics_update(p->mac, + MAC_STATS_UPDATE_FULL); + + ns->tx_packets = pstats->TxUnicastFramesOK + + pstats->TxMulticastFramesOK + pstats->TxBroadcastFramesOK; + + ns->rx_packets = pstats->RxUnicastFramesOK + + pstats->RxMulticastFramesOK + pstats->RxBroadcastFramesOK; + + ns->tx_bytes = pstats->TxOctetsOK; + ns->rx_bytes = pstats->RxOctetsOK; + + ns->tx_errors = pstats->TxLateCollisions + pstats->TxLengthErrors + + pstats->TxUnderrun + pstats->TxFramesAbortedDueToXSCollisions; + ns->rx_errors = pstats->RxDataErrors + pstats->RxJabberErrors + + pstats->RxFCSErrors + pstats->RxAlignErrors + + pstats->RxSequenceErrors + pstats->RxFrameTooLongErrors + + pstats->RxSymbolErrors + pstats->RxRuntErrors; + + ns->multicast = pstats->RxMulticastFramesOK; + ns->collisions = pstats->TxTotalCollisions; + + /* detailed rx_errors */ + ns->rx_length_errors = pstats->RxFrameTooLongErrors + + pstats->RxJabberErrors; + ns->rx_over_errors = 0; + ns->rx_crc_errors = pstats->RxFCSErrors; + ns->rx_frame_errors = pstats->RxAlignErrors; + ns->rx_fifo_errors = 0; + ns->rx_missed_errors = 0; + + /* detailed tx_errors */ + ns->tx_aborted_errors = pstats->TxFramesAbortedDueToXSCollisions; + ns->tx_carrier_errors = 0; + ns->tx_fifo_errors = pstats->TxUnderrun; + ns->tx_heartbeat_errors = 0; + ns->tx_window_errors = pstats->TxLateCollisions; + return ns; +} + +static u32 get_msglevel(struct net_device *dev) +{ + struct adapter *adapter = dev->ml_priv; + + return adapter->msg_enable; +} + +static void set_msglevel(struct net_device *dev, u32 val) +{ + struct adapter *adapter = dev->ml_priv; + + adapter->msg_enable = val; +} + +static char stats_strings[][ETH_GSTRING_LEN] = { + "TxOctetsOK", + "TxOctetsBad", + "TxUnicastFramesOK", + "TxMulticastFramesOK", + "TxBroadcastFramesOK", + "TxPauseFrames", + "TxFramesWithDeferredXmissions", + "TxLateCollisions", + "TxTotalCollisions", + "TxFramesAbortedDueToXSCollisions", + "TxUnderrun", + "TxLengthErrors", + "TxInternalMACXmitError", + "TxFramesWithExcessiveDeferral", + "TxFCSErrors", + "TxJumboFramesOk", + "TxJumboOctetsOk", + + "RxOctetsOK", + "RxOctetsBad", + "RxUnicastFramesOK", + "RxMulticastFramesOK", + "RxBroadcastFramesOK", + "RxPauseFrames", + "RxFCSErrors", + "RxAlignErrors", + "RxSymbolErrors", + "RxDataErrors", + "RxSequenceErrors", + "RxRuntErrors", + "RxJabberErrors", + "RxInternalMACRcvError", + "RxInRangeLengthErrors", + "RxOutOfRangeLengthField", + "RxFrameTooLongErrors", + "RxJumboFramesOk", + "RxJumboOctetsOk", + + /* Port stats */ + "RxCsumGood", + "TxCsumOffload", + "TxTso", + "RxVlan", + "TxVlan", + "TxNeedHeadroom", + + /* Interrupt stats */ + "rx drops", + "pure_rsps", + "unhandled irqs", + "respQ_empty", + "respQ_overflow", + "freelistQ_empty", + "pkt_too_big", + "pkt_mismatch", + "cmdQ_full0", + "cmdQ_full1", + + "espi_DIP2ParityErr", + "espi_DIP4Err", + "espi_RxDrops", + "espi_TxDrops", + "espi_RxOvfl", + "espi_ParityErr" +}; + +#define T2_REGMAP_SIZE (3 * 1024) + +static int get_regs_len(struct net_device *dev) +{ + return T2_REGMAP_SIZE; +} + +static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + struct adapter *adapter = dev->ml_priv; + + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + strcpy(info->fw_version, "N/A"); + strcpy(info->bus_info, pci_name(adapter->pdev)); +} + +static int get_sset_count(struct net_device *dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(stats_strings); + default: + return -EOPNOTSUPP; + } +} + +static void get_strings(struct net_device *dev, u32 stringset, u8 *data) +{ + if (stringset == ETH_SS_STATS) + memcpy(data, stats_strings, sizeof(stats_strings)); +} + +static void get_stats(struct net_device *dev, struct ethtool_stats *stats, + u64 *data) +{ + struct adapter *adapter = dev->ml_priv; + struct cmac *mac = adapter->port[dev->if_port].mac; + const struct cmac_statistics *s; + const struct sge_intr_counts *t; + struct sge_port_stats ss; + + s = mac->ops->statistics_update(mac, MAC_STATS_UPDATE_FULL); + t = t1_sge_get_intr_counts(adapter->sge); + t1_sge_get_port_stats(adapter->sge, dev->if_port, &ss); + + *data++ = s->TxOctetsOK; + *data++ = s->TxOctetsBad; + *data++ = s->TxUnicastFramesOK; + *data++ = s->TxMulticastFramesOK; + *data++ = s->TxBroadcastFramesOK; + *data++ = s->TxPauseFrames; + *data++ = s->TxFramesWithDeferredXmissions; + *data++ = s->TxLateCollisions; + *data++ = s->TxTotalCollisions; + *data++ = s->TxFramesAbortedDueToXSCollisions; + *data++ = s->TxUnderrun; + *data++ = s->TxLengthErrors; + *data++ = s->TxInternalMACXmitError; + *data++ = s->TxFramesWithExcessiveDeferral; + *data++ = s->TxFCSErrors; + *data++ = s->TxJumboFramesOK; + *data++ = s->TxJumboOctetsOK; + + *data++ = s->RxOctetsOK; + *data++ = s->RxOctetsBad; + *data++ = s->RxUnicastFramesOK; + *data++ = s->RxMulticastFramesOK; + *data++ = s->RxBroadcastFramesOK; + *data++ = s->RxPauseFrames; + *data++ = s->RxFCSErrors; + *data++ = s->RxAlignErrors; + *data++ = s->RxSymbolErrors; + *data++ = s->RxDataErrors; + *data++ = s->RxSequenceErrors; + *data++ = s->RxRuntErrors; + *data++ = s->RxJabberErrors; + *data++ = s->RxInternalMACRcvError; + *data++ = s->RxInRangeLengthErrors; + *data++ = s->RxOutOfRangeLengthField; + *data++ = s->RxFrameTooLongErrors; + *data++ = s->RxJumboFramesOK; + *data++ = s->RxJumboOctetsOK; + + *data++ = ss.rx_cso_good; + *data++ = ss.tx_cso; + *data++ = ss.tx_tso; + *data++ = ss.vlan_xtract; + *data++ = ss.vlan_insert; + *data++ = ss.tx_need_hdrroom; + + *data++ = t->rx_drops; + *data++ = t->pure_rsps; + *data++ = t->unhandled_irqs; + *data++ = t->respQ_empty; + *data++ = t->respQ_overflow; + *data++ = t->freelistQ_empty; + *data++ = t->pkt_too_big; + *data++ = t->pkt_mismatch; + *data++ = t->cmdQ_full[0]; + *data++ = t->cmdQ_full[1]; + + if (adapter->espi) { + const struct espi_intr_counts *e; + + e = t1_espi_get_intr_counts(adapter->espi); + *data++ = e->DIP2_parity_err; + *data++ = e->DIP4_err; + *data++ = e->rx_drops; + *data++ = e->tx_drops; + *data++ = e->rx_ovflw; + *data++ = e->parity_err; + } +} + +static inline void reg_block_dump(struct adapter *ap, void *buf, + unsigned int start, unsigned int end) +{ + u32 *p = buf + start; + + for ( ; start <= end; start += sizeof(u32)) + *p++ = readl(ap->regs + start); +} + +static void get_regs(struct net_device *dev, struct ethtool_regs *regs, + void *buf) +{ + struct adapter *ap = dev->ml_priv; + + /* + * Version scheme: bits 0..9: chip version, bits 10..15: chip revision + */ + regs->version = 2; + + memset(buf, 0, T2_REGMAP_SIZE); + reg_block_dump(ap, buf, 0, A_SG_RESPACCUTIMER); + reg_block_dump(ap, buf, A_MC3_CFG, A_MC4_INT_CAUSE); + reg_block_dump(ap, buf, A_TPI_ADDR, A_TPI_PAR); + reg_block_dump(ap, buf, A_TP_IN_CONFIG, A_TP_TX_DROP_COUNT); + reg_block_dump(ap, buf, A_RAT_ROUTE_CONTROL, A_RAT_INTR_CAUSE); + reg_block_dump(ap, buf, A_CSPI_RX_AE_WM, A_CSPI_INTR_ENABLE); + reg_block_dump(ap, buf, A_ESPI_SCH_TOKEN0, A_ESPI_GOSTAT); + reg_block_dump(ap, buf, A_ULP_ULIMIT, A_ULP_PIO_CTRL); + reg_block_dump(ap, buf, A_PL_ENABLE, A_PL_CAUSE); + reg_block_dump(ap, buf, A_MC5_CONFIG, A_MC5_MASK_WRITE_CMD); +} + +static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct adapter *adapter = dev->ml_priv; + struct port_info *p = &adapter->port[dev->if_port]; + + cmd->supported = p->link_config.supported; + cmd->advertising = p->link_config.advertising; + + if (netif_carrier_ok(dev)) { + ethtool_cmd_speed_set(cmd, p->link_config.speed); + cmd->duplex = p->link_config.duplex; + } else { + ethtool_cmd_speed_set(cmd, -1); + cmd->duplex = -1; + } + + cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE; + cmd->phy_address = p->phy->mdio.prtad; + cmd->transceiver = XCVR_EXTERNAL; + cmd->autoneg = p->link_config.autoneg; + cmd->maxtxpkt = 0; + cmd->maxrxpkt = 0; + return 0; +} + +static int speed_duplex_to_caps(int speed, int duplex) +{ + int cap = 0; + + switch (speed) { + case SPEED_10: + if (duplex == DUPLEX_FULL) + cap = SUPPORTED_10baseT_Full; + else + cap = SUPPORTED_10baseT_Half; + break; + case SPEED_100: + if (duplex == DUPLEX_FULL) + cap = SUPPORTED_100baseT_Full; + else + cap = SUPPORTED_100baseT_Half; + break; + case SPEED_1000: + if (duplex == DUPLEX_FULL) + cap = SUPPORTED_1000baseT_Full; + else + cap = SUPPORTED_1000baseT_Half; + break; + case SPEED_10000: + if (duplex == DUPLEX_FULL) + cap = SUPPORTED_10000baseT_Full; + } + return cap; +} + +#define ADVERTISED_MASK (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \ + ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \ + ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | \ + ADVERTISED_10000baseT_Full) + +static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct adapter *adapter = dev->ml_priv; + struct port_info *p = &adapter->port[dev->if_port]; + struct link_config *lc = &p->link_config; + + if (!(lc->supported & SUPPORTED_Autoneg)) + return -EOPNOTSUPP; /* can't change speed/duplex */ + + if (cmd->autoneg == AUTONEG_DISABLE) { + u32 speed = ethtool_cmd_speed(cmd); + int cap = speed_duplex_to_caps(speed, cmd->duplex); + + if (!(lc->supported & cap) || (speed == SPEED_1000)) + return -EINVAL; + lc->requested_speed = speed; + lc->requested_duplex = cmd->duplex; + lc->advertising = 0; + } else { + cmd->advertising &= ADVERTISED_MASK; + if (cmd->advertising & (cmd->advertising - 1)) + cmd->advertising = lc->supported; + cmd->advertising &= lc->supported; + if (!cmd->advertising) + return -EINVAL; + lc->requested_speed = SPEED_INVALID; + lc->requested_duplex = DUPLEX_INVALID; + lc->advertising = cmd->advertising | ADVERTISED_Autoneg; + } + lc->autoneg = cmd->autoneg; + if (netif_running(dev)) + t1_link_start(p->phy, p->mac, lc); + return 0; +} + +static void get_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *epause) +{ + struct adapter *adapter = dev->ml_priv; + struct port_info *p = &adapter->port[dev->if_port]; + + epause->autoneg = (p->link_config.requested_fc & PAUSE_AUTONEG) != 0; + epause->rx_pause = (p->link_config.fc & PAUSE_RX) != 0; + epause->tx_pause = (p->link_config.fc & PAUSE_TX) != 0; +} + +static int set_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *epause) +{ + struct adapter *adapter = dev->ml_priv; + struct port_info *p = &adapter->port[dev->if_port]; + struct link_config *lc = &p->link_config; + + if (epause->autoneg == AUTONEG_DISABLE) + lc->requested_fc = 0; + else if (lc->supported & SUPPORTED_Autoneg) + lc->requested_fc = PAUSE_AUTONEG; + else + return -EINVAL; + + if (epause->rx_pause) + lc->requested_fc |= PAUSE_RX; + if (epause->tx_pause) + lc->requested_fc |= PAUSE_TX; + if (lc->autoneg == AUTONEG_ENABLE) { + if (netif_running(dev)) + t1_link_start(p->phy, p->mac, lc); + } else { + lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); + if (netif_running(dev)) + p->mac->ops->set_speed_duplex_fc(p->mac, -1, -1, + lc->fc); + } + return 0; +} + +static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) +{ + struct adapter *adapter = dev->ml_priv; + int jumbo_fl = t1_is_T1B(adapter) ? 1 : 0; + + e->rx_max_pending = MAX_RX_BUFFERS; + e->rx_mini_max_pending = 0; + e->rx_jumbo_max_pending = MAX_RX_JUMBO_BUFFERS; + e->tx_max_pending = MAX_CMDQ_ENTRIES; + + e->rx_pending = adapter->params.sge.freelQ_size[!jumbo_fl]; + e->rx_mini_pending = 0; + e->rx_jumbo_pending = adapter->params.sge.freelQ_size[jumbo_fl]; + e->tx_pending = adapter->params.sge.cmdQ_size[0]; +} + +static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e) +{ + struct adapter *adapter = dev->ml_priv; + int jumbo_fl = t1_is_T1B(adapter) ? 1 : 0; + + if (e->rx_pending > MAX_RX_BUFFERS || e->rx_mini_pending || + e->rx_jumbo_pending > MAX_RX_JUMBO_BUFFERS || + e->tx_pending > MAX_CMDQ_ENTRIES || + e->rx_pending < MIN_FL_ENTRIES || + e->rx_jumbo_pending < MIN_FL_ENTRIES || + e->tx_pending < (adapter->params.nports + 1) * (MAX_SKB_FRAGS + 1)) + return -EINVAL; + + if (adapter->flags & FULL_INIT_DONE) + return -EBUSY; + + adapter->params.sge.freelQ_size[!jumbo_fl] = e->rx_pending; + adapter->params.sge.freelQ_size[jumbo_fl] = e->rx_jumbo_pending; + adapter->params.sge.cmdQ_size[0] = e->tx_pending; + adapter->params.sge.cmdQ_size[1] = e->tx_pending > MAX_CMDQ1_ENTRIES ? + MAX_CMDQ1_ENTRIES : e->tx_pending; + return 0; +} + +static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c) +{ + struct adapter *adapter = dev->ml_priv; + + adapter->params.sge.rx_coalesce_usecs = c->rx_coalesce_usecs; + adapter->params.sge.coalesce_enable = c->use_adaptive_rx_coalesce; + adapter->params.sge.sample_interval_usecs = c->rate_sample_interval; + t1_sge_set_coalesce_params(adapter->sge, &adapter->params.sge); + return 0; +} + +static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c) +{ + struct adapter *adapter = dev->ml_priv; + + c->rx_coalesce_usecs = adapter->params.sge.rx_coalesce_usecs; + c->rate_sample_interval = adapter->params.sge.sample_interval_usecs; + c->use_adaptive_rx_coalesce = adapter->params.sge.coalesce_enable; + return 0; +} + +static int get_eeprom_len(struct net_device *dev) +{ + struct adapter *adapter = dev->ml_priv; + + return t1_is_asic(adapter) ? EEPROM_SIZE : 0; +} + +#define EEPROM_MAGIC(ap) \ + (PCI_VENDOR_ID_CHELSIO | ((ap)->params.chip_version << 16)) + +static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e, + u8 *data) +{ + int i; + u8 buf[EEPROM_SIZE] __attribute__((aligned(4))); + struct adapter *adapter = dev->ml_priv; + + e->magic = EEPROM_MAGIC(adapter); + for (i = e->offset & ~3; i < e->offset + e->len; i += sizeof(u32)) + t1_seeprom_read(adapter, i, (__le32 *)&buf[i]); + memcpy(data, buf + e->offset, e->len); + return 0; +} + +static const struct ethtool_ops t1_ethtool_ops = { + .get_settings = get_settings, + .set_settings = set_settings, + .get_drvinfo = get_drvinfo, + .get_msglevel = get_msglevel, + .set_msglevel = set_msglevel, + .get_ringparam = get_sge_param, + .set_ringparam = set_sge_param, + .get_coalesce = get_coalesce, + .set_coalesce = set_coalesce, + .get_eeprom_len = get_eeprom_len, + .get_eeprom = get_eeprom, + .get_pauseparam = get_pauseparam, + .set_pauseparam = set_pauseparam, + .get_link = ethtool_op_get_link, + .get_strings = get_strings, + .get_sset_count = get_sset_count, + .get_ethtool_stats = get_stats, + .get_regs_len = get_regs_len, + .get_regs = get_regs, +}; + +static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd) +{ + struct adapter *adapter = dev->ml_priv; + struct mdio_if_info *mdio = &adapter->port[dev->if_port].phy->mdio; + + return mdio_mii_ioctl(mdio, if_mii(req), cmd); +} + +static int t1_change_mtu(struct net_device *dev, int new_mtu) +{ + int ret; + struct adapter *adapter = dev->ml_priv; + struct cmac *mac = adapter->port[dev->if_port].mac; + + if (!mac->ops->set_mtu) + return -EOPNOTSUPP; + if (new_mtu < 68) + return -EINVAL; + if ((ret = mac->ops->set_mtu(mac, new_mtu))) + return ret; + dev->mtu = new_mtu; + return 0; +} + +static int t1_set_mac_addr(struct net_device *dev, void *p) +{ + struct adapter *adapter = dev->ml_priv; + struct cmac *mac = adapter->port[dev->if_port].mac; + struct sockaddr *addr = p; + + if (!mac->ops->macaddress_set) + return -EOPNOTSUPP; + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + mac->ops->macaddress_set(mac, dev->dev_addr); + return 0; +} + +static u32 t1_fix_features(struct net_device *dev, u32 features) +{ + /* + * Since there is no support for separate rx/tx vlan accel + * enable/disable make sure tx flag is always in same state as rx. + */ + if (features & NETIF_F_HW_VLAN_RX) + features |= NETIF_F_HW_VLAN_TX; + else + features &= ~NETIF_F_HW_VLAN_TX; + + return features; +} + +static int t1_set_features(struct net_device *dev, u32 features) +{ + u32 changed = dev->features ^ features; + struct adapter *adapter = dev->ml_priv; + + if (changed & NETIF_F_HW_VLAN_RX) + t1_vlan_mode(adapter, features); + + return 0; +} +#ifdef CONFIG_NET_POLL_CONTROLLER +static void t1_netpoll(struct net_device *dev) +{ + unsigned long flags; + struct adapter *adapter = dev->ml_priv; + + local_irq_save(flags); + t1_interrupt(adapter->pdev->irq, adapter); + local_irq_restore(flags); +} +#endif + +/* + * Periodic accumulation of MAC statistics. This is used only if the MAC + * does not have any other way to prevent stats counter overflow. + */ +static void mac_stats_task(struct work_struct *work) +{ + int i; + struct adapter *adapter = + container_of(work, struct adapter, stats_update_task.work); + + for_each_port(adapter, i) { + struct port_info *p = &adapter->port[i]; + + if (netif_running(p->dev)) + p->mac->ops->statistics_update(p->mac, + MAC_STATS_UPDATE_FAST); + } + + /* Schedule the next statistics update if any port is active. */ + spin_lock(&adapter->work_lock); + if (adapter->open_device_map & PORT_MASK) + schedule_mac_stats_update(adapter, + adapter->params.stats_update_period); + spin_unlock(&adapter->work_lock); +} + +/* + * Processes elmer0 external interrupts in process context. + */ +static void ext_intr_task(struct work_struct *work) +{ + struct adapter *adapter = + container_of(work, struct adapter, ext_intr_handler_task); + + t1_elmer0_ext_intr_handler(adapter); + + /* Now reenable external interrupts */ + spin_lock_irq(&adapter->async_lock); + adapter->slow_intr_mask |= F_PL_INTR_EXT; + writel(F_PL_INTR_EXT, adapter->regs + A_PL_CAUSE); + writel(adapter->slow_intr_mask | F_PL_INTR_SGE_DATA, + adapter->regs + A_PL_ENABLE); + spin_unlock_irq(&adapter->async_lock); +} + +/* + * Interrupt-context handler for elmer0 external interrupts. + */ +void t1_elmer0_ext_intr(struct adapter *adapter) +{ + /* + * Schedule a task to handle external interrupts as we require + * a process context. We disable EXT interrupts in the interim + * and let the task reenable them when it's done. + */ + adapter->slow_intr_mask &= ~F_PL_INTR_EXT; + writel(adapter->slow_intr_mask | F_PL_INTR_SGE_DATA, + adapter->regs + A_PL_ENABLE); + schedule_work(&adapter->ext_intr_handler_task); +} + +void t1_fatal_err(struct adapter *adapter) +{ + if (adapter->flags & FULL_INIT_DONE) { + t1_sge_stop(adapter->sge); + t1_interrupts_disable(adapter); + } + pr_alert("%s: encountered fatal error, operation suspended\n", + adapter->name); +} + +static const struct net_device_ops cxgb_netdev_ops = { + .ndo_open = cxgb_open, + .ndo_stop = cxgb_close, + .ndo_start_xmit = t1_start_xmit, + .ndo_get_stats = t1_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = t1_set_rxmode, + .ndo_do_ioctl = t1_ioctl, + .ndo_change_mtu = t1_change_mtu, + .ndo_set_mac_address = t1_set_mac_addr, + .ndo_fix_features = t1_fix_features, + .ndo_set_features = t1_set_features, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = t1_netpoll, +#endif +}; + +static int __devinit init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + static int version_printed; + + int i, err, pci_using_dac = 0; + unsigned long mmio_start, mmio_len; + const struct board_info *bi; + struct adapter *adapter = NULL; + struct port_info *pi; + + if (!version_printed) { + printk(KERN_INFO "%s - version %s\n", DRV_DESCRIPTION, + DRV_VERSION); + ++version_printed; + } + + err = pci_enable_device(pdev); + if (err) + return err; + + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { + pr_err("%s: cannot find PCI device memory base address\n", + pci_name(pdev)); + err = -ENODEV; + goto out_disable_pdev; + } + + if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { + pci_using_dac = 1; + + if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) { + pr_err("%s: unable to obtain 64-bit DMA for " + "consistent allocations\n", pci_name(pdev)); + err = -ENODEV; + goto out_disable_pdev; + } + + } else if ((err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) != 0) { + pr_err("%s: no usable DMA configuration\n", pci_name(pdev)); + goto out_disable_pdev; + } + + err = pci_request_regions(pdev, DRV_NAME); + if (err) { + pr_err("%s: cannot obtain PCI resources\n", pci_name(pdev)); + goto out_disable_pdev; + } + + pci_set_master(pdev); + + mmio_start = pci_resource_start(pdev, 0); + mmio_len = pci_resource_len(pdev, 0); + bi = t1_get_board_info(ent->driver_data); + + for (i = 0; i < bi->port_number; ++i) { + struct net_device *netdev; + + netdev = alloc_etherdev(adapter ? 0 : sizeof(*adapter)); + if (!netdev) { + err = -ENOMEM; + goto out_free_dev; + } + + SET_NETDEV_DEV(netdev, &pdev->dev); + + if (!adapter) { + adapter = netdev_priv(netdev); + adapter->pdev = pdev; + adapter->port[0].dev = netdev; /* so we don't leak it */ + + adapter->regs = ioremap(mmio_start, mmio_len); + if (!adapter->regs) { + pr_err("%s: cannot map device registers\n", + pci_name(pdev)); + err = -ENOMEM; + goto out_free_dev; + } + + if (t1_get_board_rev(adapter, bi, &adapter->params)) { + err = -ENODEV; /* Can't handle this chip rev */ + goto out_free_dev; + } + + adapter->name = pci_name(pdev); + adapter->msg_enable = dflt_msg_enable; + adapter->mmio_len = mmio_len; + + spin_lock_init(&adapter->tpi_lock); + spin_lock_init(&adapter->work_lock); + spin_lock_init(&adapter->async_lock); + spin_lock_init(&adapter->mac_lock); + + INIT_WORK(&adapter->ext_intr_handler_task, + ext_intr_task); + INIT_DELAYED_WORK(&adapter->stats_update_task, + mac_stats_task); + + pci_set_drvdata(pdev, netdev); + } + + pi = &adapter->port[i]; + pi->dev = netdev; + netif_carrier_off(netdev); + netdev->irq = pdev->irq; + netdev->if_port = i; + netdev->mem_start = mmio_start; + netdev->mem_end = mmio_start + mmio_len - 1; + netdev->ml_priv = adapter; + netdev->hw_features |= NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_RXCSUM; + netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_RXCSUM | NETIF_F_LLTX; + + if (pci_using_dac) + netdev->features |= NETIF_F_HIGHDMA; + if (vlan_tso_capable(adapter)) { + netdev->features |= + NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + netdev->hw_features |= NETIF_F_HW_VLAN_RX; + + /* T204: disable TSO */ + if (!(is_T2(adapter)) || bi->port_number != 4) { + netdev->hw_features |= NETIF_F_TSO; + netdev->features |= NETIF_F_TSO; + } + } + + netdev->netdev_ops = &cxgb_netdev_ops; + netdev->hard_header_len += (netdev->hw_features & NETIF_F_TSO) ? + sizeof(struct cpl_tx_pkt_lso) : sizeof(struct cpl_tx_pkt); + + netif_napi_add(netdev, &adapter->napi, t1_poll, 64); + + SET_ETHTOOL_OPS(netdev, &t1_ethtool_ops); + } + + if (t1_init_sw_modules(adapter, bi) < 0) { + err = -ENODEV; + goto out_free_dev; + } + + /* + * The card is now ready to go. If any errors occur during device + * registration we do not fail the whole card but rather proceed only + * with the ports we manage to register successfully. However we must + * register at least one net device. + */ + for (i = 0; i < bi->port_number; ++i) { + err = register_netdev(adapter->port[i].dev); + if (err) + pr_warning("%s: cannot register net device %s, skipping\n", + pci_name(pdev), adapter->port[i].dev->name); + else { + /* + * Change the name we use for messages to the name of + * the first successfully registered interface. + */ + if (!adapter->registered_device_map) + adapter->name = adapter->port[i].dev->name; + + __set_bit(i, &adapter->registered_device_map); + } + } + if (!adapter->registered_device_map) { + pr_err("%s: could not register any net devices\n", + pci_name(pdev)); + goto out_release_adapter_res; + } + + printk(KERN_INFO "%s: %s (rev %d), %s %dMHz/%d-bit\n", adapter->name, + bi->desc, adapter->params.chip_revision, + adapter->params.pci.is_pcix ? "PCIX" : "PCI", + adapter->params.pci.speed, adapter->params.pci.width); + + /* + * Set the T1B ASIC and memory clocks. + */ + if (t1powersave) + adapter->t1powersave = LCLOCK; /* HW default is powersave mode. */ + else + adapter->t1powersave = HCLOCK; + if (t1_is_T1B(adapter)) + t1_clock(adapter, t1powersave); + + return 0; + +out_release_adapter_res: + t1_free_sw_modules(adapter); +out_free_dev: + if (adapter) { + if (adapter->regs) + iounmap(adapter->regs); + for (i = bi->port_number - 1; i >= 0; --i) + if (adapter->port[i].dev) + free_netdev(adapter->port[i].dev); + } + pci_release_regions(pdev); +out_disable_pdev: + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + return err; +} + +static void bit_bang(struct adapter *adapter, int bitdata, int nbits) +{ + int data; + int i; + u32 val; + + enum { + S_CLOCK = 1 << 3, + S_DATA = 1 << 4 + }; + + for (i = (nbits - 1); i > -1; i--) { + + udelay(50); + + data = ((bitdata >> i) & 0x1); + __t1_tpi_read(adapter, A_ELMER0_GPO, &val); + + if (data) + val |= S_DATA; + else + val &= ~S_DATA; + + udelay(50); + + /* Set SCLOCK low */ + val &= ~S_CLOCK; + __t1_tpi_write(adapter, A_ELMER0_GPO, val); + + udelay(50); + + /* Write SCLOCK high */ + val |= S_CLOCK; + __t1_tpi_write(adapter, A_ELMER0_GPO, val); + + } +} + +static int t1_clock(struct adapter *adapter, int mode) +{ + u32 val; + int M_CORE_VAL; + int M_MEM_VAL; + + enum { + M_CORE_BITS = 9, + T_CORE_VAL = 0, + T_CORE_BITS = 2, + N_CORE_VAL = 0, + N_CORE_BITS = 2, + M_MEM_BITS = 9, + T_MEM_VAL = 0, + T_MEM_BITS = 2, + N_MEM_VAL = 0, + N_MEM_BITS = 2, + NP_LOAD = 1 << 17, + S_LOAD_MEM = 1 << 5, + S_LOAD_CORE = 1 << 6, + S_CLOCK = 1 << 3 + }; + + if (!t1_is_T1B(adapter)) + return -ENODEV; /* Can't re-clock this chip. */ + + if (mode & 2) + return 0; /* show current mode. */ + + if ((adapter->t1powersave & 1) == (mode & 1)) + return -EALREADY; /* ASIC already running in mode. */ + + if ((mode & 1) == HCLOCK) { + M_CORE_VAL = 0x14; + M_MEM_VAL = 0x18; + adapter->t1powersave = HCLOCK; /* overclock */ + } else { + M_CORE_VAL = 0xe; + M_MEM_VAL = 0x10; + adapter->t1powersave = LCLOCK; /* underclock */ + } + + /* Don't interrupt this serial stream! */ + spin_lock(&adapter->tpi_lock); + + /* Initialize for ASIC core */ + __t1_tpi_read(adapter, A_ELMER0_GPO, &val); + val |= NP_LOAD; + udelay(50); + __t1_tpi_write(adapter, A_ELMER0_GPO, val); + udelay(50); + __t1_tpi_read(adapter, A_ELMER0_GPO, &val); + val &= ~S_LOAD_CORE; + val &= ~S_CLOCK; + __t1_tpi_write(adapter, A_ELMER0_GPO, val); + udelay(50); + + /* Serial program the ASIC clock synthesizer */ + bit_bang(adapter, T_CORE_VAL, T_CORE_BITS); + bit_bang(adapter, N_CORE_VAL, N_CORE_BITS); + bit_bang(adapter, M_CORE_VAL, M_CORE_BITS); + udelay(50); + + /* Finish ASIC core */ + __t1_tpi_read(adapter, A_ELMER0_GPO, &val); + val |= S_LOAD_CORE; + udelay(50); + __t1_tpi_write(adapter, A_ELMER0_GPO, val); + udelay(50); + __t1_tpi_read(adapter, A_ELMER0_GPO, &val); + val &= ~S_LOAD_CORE; + udelay(50); + __t1_tpi_write(adapter, A_ELMER0_GPO, val); + udelay(50); + + /* Initialize for memory */ + __t1_tpi_read(adapter, A_ELMER0_GPO, &val); + val |= NP_LOAD; + udelay(50); + __t1_tpi_write(adapter, A_ELMER0_GPO, val); + udelay(50); + __t1_tpi_read(adapter, A_ELMER0_GPO, &val); + val &= ~S_LOAD_MEM; + val &= ~S_CLOCK; + udelay(50); + __t1_tpi_write(adapter, A_ELMER0_GPO, val); + udelay(50); + + /* Serial program the memory clock synthesizer */ + bit_bang(adapter, T_MEM_VAL, T_MEM_BITS); + bit_bang(adapter, N_MEM_VAL, N_MEM_BITS); + bit_bang(adapter, M_MEM_VAL, M_MEM_BITS); + udelay(50); + + /* Finish memory */ + __t1_tpi_read(adapter, A_ELMER0_GPO, &val); + val |= S_LOAD_MEM; + udelay(50); + __t1_tpi_write(adapter, A_ELMER0_GPO, val); + udelay(50); + __t1_tpi_read(adapter, A_ELMER0_GPO, &val); + val &= ~S_LOAD_MEM; + udelay(50); + __t1_tpi_write(adapter, A_ELMER0_GPO, val); + + spin_unlock(&adapter->tpi_lock); + + return 0; +} + +static inline void t1_sw_reset(struct pci_dev *pdev) +{ + pci_write_config_dword(pdev, A_PCICFG_PM_CSR, 3); + pci_write_config_dword(pdev, A_PCICFG_PM_CSR, 0); +} + +static void __devexit remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct adapter *adapter = dev->ml_priv; + int i; + + for_each_port(adapter, i) { + if (test_bit(i, &adapter->registered_device_map)) + unregister_netdev(adapter->port[i].dev); + } + + t1_free_sw_modules(adapter); + iounmap(adapter->regs); + + while (--i >= 0) { + if (adapter->port[i].dev) + free_netdev(adapter->port[i].dev); + } + + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + t1_sw_reset(pdev); +} + +static struct pci_driver driver = { + .name = DRV_NAME, + .id_table = t1_pci_tbl, + .probe = init_one, + .remove = __devexit_p(remove_one), +}; + +static int __init t1_init_module(void) +{ + return pci_register_driver(&driver); +} + +static void __exit t1_cleanup_module(void) +{ + pci_unregister_driver(&driver); +} + +module_init(t1_init_module); +module_exit(t1_cleanup_module); diff --git a/drivers/net/ethernet/chelsio/cxgb/elmer0.h b/drivers/net/ethernet/chelsio/cxgb/elmer0.h new file mode 100644 index 000000000000..eef655c827d9 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb/elmer0.h @@ -0,0 +1,158 @@ +/***************************************************************************** + * * + * File: elmer0.h * + * $Revision: 1.6 $ * + * $Date: 2005/06/21 22:49:43 $ * + * Description: * + * part of the Chelsio 10Gb Ethernet Driver. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License, version 2, as * + * published by the Free Software Foundation. * + * * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * + * * + * http://www.chelsio.com * + * * + * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * + * All rights reserved. * + * * + * Maintainers: maintainers@chelsio.com * + * * + * Authors: Dimitrios Michailidis * + * Tina Yang * + * Felix Marti * + * Scott Bardone * + * Kurt Ottaway * + * Frank DiMambro * + * * + * History: * + * * + ****************************************************************************/ + +#ifndef _CXGB_ELMER0_H_ +#define _CXGB_ELMER0_H_ + +/* ELMER0 flavors */ +enum { + ELMER0_XC2S300E_6FT256_C, + ELMER0_XC2S100E_6TQ144_C +}; + +/* ELMER0 registers */ +#define A_ELMER0_VERSION 0x100000 +#define A_ELMER0_PHY_CFG 0x100004 +#define A_ELMER0_INT_ENABLE 0x100008 +#define A_ELMER0_INT_CAUSE 0x10000c +#define A_ELMER0_GPI_CFG 0x100010 +#define A_ELMER0_GPI_STAT 0x100014 +#define A_ELMER0_GPO 0x100018 +#define A_ELMER0_PORT0_MI1_CFG 0x400000 + +#define S_MI1_MDI_ENABLE 0 +#define V_MI1_MDI_ENABLE(x) ((x) << S_MI1_MDI_ENABLE) +#define F_MI1_MDI_ENABLE V_MI1_MDI_ENABLE(1U) + +#define S_MI1_MDI_INVERT 1 +#define V_MI1_MDI_INVERT(x) ((x) << S_MI1_MDI_INVERT) +#define F_MI1_MDI_INVERT V_MI1_MDI_INVERT(1U) + +#define S_MI1_PREAMBLE_ENABLE 2 +#define V_MI1_PREAMBLE_ENABLE(x) ((x) << S_MI1_PREAMBLE_ENABLE) +#define F_MI1_PREAMBLE_ENABLE V_MI1_PREAMBLE_ENABLE(1U) + +#define S_MI1_SOF 3 +#define M_MI1_SOF 0x3 +#define V_MI1_SOF(x) ((x) << S_MI1_SOF) +#define G_MI1_SOF(x) (((x) >> S_MI1_SOF) & M_MI1_SOF) + +#define S_MI1_CLK_DIV 5 +#define M_MI1_CLK_DIV 0xff +#define V_MI1_CLK_DIV(x) ((x) << S_MI1_CLK_DIV) +#define G_MI1_CLK_DIV(x) (((x) >> S_MI1_CLK_DIV) & M_MI1_CLK_DIV) + +#define A_ELMER0_PORT0_MI1_ADDR 0x400004 + +#define S_MI1_REG_ADDR 0 +#define M_MI1_REG_ADDR 0x1f +#define V_MI1_REG_ADDR(x) ((x) << S_MI1_REG_ADDR) +#define G_MI1_REG_ADDR(x) (((x) >> S_MI1_REG_ADDR) & M_MI1_REG_ADDR) + +#define S_MI1_PHY_ADDR 5 +#define M_MI1_PHY_ADDR 0x1f +#define V_MI1_PHY_ADDR(x) ((x) << S_MI1_PHY_ADDR) +#define G_MI1_PHY_ADDR(x) (((x) >> S_MI1_PHY_ADDR) & M_MI1_PHY_ADDR) + +#define A_ELMER0_PORT0_MI1_DATA 0x400008 + +#define S_MI1_DATA 0 +#define M_MI1_DATA 0xffff +#define V_MI1_DATA(x) ((x) << S_MI1_DATA) +#define G_MI1_DATA(x) (((x) >> S_MI1_DATA) & M_MI1_DATA) + +#define A_ELMER0_PORT0_MI1_OP 0x40000c + +#define S_MI1_OP 0 +#define M_MI1_OP 0x3 +#define V_MI1_OP(x) ((x) << S_MI1_OP) +#define G_MI1_OP(x) (((x) >> S_MI1_OP) & M_MI1_OP) + +#define S_MI1_ADDR_AUTOINC 2 +#define V_MI1_ADDR_AUTOINC(x) ((x) << S_MI1_ADDR_AUTOINC) +#define F_MI1_ADDR_AUTOINC V_MI1_ADDR_AUTOINC(1U) + +#define S_MI1_OP_BUSY 31 +#define V_MI1_OP_BUSY(x) ((x) << S_MI1_OP_BUSY) +#define F_MI1_OP_BUSY V_MI1_OP_BUSY(1U) + +#define A_ELMER0_PORT1_MI1_CFG 0x500000 +#define A_ELMER0_PORT1_MI1_ADDR 0x500004 +#define A_ELMER0_PORT1_MI1_DATA 0x500008 +#define A_ELMER0_PORT1_MI1_OP 0x50000c +#define A_ELMER0_PORT2_MI1_CFG 0x600000 +#define A_ELMER0_PORT2_MI1_ADDR 0x600004 +#define A_ELMER0_PORT2_MI1_DATA 0x600008 +#define A_ELMER0_PORT2_MI1_OP 0x60000c +#define A_ELMER0_PORT3_MI1_CFG 0x700000 +#define A_ELMER0_PORT3_MI1_ADDR 0x700004 +#define A_ELMER0_PORT3_MI1_DATA 0x700008 +#define A_ELMER0_PORT3_MI1_OP 0x70000c + +/* Simple bit definition for GPI and GP0 registers. */ +#define ELMER0_GP_BIT0 0x0001 +#define ELMER0_GP_BIT1 0x0002 +#define ELMER0_GP_BIT2 0x0004 +#define ELMER0_GP_BIT3 0x0008 +#define ELMER0_GP_BIT4 0x0010 +#define ELMER0_GP_BIT5 0x0020 +#define ELMER0_GP_BIT6 0x0040 +#define ELMER0_GP_BIT7 0x0080 +#define ELMER0_GP_BIT8 0x0100 +#define ELMER0_GP_BIT9 0x0200 +#define ELMER0_GP_BIT10 0x0400 +#define ELMER0_GP_BIT11 0x0800 +#define ELMER0_GP_BIT12 0x1000 +#define ELMER0_GP_BIT13 0x2000 +#define ELMER0_GP_BIT14 0x4000 +#define ELMER0_GP_BIT15 0x8000 +#define ELMER0_GP_BIT16 0x10000 +#define ELMER0_GP_BIT17 0x20000 +#define ELMER0_GP_BIT18 0x40000 +#define ELMER0_GP_BIT19 0x80000 + +#define MI1_OP_DIRECT_WRITE 1 +#define MI1_OP_DIRECT_READ 2 + +#define MI1_OP_INDIRECT_ADDRESS 0 +#define MI1_OP_INDIRECT_WRITE 1 +#define MI1_OP_INDIRECT_READ_INC 2 +#define MI1_OP_INDIRECT_READ 3 + +#endif /* _CXGB_ELMER0_H_ */ + diff --git a/drivers/net/ethernet/chelsio/cxgb/espi.c b/drivers/net/ethernet/chelsio/cxgb/espi.c new file mode 100644 index 000000000000..639ff1955739 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb/espi.c @@ -0,0 +1,373 @@ +/***************************************************************************** + * * + * File: espi.c * + * $Revision: 1.14 $ * + * $Date: 2005/05/14 00:59:32 $ * + * Description: * + * Ethernet SPI functionality. * + * part of the Chelsio 10Gb Ethernet Driver. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License, version 2, as * + * published by the Free Software Foundation. * + * * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * + * * + * http://www.chelsio.com * + * * + * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * + * All rights reserved. * + * * + * Maintainers: maintainers@chelsio.com * + * * + * Authors: Dimitrios Michailidis * + * Tina Yang * + * Felix Marti * + * Scott Bardone * + * Kurt Ottaway * + * Frank DiMambro * + * * + * History: * + * * + ****************************************************************************/ + +#include "common.h" +#include "regs.h" +#include "espi.h" + +struct peespi { + adapter_t *adapter; + struct espi_intr_counts intr_cnt; + u32 misc_ctrl; + spinlock_t lock; +}; + +#define ESPI_INTR_MASK (F_DIP4ERR | F_RXDROP | F_TXDROP | F_RXOVERFLOW | \ + F_RAMPARITYERR | F_DIP2PARITYERR) +#define MON_MASK (V_MONITORED_PORT_NUM(3) | F_MONITORED_DIRECTION \ + | F_MONITORED_INTERFACE) + +#define TRICN_CNFG 14 +#define TRICN_CMD_READ 0x11 +#define TRICN_CMD_WRITE 0x21 +#define TRICN_CMD_ATTEMPTS 10 + +static int tricn_write(adapter_t *adapter, int bundle_addr, int module_addr, + int ch_addr, int reg_offset, u32 wr_data) +{ + int busy, attempts = TRICN_CMD_ATTEMPTS; + + writel(V_WRITE_DATA(wr_data) | + V_REGISTER_OFFSET(reg_offset) | + V_CHANNEL_ADDR(ch_addr) | V_MODULE_ADDR(module_addr) | + V_BUNDLE_ADDR(bundle_addr) | + V_SPI4_COMMAND(TRICN_CMD_WRITE), + adapter->regs + A_ESPI_CMD_ADDR); + writel(0, adapter->regs + A_ESPI_GOSTAT); + + do { + busy = readl(adapter->regs + A_ESPI_GOSTAT) & F_ESPI_CMD_BUSY; + } while (busy && --attempts); + + if (busy) + pr_err("%s: TRICN write timed out\n", adapter->name); + + return busy; +} + +static int tricn_init(adapter_t *adapter) +{ + int i, sme = 1; + + if (!(readl(adapter->regs + A_ESPI_RX_RESET) & F_RX_CLK_STATUS)) { + pr_err("%s: ESPI clock not ready\n", adapter->name); + return -1; + } + + writel(F_ESPI_RX_CORE_RST, adapter->regs + A_ESPI_RX_RESET); + + if (sme) { + tricn_write(adapter, 0, 0, 0, TRICN_CNFG, 0x81); + tricn_write(adapter, 0, 1, 0, TRICN_CNFG, 0x81); + tricn_write(adapter, 0, 2, 0, TRICN_CNFG, 0x81); + } + for (i = 1; i <= 8; i++) + tricn_write(adapter, 0, 0, i, TRICN_CNFG, 0xf1); + for (i = 1; i <= 2; i++) + tricn_write(adapter, 0, 1, i, TRICN_CNFG, 0xf1); + for (i = 1; i <= 3; i++) + tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xe1); + tricn_write(adapter, 0, 2, 4, TRICN_CNFG, 0xf1); + tricn_write(adapter, 0, 2, 5, TRICN_CNFG, 0xe1); + tricn_write(adapter, 0, 2, 6, TRICN_CNFG, 0xf1); + tricn_write(adapter, 0, 2, 7, TRICN_CNFG, 0x80); + tricn_write(adapter, 0, 2, 8, TRICN_CNFG, 0xf1); + + writel(F_ESPI_RX_CORE_RST | F_ESPI_RX_LNK_RST, + adapter->regs + A_ESPI_RX_RESET); + + return 0; +} + +void t1_espi_intr_enable(struct peespi *espi) +{ + u32 enable, pl_intr = readl(espi->adapter->regs + A_PL_ENABLE); + + /* + * Cannot enable ESPI interrupts on T1B because HW asserts the + * interrupt incorrectly, namely the driver gets ESPI interrupts + * but no data is actually dropped (can verify this reading the ESPI + * drop registers). Also, once the ESPI interrupt is asserted it + * cannot be cleared (HW bug). + */ + enable = t1_is_T1B(espi->adapter) ? 0 : ESPI_INTR_MASK; + writel(enable, espi->adapter->regs + A_ESPI_INTR_ENABLE); + writel(pl_intr | F_PL_INTR_ESPI, espi->adapter->regs + A_PL_ENABLE); +} + +void t1_espi_intr_clear(struct peespi *espi) +{ + readl(espi->adapter->regs + A_ESPI_DIP2_ERR_COUNT); + writel(0xffffffff, espi->adapter->regs + A_ESPI_INTR_STATUS); + writel(F_PL_INTR_ESPI, espi->adapter->regs + A_PL_CAUSE); +} + +void t1_espi_intr_disable(struct peespi *espi) +{ + u32 pl_intr = readl(espi->adapter->regs + A_PL_ENABLE); + + writel(0, espi->adapter->regs + A_ESPI_INTR_ENABLE); + writel(pl_intr & ~F_PL_INTR_ESPI, espi->adapter->regs + A_PL_ENABLE); +} + +int t1_espi_intr_handler(struct peespi *espi) +{ + u32 status = readl(espi->adapter->regs + A_ESPI_INTR_STATUS); + + if (status & F_DIP4ERR) + espi->intr_cnt.DIP4_err++; + if (status & F_RXDROP) + espi->intr_cnt.rx_drops++; + if (status & F_TXDROP) + espi->intr_cnt.tx_drops++; + if (status & F_RXOVERFLOW) + espi->intr_cnt.rx_ovflw++; + if (status & F_RAMPARITYERR) + espi->intr_cnt.parity_err++; + if (status & F_DIP2PARITYERR) { + espi->intr_cnt.DIP2_parity_err++; + + /* + * Must read the error count to clear the interrupt + * that it causes. + */ + readl(espi->adapter->regs + A_ESPI_DIP2_ERR_COUNT); + } + + /* + * For T1B we need to write 1 to clear ESPI interrupts. For T2+ we + * write the status as is. + */ + if (status && t1_is_T1B(espi->adapter)) + status = 1; + writel(status, espi->adapter->regs + A_ESPI_INTR_STATUS); + return 0; +} + +const struct espi_intr_counts *t1_espi_get_intr_counts(struct peespi *espi) +{ + return &espi->intr_cnt; +} + +static void espi_setup_for_pm3393(adapter_t *adapter) +{ + u32 wmark = t1_is_T1B(adapter) ? 0x4000 : 0x3200; + + writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0); + writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN1); + writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2); + writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN3); + writel(0x100, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK); + writel(wmark, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK); + writel(3, adapter->regs + A_ESPI_CALENDAR_LENGTH); + writel(0x08000008, adapter->regs + A_ESPI_TRAIN); + writel(V_RX_NPORTS(1) | V_TX_NPORTS(1), adapter->regs + A_PORT_CONFIG); +} + +static void espi_setup_for_vsc7321(adapter_t *adapter) +{ + writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0); + writel(0x1f401f4, adapter->regs + A_ESPI_SCH_TOKEN1); + writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2); + writel(0xa00, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK); + writel(0x1ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK); + writel(1, adapter->regs + A_ESPI_CALENDAR_LENGTH); + writel(V_RX_NPORTS(4) | V_TX_NPORTS(4), adapter->regs + A_PORT_CONFIG); + + writel(0x08000008, adapter->regs + A_ESPI_TRAIN); +} + +/* + * Note that T1B requires at least 2 ports for IXF1010 due to a HW bug. + */ +static void espi_setup_for_ixf1010(adapter_t *adapter, int nports) +{ + writel(1, adapter->regs + A_ESPI_CALENDAR_LENGTH); + if (nports == 4) { + if (is_T2(adapter)) { + writel(0xf00, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK); + writel(0x3c0, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK); + } else { + writel(0x7ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK); + writel(0x1ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK); + } + } else { + writel(0x1fff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK); + writel(0x7ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK); + } + writel(V_RX_NPORTS(nports) | V_TX_NPORTS(nports), adapter->regs + A_PORT_CONFIG); + +} + +int t1_espi_init(struct peespi *espi, int mac_type, int nports) +{ + u32 status_enable_extra = 0; + adapter_t *adapter = espi->adapter; + + /* Disable ESPI training. MACs that can handle it enable it below. */ + writel(0, adapter->regs + A_ESPI_TRAIN); + + if (is_T2(adapter)) { + writel(V_OUT_OF_SYNC_COUNT(4) | + V_DIP2_PARITY_ERR_THRES(3) | + V_DIP4_THRES(1), adapter->regs + A_ESPI_MISC_CONTROL); + writel(nports == 4 ? 0x200040 : 0x1000080, + adapter->regs + A_ESPI_MAXBURST1_MAXBURST2); + } else + writel(0x800100, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2); + + if (mac_type == CHBT_MAC_PM3393) + espi_setup_for_pm3393(adapter); + else if (mac_type == CHBT_MAC_VSC7321) + espi_setup_for_vsc7321(adapter); + else if (mac_type == CHBT_MAC_IXF1010) { + status_enable_extra = F_INTEL1010MODE; + espi_setup_for_ixf1010(adapter, nports); + } else + return -1; + + writel(status_enable_extra | F_RXSTATUSENABLE, + adapter->regs + A_ESPI_FIFO_STATUS_ENABLE); + + if (is_T2(adapter)) { + tricn_init(adapter); + /* + * Always position the control at the 1st port egress IN + * (sop,eop) counter to reduce PIOs for T/N210 workaround. + */ + espi->misc_ctrl = readl(adapter->regs + A_ESPI_MISC_CONTROL); + espi->misc_ctrl &= ~MON_MASK; + espi->misc_ctrl |= F_MONITORED_DIRECTION; + if (adapter->params.nports == 1) + espi->misc_ctrl |= F_MONITORED_INTERFACE; + writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); + spin_lock_init(&espi->lock); + } + + return 0; +} + +void t1_espi_destroy(struct peespi *espi) +{ + kfree(espi); +} + +struct peespi *t1_espi_create(adapter_t *adapter) +{ + struct peespi *espi = kzalloc(sizeof(*espi), GFP_KERNEL); + + if (espi) + espi->adapter = adapter; + return espi; +} + +#if 0 +void t1_espi_set_misc_ctrl(adapter_t *adapter, u32 val) +{ + struct peespi *espi = adapter->espi; + + if (!is_T2(adapter)) + return; + spin_lock(&espi->lock); + espi->misc_ctrl = (val & ~MON_MASK) | + (espi->misc_ctrl & MON_MASK); + writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); + spin_unlock(&espi->lock); +} +#endif /* 0 */ + +u32 t1_espi_get_mon(adapter_t *adapter, u32 addr, u8 wait) +{ + struct peespi *espi = adapter->espi; + u32 sel; + + if (!is_T2(adapter)) + return 0; + + sel = V_MONITORED_PORT_NUM((addr & 0x3c) >> 2); + if (!wait) { + if (!spin_trylock(&espi->lock)) + return 0; + } else + spin_lock(&espi->lock); + + if ((sel != (espi->misc_ctrl & MON_MASK))) { + writel(((espi->misc_ctrl & ~MON_MASK) | sel), + adapter->regs + A_ESPI_MISC_CONTROL); + sel = readl(adapter->regs + A_ESPI_SCH_TOKEN3); + writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); + } else + sel = readl(adapter->regs + A_ESPI_SCH_TOKEN3); + spin_unlock(&espi->lock); + return sel; +} + +/* + * This function is for T204 only. + * compare with t1_espi_get_mon(), it reads espiInTxSop[0 ~ 3] in + * one shot, since there is no per port counter on the out side. + */ +int t1_espi_get_mon_t204(adapter_t *adapter, u32 *valp, u8 wait) +{ + struct peespi *espi = adapter->espi; + u8 i, nport = (u8)adapter->params.nports; + + if (!wait) { + if (!spin_trylock(&espi->lock)) + return -1; + } else + spin_lock(&espi->lock); + + if ((espi->misc_ctrl & MON_MASK) != F_MONITORED_DIRECTION) { + espi->misc_ctrl = (espi->misc_ctrl & ~MON_MASK) | + F_MONITORED_DIRECTION; + writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); + } + for (i = 0 ; i < nport; i++, valp++) { + if (i) { + writel(espi->misc_ctrl | V_MONITORED_PORT_NUM(i), + adapter->regs + A_ESPI_MISC_CONTROL); + } + *valp = readl(adapter->regs + A_ESPI_SCH_TOKEN3); + } + + writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); + spin_unlock(&espi->lock); + return 0; +} diff --git a/drivers/net/ethernet/chelsio/cxgb/espi.h b/drivers/net/ethernet/chelsio/cxgb/espi.h new file mode 100644 index 000000000000..5694aad4fbc0 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb/espi.h @@ -0,0 +1,68 @@ +/***************************************************************************** + * * + * File: espi.h * + * $Revision: 1.7 $ * + * $Date: 2005/06/21 18:29:47 $ * + * Description: * + * part of the Chelsio 10Gb Ethernet Driver. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License, version 2, as * + * published by the Free Software Foundation. * + * * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * + * * + * http://www.chelsio.com * + * * + * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * + * All rights reserved. * + * * + * Maintainers: maintainers@chelsio.com * + * * + * Authors: Dimitrios Michailidis * + * Tina Yang * + * Felix Marti * + * Scott Bardone * + * Kurt Ottaway * + * Frank DiMambro * + * * + * History: * + * * + ****************************************************************************/ + +#ifndef _CXGB_ESPI_H_ +#define _CXGB_ESPI_H_ + +#include "common.h" + +struct espi_intr_counts { + unsigned int DIP4_err; + unsigned int rx_drops; + unsigned int tx_drops; + unsigned int rx_ovflw; + unsigned int parity_err; + unsigned int DIP2_parity_err; +}; + +struct peespi; + +struct peespi *t1_espi_create(adapter_t *adapter); +void t1_espi_destroy(struct peespi *espi); +int t1_espi_init(struct peespi *espi, int mac_type, int nports); + +void t1_espi_intr_enable(struct peespi *); +void t1_espi_intr_clear(struct peespi *); +void t1_espi_intr_disable(struct peespi *); +int t1_espi_intr_handler(struct peespi *); +const struct espi_intr_counts *t1_espi_get_intr_counts(struct peespi *espi); + +u32 t1_espi_get_mon(adapter_t *adapter, u32 addr, u8 wait); +int t1_espi_get_mon_t204(adapter_t *, u32 *, u8); + +#endif /* _CXGB_ESPI_H_ */ diff --git a/drivers/net/ethernet/chelsio/cxgb/fpga_defs.h b/drivers/net/ethernet/chelsio/cxgb/fpga_defs.h new file mode 100644 index 000000000000..ccdb2bc9ae98 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb/fpga_defs.h @@ -0,0 +1,232 @@ +/* $Date: 2005/03/07 23:59:05 $ $RCSfile: fpga_defs.h,v $ $Revision: 1.4 $ */ + +/* + * FPGA specific definitions + */ + +#ifndef __CHELSIO_FPGA_DEFS_H__ +#define __CHELSIO_FPGA_DEFS_H__ + +#define FPGA_PCIX_ADDR_VERSION 0xA08 +#define FPGA_PCIX_ADDR_STAT 0xA0C + +/* FPGA master interrupt Cause/Enable bits */ +#define FPGA_PCIX_INTERRUPT_SGE_ERROR 0x1 +#define FPGA_PCIX_INTERRUPT_SGE_DATA 0x2 +#define FPGA_PCIX_INTERRUPT_TP 0x4 +#define FPGA_PCIX_INTERRUPT_MC3 0x8 +#define FPGA_PCIX_INTERRUPT_GMAC 0x10 +#define FPGA_PCIX_INTERRUPT_PCIX 0x20 + +/* TP interrupt register addresses */ +#define FPGA_TP_ADDR_INTERRUPT_ENABLE 0xA10 +#define FPGA_TP_ADDR_INTERRUPT_CAUSE 0xA14 +#define FPGA_TP_ADDR_VERSION 0xA18 + +/* TP interrupt Cause/Enable bits */ +#define FPGA_TP_INTERRUPT_MC4 0x1 +#define FPGA_TP_INTERRUPT_MC5 0x2 + +/* + * PM interrupt register addresses + */ +#define FPGA_MC3_REG_INTRENABLE 0xA20 +#define FPGA_MC3_REG_INTRCAUSE 0xA24 +#define FPGA_MC3_REG_VERSION 0xA28 + +/* + * GMAC interrupt register addresses + */ +#define FPGA_GMAC_ADDR_INTERRUPT_ENABLE 0xA30 +#define FPGA_GMAC_ADDR_INTERRUPT_CAUSE 0xA34 +#define FPGA_GMAC_ADDR_VERSION 0xA38 + +/* GMAC Cause/Enable bits */ +#define FPGA_GMAC_INTERRUPT_PORT0 0x1 +#define FPGA_GMAC_INTERRUPT_PORT1 0x2 +#define FPGA_GMAC_INTERRUPT_PORT2 0x4 +#define FPGA_GMAC_INTERRUPT_PORT3 0x8 + +/* MI0 registers */ +#define A_MI0_CLK 0xb00 + +#define S_MI0_CLK_DIV 0 +#define M_MI0_CLK_DIV 0xff +#define V_MI0_CLK_DIV(x) ((x) << S_MI0_CLK_DIV) +#define G_MI0_CLK_DIV(x) (((x) >> S_MI0_CLK_DIV) & M_MI0_CLK_DIV) + +#define S_MI0_CLK_CNT 8 +#define M_MI0_CLK_CNT 0xff +#define V_MI0_CLK_CNT(x) ((x) << S_MI0_CLK_CNT) +#define G_MI0_CLK_CNT(x) (((x) >> S_MI0_CLK_CNT) & M_MI0_CLK_CNT) + +#define A_MI0_CSR 0xb04 + +#define S_MI0_CSR_POLL 0 +#define V_MI0_CSR_POLL(x) ((x) << S_MI0_CSR_POLL) +#define F_MI0_CSR_POLL V_MI0_CSR_POLL(1U) + +#define S_MI0_PREAMBLE 1 +#define V_MI0_PREAMBLE(x) ((x) << S_MI0_PREAMBLE) +#define F_MI0_PREAMBLE V_MI0_PREAMBLE(1U) + +#define S_MI0_INTR_ENABLE 2 +#define V_MI0_INTR_ENABLE(x) ((x) << S_MI0_INTR_ENABLE) +#define F_MI0_INTR_ENABLE V_MI0_INTR_ENABLE(1U) + +#define S_MI0_BUSY 3 +#define V_MI0_BUSY(x) ((x) << S_MI0_BUSY) +#define F_MI0_BUSY V_MI0_BUSY(1U) + +#define S_MI0_MDIO 4 +#define V_MI0_MDIO(x) ((x) << S_MI0_MDIO) +#define F_MI0_MDIO V_MI0_MDIO(1U) + +#define A_MI0_ADDR 0xb08 + +#define S_MI0_PHY_REG_ADDR 0 +#define M_MI0_PHY_REG_ADDR 0x1f +#define V_MI0_PHY_REG_ADDR(x) ((x) << S_MI0_PHY_REG_ADDR) +#define G_MI0_PHY_REG_ADDR(x) (((x) >> S_MI0_PHY_REG_ADDR) & M_MI0_PHY_REG_ADDR) + +#define S_MI0_PHY_ADDR 5 +#define M_MI0_PHY_ADDR 0x1f +#define V_MI0_PHY_ADDR(x) ((x) << S_MI0_PHY_ADDR) +#define G_MI0_PHY_ADDR(x) (((x) >> S_MI0_PHY_ADDR) & M_MI0_PHY_ADDR) + +#define A_MI0_DATA_EXT 0xb0c +#define A_MI0_DATA_INT 0xb10 + +/* GMAC registers */ +#define A_GMAC_MACID_LO 0x28 +#define A_GMAC_MACID_HI 0x2c +#define A_GMAC_CSR 0x30 + +#define S_INTERFACE 0 +#define M_INTERFACE 0x3 +#define V_INTERFACE(x) ((x) << S_INTERFACE) +#define G_INTERFACE(x) (((x) >> S_INTERFACE) & M_INTERFACE) + +#define S_MAC_TX_ENABLE 2 +#define V_MAC_TX_ENABLE(x) ((x) << S_MAC_TX_ENABLE) +#define F_MAC_TX_ENABLE V_MAC_TX_ENABLE(1U) + +#define S_MAC_RX_ENABLE 3 +#define V_MAC_RX_ENABLE(x) ((x) << S_MAC_RX_ENABLE) +#define F_MAC_RX_ENABLE V_MAC_RX_ENABLE(1U) + +#define S_MAC_LB_ENABLE 4 +#define V_MAC_LB_ENABLE(x) ((x) << S_MAC_LB_ENABLE) +#define F_MAC_LB_ENABLE V_MAC_LB_ENABLE(1U) + +#define S_MAC_SPEED 5 +#define M_MAC_SPEED 0x3 +#define V_MAC_SPEED(x) ((x) << S_MAC_SPEED) +#define G_MAC_SPEED(x) (((x) >> S_MAC_SPEED) & M_MAC_SPEED) + +#define S_MAC_HD_FC_ENABLE 7 +#define V_MAC_HD_FC_ENABLE(x) ((x) << S_MAC_HD_FC_ENABLE) +#define F_MAC_HD_FC_ENABLE V_MAC_HD_FC_ENABLE(1U) + +#define S_MAC_HALF_DUPLEX 8 +#define V_MAC_HALF_DUPLEX(x) ((x) << S_MAC_HALF_DUPLEX) +#define F_MAC_HALF_DUPLEX V_MAC_HALF_DUPLEX(1U) + +#define S_MAC_PROMISC 9 +#define V_MAC_PROMISC(x) ((x) << S_MAC_PROMISC) +#define F_MAC_PROMISC V_MAC_PROMISC(1U) + +#define S_MAC_MC_ENABLE 10 +#define V_MAC_MC_ENABLE(x) ((x) << S_MAC_MC_ENABLE) +#define F_MAC_MC_ENABLE V_MAC_MC_ENABLE(1U) + +#define S_MAC_RESET 11 +#define V_MAC_RESET(x) ((x) << S_MAC_RESET) +#define F_MAC_RESET V_MAC_RESET(1U) + +#define S_MAC_RX_PAUSE_ENABLE 12 +#define V_MAC_RX_PAUSE_ENABLE(x) ((x) << S_MAC_RX_PAUSE_ENABLE) +#define F_MAC_RX_PAUSE_ENABLE V_MAC_RX_PAUSE_ENABLE(1U) + +#define S_MAC_TX_PAUSE_ENABLE 13 +#define V_MAC_TX_PAUSE_ENABLE(x) ((x) << S_MAC_TX_PAUSE_ENABLE) +#define F_MAC_TX_PAUSE_ENABLE V_MAC_TX_PAUSE_ENABLE(1U) + +#define S_MAC_LWM_ENABLE 14 +#define V_MAC_LWM_ENABLE(x) ((x) << S_MAC_LWM_ENABLE) +#define F_MAC_LWM_ENABLE V_MAC_LWM_ENABLE(1U) + +#define S_MAC_MAGIC_PKT_ENABLE 15 +#define V_MAC_MAGIC_PKT_ENABLE(x) ((x) << S_MAC_MAGIC_PKT_ENABLE) +#define F_MAC_MAGIC_PKT_ENABLE V_MAC_MAGIC_PKT_ENABLE(1U) + +#define S_MAC_ISL_ENABLE 16 +#define V_MAC_ISL_ENABLE(x) ((x) << S_MAC_ISL_ENABLE) +#define F_MAC_ISL_ENABLE V_MAC_ISL_ENABLE(1U) + +#define S_MAC_JUMBO_ENABLE 17 +#define V_MAC_JUMBO_ENABLE(x) ((x) << S_MAC_JUMBO_ENABLE) +#define F_MAC_JUMBO_ENABLE V_MAC_JUMBO_ENABLE(1U) + +#define S_MAC_RX_PAD_ENABLE 18 +#define V_MAC_RX_PAD_ENABLE(x) ((x) << S_MAC_RX_PAD_ENABLE) +#define F_MAC_RX_PAD_ENABLE V_MAC_RX_PAD_ENABLE(1U) + +#define S_MAC_RX_CRC_ENABLE 19 +#define V_MAC_RX_CRC_ENABLE(x) ((x) << S_MAC_RX_CRC_ENABLE) +#define F_MAC_RX_CRC_ENABLE V_MAC_RX_CRC_ENABLE(1U) + +#define A_GMAC_IFS 0x34 + +#define S_MAC_IFS2 0 +#define M_MAC_IFS2 0x3f +#define V_MAC_IFS2(x) ((x) << S_MAC_IFS2) +#define G_MAC_IFS2(x) (((x) >> S_MAC_IFS2) & M_MAC_IFS2) + +#define S_MAC_IFS1 8 +#define M_MAC_IFS1 0x7f +#define V_MAC_IFS1(x) ((x) << S_MAC_IFS1) +#define G_MAC_IFS1(x) (((x) >> S_MAC_IFS1) & M_MAC_IFS1) + +#define A_GMAC_JUMBO_FRAME_LEN 0x38 +#define A_GMAC_LNK_DLY 0x3c +#define A_GMAC_PAUSETIME 0x40 +#define A_GMAC_MCAST_LO 0x44 +#define A_GMAC_MCAST_HI 0x48 +#define A_GMAC_MCAST_MASK_LO 0x4c +#define A_GMAC_MCAST_MASK_HI 0x50 +#define A_GMAC_RMT_CNT 0x54 +#define A_GMAC_RMT_DATA 0x58 +#define A_GMAC_BACKOFF_SEED 0x5c +#define A_GMAC_TXF_THRES 0x60 + +#define S_TXF_READ_THRESHOLD 0 +#define M_TXF_READ_THRESHOLD 0xff +#define V_TXF_READ_THRESHOLD(x) ((x) << S_TXF_READ_THRESHOLD) +#define G_TXF_READ_THRESHOLD(x) (((x) >> S_TXF_READ_THRESHOLD) & M_TXF_READ_THRESHOLD) + +#define S_TXF_WRITE_THRESHOLD 16 +#define M_TXF_WRITE_THRESHOLD 0xff +#define V_TXF_WRITE_THRESHOLD(x) ((x) << S_TXF_WRITE_THRESHOLD) +#define G_TXF_WRITE_THRESHOLD(x) (((x) >> S_TXF_WRITE_THRESHOLD) & M_TXF_WRITE_THRESHOLD) + +#define MAC_REG_BASE 0x600 +#define MAC_REG_ADDR(idx, reg) (MAC_REG_BASE + (idx) * 128 + (reg)) + +#define MAC_REG_IDLO(idx) MAC_REG_ADDR(idx, A_GMAC_MACID_LO) +#define MAC_REG_IDHI(idx) MAC_REG_ADDR(idx, A_GMAC_MACID_HI) +#define MAC_REG_CSR(idx) MAC_REG_ADDR(idx, A_GMAC_CSR) +#define MAC_REG_IFS(idx) MAC_REG_ADDR(idx, A_GMAC_IFS) +#define MAC_REG_LARGEFRAMELENGTH(idx) MAC_REG_ADDR(idx, A_GMAC_JUMBO_FRAME_LEN) +#define MAC_REG_LINKDLY(idx) MAC_REG_ADDR(idx, A_GMAC_LNK_DLY) +#define MAC_REG_PAUSETIME(idx) MAC_REG_ADDR(idx, A_GMAC_PAUSETIME) +#define MAC_REG_CASTLO(idx) MAC_REG_ADDR(idx, A_GMAC_MCAST_LO) +#define MAC_REG_MCASTHI(idx) MAC_REG_ADDR(idx, A_GMAC_MCAST_HI) +#define MAC_REG_CASTMASKLO(idx) MAC_REG_ADDR(idx, A_GMAC_MCAST_MASK_LO) +#define MAC_REG_MCASTMASKHI(idx) MAC_REG_ADDR(idx, A_GMAC_MCAST_MASK_HI) +#define MAC_REG_RMCNT(idx) MAC_REG_ADDR(idx, A_GMAC_RMT_CNT) +#define MAC_REG_RMDATA(idx) MAC_REG_ADDR(idx, A_GMAC_RMT_DATA) +#define MAC_REG_GMRANDBACKOFFSEED(idx) MAC_REG_ADDR(idx, A_GMAC_BACKOFF_SEED) +#define MAC_REG_TXFTHRESHOLDS(idx) MAC_REG_ADDR(idx, A_GMAC_TXF_THRES) + +#endif diff --git a/drivers/net/ethernet/chelsio/cxgb/gmac.h b/drivers/net/ethernet/chelsio/cxgb/gmac.h new file mode 100644 index 000000000000..d42337457cf7 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb/gmac.h @@ -0,0 +1,142 @@ +/***************************************************************************** + * * + * File: gmac.h * + * $Revision: 1.6 $ * + * $Date: 2005/06/21 18:29:47 $ * + * Description: * + * Generic MAC functionality. * + * part of the Chelsio 10Gb Ethernet Driver. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License, version 2, as * + * published by the Free Software Foundation. * + * * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * + * * + * http://www.chelsio.com * + * * + * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * + * All rights reserved. * + * * + * Maintainers: maintainers@chelsio.com * + * * + * Authors: Dimitrios Michailidis * + * Tina Yang * + * Felix Marti * + * Scott Bardone * + * Kurt Ottaway * + * Frank DiMambro * + * * + * History: * + * * + ****************************************************************************/ + +#ifndef _CXGB_GMAC_H_ +#define _CXGB_GMAC_H_ + +#include "common.h" + +enum { + MAC_STATS_UPDATE_FAST, + MAC_STATS_UPDATE_FULL +}; + +enum { + MAC_DIRECTION_RX = 1, + MAC_DIRECTION_TX = 2 +}; + +struct cmac_statistics { + /* Transmit */ + u64 TxOctetsOK; + u64 TxOctetsBad; + u64 TxUnicastFramesOK; + u64 TxMulticastFramesOK; + u64 TxBroadcastFramesOK; + u64 TxPauseFrames; + u64 TxFramesWithDeferredXmissions; + u64 TxLateCollisions; + u64 TxTotalCollisions; + u64 TxFramesAbortedDueToXSCollisions; + u64 TxUnderrun; + u64 TxLengthErrors; + u64 TxInternalMACXmitError; + u64 TxFramesWithExcessiveDeferral; + u64 TxFCSErrors; + u64 TxJumboFramesOK; + u64 TxJumboOctetsOK; + + /* Receive */ + u64 RxOctetsOK; + u64 RxOctetsBad; + u64 RxUnicastFramesOK; + u64 RxMulticastFramesOK; + u64 RxBroadcastFramesOK; + u64 RxPauseFrames; + u64 RxFCSErrors; + u64 RxAlignErrors; + u64 RxSymbolErrors; + u64 RxDataErrors; + u64 RxSequenceErrors; + u64 RxRuntErrors; + u64 RxJabberErrors; + u64 RxInternalMACRcvError; + u64 RxInRangeLengthErrors; + u64 RxOutOfRangeLengthField; + u64 RxFrameTooLongErrors; + u64 RxJumboFramesOK; + u64 RxJumboOctetsOK; +}; + +struct cmac_ops { + void (*destroy)(struct cmac *); + int (*reset)(struct cmac *); + int (*interrupt_enable)(struct cmac *); + int (*interrupt_disable)(struct cmac *); + int (*interrupt_clear)(struct cmac *); + int (*interrupt_handler)(struct cmac *); + + int (*enable)(struct cmac *, int); + int (*disable)(struct cmac *, int); + + int (*loopback_enable)(struct cmac *); + int (*loopback_disable)(struct cmac *); + + int (*set_mtu)(struct cmac *, int mtu); + int (*set_rx_mode)(struct cmac *, struct t1_rx_mode *rm); + + int (*set_speed_duplex_fc)(struct cmac *, int speed, int duplex, int fc); + int (*get_speed_duplex_fc)(struct cmac *, int *speed, int *duplex, + int *fc); + + const struct cmac_statistics *(*statistics_update)(struct cmac *, int); + + int (*macaddress_get)(struct cmac *, u8 mac_addr[6]); + int (*macaddress_set)(struct cmac *, u8 mac_addr[6]); +}; + +typedef struct _cmac_instance cmac_instance; + +struct cmac { + struct cmac_statistics stats; + adapter_t *adapter; + const struct cmac_ops *ops; + cmac_instance *instance; +}; + +struct gmac { + unsigned int stats_update_period; + struct cmac *(*create)(adapter_t *adapter, int index); + int (*reset)(adapter_t *); +}; + +extern const struct gmac t1_pm3393_ops; +extern const struct gmac t1_vsc7326_ops; + +#endif /* _CXGB_GMAC_H_ */ diff --git a/drivers/net/ethernet/chelsio/cxgb/mv88e1xxx.c b/drivers/net/ethernet/chelsio/cxgb/mv88e1xxx.c new file mode 100644 index 000000000000..71018a4fdf15 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb/mv88e1xxx.c @@ -0,0 +1,397 @@ +/* $Date: 2005/10/24 23:18:13 $ $RCSfile: mv88e1xxx.c,v $ $Revision: 1.49 $ */ +#include "common.h" +#include "mv88e1xxx.h" +#include "cphy.h" +#include "elmer0.h" + +/* MV88E1XXX MDI crossover register values */ +#define CROSSOVER_MDI 0 +#define CROSSOVER_MDIX 1 +#define CROSSOVER_AUTO 3 + +#define INTR_ENABLE_MASK 0x6CA0 + +/* + * Set the bits given by 'bitval' in PHY register 'reg'. + */ +static void mdio_set_bit(struct cphy *cphy, int reg, u32 bitval) +{ + u32 val; + + (void) simple_mdio_read(cphy, reg, &val); + (void) simple_mdio_write(cphy, reg, val | bitval); +} + +/* + * Clear the bits given by 'bitval' in PHY register 'reg'. + */ +static void mdio_clear_bit(struct cphy *cphy, int reg, u32 bitval) +{ + u32 val; + + (void) simple_mdio_read(cphy, reg, &val); + (void) simple_mdio_write(cphy, reg, val & ~bitval); +} + +/* + * NAME: phy_reset + * + * DESC: Reset the given PHY's port. NOTE: This is not a global + * chip reset. + * + * PARAMS: cphy - Pointer to PHY instance data. + * + * RETURN: 0 - Successful reset. + * -1 - Timeout. + */ +static int mv88e1xxx_reset(struct cphy *cphy, int wait) +{ + u32 ctl; + int time_out = 1000; + + mdio_set_bit(cphy, MII_BMCR, BMCR_RESET); + + do { + (void) simple_mdio_read(cphy, MII_BMCR, &ctl); + ctl &= BMCR_RESET; + if (ctl) + udelay(1); + } while (ctl && --time_out); + + return ctl ? -1 : 0; +} + +static int mv88e1xxx_interrupt_enable(struct cphy *cphy) +{ + /* Enable PHY interrupts. */ + (void) simple_mdio_write(cphy, MV88E1XXX_INTERRUPT_ENABLE_REGISTER, + INTR_ENABLE_MASK); + + /* Enable Marvell interrupts through Elmer0. */ + if (t1_is_asic(cphy->adapter)) { + u32 elmer; + + t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer); + elmer |= ELMER0_GP_BIT1; + if (is_T2(cphy->adapter)) + elmer |= ELMER0_GP_BIT2 | ELMER0_GP_BIT3 | ELMER0_GP_BIT4; + t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer); + } + return 0; +} + +static int mv88e1xxx_interrupt_disable(struct cphy *cphy) +{ + /* Disable all phy interrupts. */ + (void) simple_mdio_write(cphy, MV88E1XXX_INTERRUPT_ENABLE_REGISTER, 0); + + /* Disable Marvell interrupts through Elmer0. */ + if (t1_is_asic(cphy->adapter)) { + u32 elmer; + + t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer); + elmer &= ~ELMER0_GP_BIT1; + if (is_T2(cphy->adapter)) + elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4); + t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer); + } + return 0; +} + +static int mv88e1xxx_interrupt_clear(struct cphy *cphy) +{ + u32 elmer; + + /* Clear PHY interrupts by reading the register. */ + (void) simple_mdio_read(cphy, + MV88E1XXX_INTERRUPT_STATUS_REGISTER, &elmer); + + /* Clear Marvell interrupts through Elmer0. */ + if (t1_is_asic(cphy->adapter)) { + t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer); + elmer |= ELMER0_GP_BIT1; + if (is_T2(cphy->adapter)) + elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4; + t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer); + } + return 0; +} + +/* + * Set the PHY speed and duplex. This also disables auto-negotiation, except + * for 1Gb/s, where auto-negotiation is mandatory. + */ +static int mv88e1xxx_set_speed_duplex(struct cphy *phy, int speed, int duplex) +{ + u32 ctl; + + (void) simple_mdio_read(phy, MII_BMCR, &ctl); + if (speed >= 0) { + ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); + if (speed == SPEED_100) + ctl |= BMCR_SPEED100; + else if (speed == SPEED_1000) + ctl |= BMCR_SPEED1000; + } + if (duplex >= 0) { + ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE); + if (duplex == DUPLEX_FULL) + ctl |= BMCR_FULLDPLX; + } + if (ctl & BMCR_SPEED1000) /* auto-negotiation required for 1Gb/s */ + ctl |= BMCR_ANENABLE; + (void) simple_mdio_write(phy, MII_BMCR, ctl); + return 0; +} + +static int mv88e1xxx_crossover_set(struct cphy *cphy, int crossover) +{ + u32 data32; + + (void) simple_mdio_read(cphy, + MV88E1XXX_SPECIFIC_CNTRL_REGISTER, &data32); + data32 &= ~V_PSCR_MDI_XOVER_MODE(M_PSCR_MDI_XOVER_MODE); + data32 |= V_PSCR_MDI_XOVER_MODE(crossover); + (void) simple_mdio_write(cphy, + MV88E1XXX_SPECIFIC_CNTRL_REGISTER, data32); + return 0; +} + +static int mv88e1xxx_autoneg_enable(struct cphy *cphy) +{ + u32 ctl; + + (void) mv88e1xxx_crossover_set(cphy, CROSSOVER_AUTO); + + (void) simple_mdio_read(cphy, MII_BMCR, &ctl); + /* restart autoneg for change to take effect */ + ctl |= BMCR_ANENABLE | BMCR_ANRESTART; + (void) simple_mdio_write(cphy, MII_BMCR, ctl); + return 0; +} + +static int mv88e1xxx_autoneg_disable(struct cphy *cphy) +{ + u32 ctl; + + /* + * Crossover *must* be set to manual in order to disable auto-neg. + * The Alaska FAQs document highlights this point. + */ + (void) mv88e1xxx_crossover_set(cphy, CROSSOVER_MDI); + + /* + * Must include autoneg reset when disabling auto-neg. This + * is described in the Alaska FAQ document. + */ + (void) simple_mdio_read(cphy, MII_BMCR, &ctl); + ctl &= ~BMCR_ANENABLE; + (void) simple_mdio_write(cphy, MII_BMCR, ctl | BMCR_ANRESTART); + return 0; +} + +static int mv88e1xxx_autoneg_restart(struct cphy *cphy) +{ + mdio_set_bit(cphy, MII_BMCR, BMCR_ANRESTART); + return 0; +} + +static int mv88e1xxx_advertise(struct cphy *phy, unsigned int advertise_map) +{ + u32 val = 0; + + if (advertise_map & + (ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) { + (void) simple_mdio_read(phy, MII_GBCR, &val); + val &= ~(GBCR_ADV_1000HALF | GBCR_ADV_1000FULL); + if (advertise_map & ADVERTISED_1000baseT_Half) + val |= GBCR_ADV_1000HALF; + if (advertise_map & ADVERTISED_1000baseT_Full) + val |= GBCR_ADV_1000FULL; + } + (void) simple_mdio_write(phy, MII_GBCR, val); + + val = 1; + if (advertise_map & ADVERTISED_10baseT_Half) + val |= ADVERTISE_10HALF; + if (advertise_map & ADVERTISED_10baseT_Full) + val |= ADVERTISE_10FULL; + if (advertise_map & ADVERTISED_100baseT_Half) + val |= ADVERTISE_100HALF; + if (advertise_map & ADVERTISED_100baseT_Full) + val |= ADVERTISE_100FULL; + if (advertise_map & ADVERTISED_PAUSE) + val |= ADVERTISE_PAUSE; + if (advertise_map & ADVERTISED_ASYM_PAUSE) + val |= ADVERTISE_PAUSE_ASYM; + (void) simple_mdio_write(phy, MII_ADVERTISE, val); + return 0; +} + +static int mv88e1xxx_set_loopback(struct cphy *cphy, int on) +{ + if (on) + mdio_set_bit(cphy, MII_BMCR, BMCR_LOOPBACK); + else + mdio_clear_bit(cphy, MII_BMCR, BMCR_LOOPBACK); + return 0; +} + +static int mv88e1xxx_get_link_status(struct cphy *cphy, int *link_ok, + int *speed, int *duplex, int *fc) +{ + u32 status; + int sp = -1, dplx = -1, pause = 0; + + (void) simple_mdio_read(cphy, + MV88E1XXX_SPECIFIC_STATUS_REGISTER, &status); + if ((status & V_PSSR_STATUS_RESOLVED) != 0) { + if (status & V_PSSR_RX_PAUSE) + pause |= PAUSE_RX; + if (status & V_PSSR_TX_PAUSE) + pause |= PAUSE_TX; + dplx = (status & V_PSSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF; + sp = G_PSSR_SPEED(status); + if (sp == 0) + sp = SPEED_10; + else if (sp == 1) + sp = SPEED_100; + else + sp = SPEED_1000; + } + if (link_ok) + *link_ok = (status & V_PSSR_LINK) != 0; + if (speed) + *speed = sp; + if (duplex) + *duplex = dplx; + if (fc) + *fc = pause; + return 0; +} + +static int mv88e1xxx_downshift_set(struct cphy *cphy, int downshift_enable) +{ + u32 val; + + (void) simple_mdio_read(cphy, + MV88E1XXX_EXT_PHY_SPECIFIC_CNTRL_REGISTER, &val); + + /* + * Set the downshift counter to 2 so we try to establish Gb link + * twice before downshifting. + */ + val &= ~(V_DOWNSHIFT_ENABLE | V_DOWNSHIFT_CNT(M_DOWNSHIFT_CNT)); + + if (downshift_enable) + val |= V_DOWNSHIFT_ENABLE | V_DOWNSHIFT_CNT(2); + (void) simple_mdio_write(cphy, + MV88E1XXX_EXT_PHY_SPECIFIC_CNTRL_REGISTER, val); + return 0; +} + +static int mv88e1xxx_interrupt_handler(struct cphy *cphy) +{ + int cphy_cause = 0; + u32 status; + + /* + * Loop until cause reads zero. Need to handle bouncing interrupts. + */ + while (1) { + u32 cause; + + (void) simple_mdio_read(cphy, + MV88E1XXX_INTERRUPT_STATUS_REGISTER, + &cause); + cause &= INTR_ENABLE_MASK; + if (!cause) + break; + + if (cause & MV88E1XXX_INTR_LINK_CHNG) { + (void) simple_mdio_read(cphy, + MV88E1XXX_SPECIFIC_STATUS_REGISTER, &status); + + if (status & MV88E1XXX_INTR_LINK_CHNG) + cphy->state |= PHY_LINK_UP; + else { + cphy->state &= ~PHY_LINK_UP; + if (cphy->state & PHY_AUTONEG_EN) + cphy->state &= ~PHY_AUTONEG_RDY; + cphy_cause |= cphy_cause_link_change; + } + } + + if (cause & MV88E1XXX_INTR_AUTONEG_DONE) + cphy->state |= PHY_AUTONEG_RDY; + + if ((cphy->state & (PHY_LINK_UP | PHY_AUTONEG_RDY)) == + (PHY_LINK_UP | PHY_AUTONEG_RDY)) + cphy_cause |= cphy_cause_link_change; + } + return cphy_cause; +} + +static void mv88e1xxx_destroy(struct cphy *cphy) +{ + kfree(cphy); +} + +static struct cphy_ops mv88e1xxx_ops = { + .destroy = mv88e1xxx_destroy, + .reset = mv88e1xxx_reset, + .interrupt_enable = mv88e1xxx_interrupt_enable, + .interrupt_disable = mv88e1xxx_interrupt_disable, + .interrupt_clear = mv88e1xxx_interrupt_clear, + .interrupt_handler = mv88e1xxx_interrupt_handler, + .autoneg_enable = mv88e1xxx_autoneg_enable, + .autoneg_disable = mv88e1xxx_autoneg_disable, + .autoneg_restart = mv88e1xxx_autoneg_restart, + .advertise = mv88e1xxx_advertise, + .set_loopback = mv88e1xxx_set_loopback, + .set_speed_duplex = mv88e1xxx_set_speed_duplex, + .get_link_status = mv88e1xxx_get_link_status, +}; + +static struct cphy *mv88e1xxx_phy_create(struct net_device *dev, int phy_addr, + const struct mdio_ops *mdio_ops) +{ + struct adapter *adapter = netdev_priv(dev); + struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL); + + if (!cphy) + return NULL; + + cphy_init(cphy, dev, phy_addr, &mv88e1xxx_ops, mdio_ops); + + /* Configure particular PHY's to run in a different mode. */ + if ((board_info(adapter)->caps & SUPPORTED_TP) && + board_info(adapter)->chip_phy == CHBT_PHY_88E1111) { + /* + * Configure the PHY transmitter as class A to reduce EMI. + */ + (void) simple_mdio_write(cphy, + MV88E1XXX_EXTENDED_ADDR_REGISTER, 0xB); + (void) simple_mdio_write(cphy, + MV88E1XXX_EXTENDED_REGISTER, 0x8004); + } + (void) mv88e1xxx_downshift_set(cphy, 1); /* Enable downshift */ + + /* LED */ + if (is_T2(adapter)) { + (void) simple_mdio_write(cphy, + MV88E1XXX_LED_CONTROL_REGISTER, 0x1); + } + + return cphy; +} + +static int mv88e1xxx_phy_reset(adapter_t* adapter) +{ + return 0; +} + +const struct gphy t1_mv88e1xxx_ops = { + .create = mv88e1xxx_phy_create, + .reset = mv88e1xxx_phy_reset +}; diff --git a/drivers/net/ethernet/chelsio/cxgb/mv88e1xxx.h b/drivers/net/ethernet/chelsio/cxgb/mv88e1xxx.h new file mode 100644 index 000000000000..967cc4286359 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb/mv88e1xxx.h @@ -0,0 +1,127 @@ +/* $Date: 2005/03/07 23:59:05 $ $RCSfile: mv88e1xxx.h,v $ $Revision: 1.13 $ */ +#ifndef CHELSIO_MV8E1XXX_H +#define CHELSIO_MV8E1XXX_H + +#ifndef BMCR_SPEED1000 +# define BMCR_SPEED1000 0x40 +#endif + +#ifndef ADVERTISE_PAUSE +# define ADVERTISE_PAUSE 0x400 +#endif +#ifndef ADVERTISE_PAUSE_ASYM +# define ADVERTISE_PAUSE_ASYM 0x800 +#endif + +/* Gigabit MII registers */ +#define MII_GBCR 9 /* 1000Base-T control register */ +#define MII_GBSR 10 /* 1000Base-T status register */ + +/* 1000Base-T control register fields */ +#define GBCR_ADV_1000HALF 0x100 +#define GBCR_ADV_1000FULL 0x200 +#define GBCR_PREFER_MASTER 0x400 +#define GBCR_MANUAL_AS_MASTER 0x800 +#define GBCR_MANUAL_CONFIG_ENABLE 0x1000 + +/* 1000Base-T status register fields */ +#define GBSR_LP_1000HALF 0x400 +#define GBSR_LP_1000FULL 0x800 +#define GBSR_REMOTE_OK 0x1000 +#define GBSR_LOCAL_OK 0x2000 +#define GBSR_LOCAL_MASTER 0x4000 +#define GBSR_MASTER_FAULT 0x8000 + +/* Marvell PHY interrupt status bits. */ +#define MV88E1XXX_INTR_JABBER 0x0001 +#define MV88E1XXX_INTR_POLARITY_CHNG 0x0002 +#define MV88E1XXX_INTR_ENG_DETECT_CHNG 0x0010 +#define MV88E1XXX_INTR_DOWNSHIFT 0x0020 +#define MV88E1XXX_INTR_MDI_XOVER_CHNG 0x0040 +#define MV88E1XXX_INTR_FIFO_OVER_UNDER 0x0080 +#define MV88E1XXX_INTR_FALSE_CARRIER 0x0100 +#define MV88E1XXX_INTR_SYMBOL_ERROR 0x0200 +#define MV88E1XXX_INTR_LINK_CHNG 0x0400 +#define MV88E1XXX_INTR_AUTONEG_DONE 0x0800 +#define MV88E1XXX_INTR_PAGE_RECV 0x1000 +#define MV88E1XXX_INTR_DUPLEX_CHNG 0x2000 +#define MV88E1XXX_INTR_SPEED_CHNG 0x4000 +#define MV88E1XXX_INTR_AUTONEG_ERR 0x8000 + +/* Marvell PHY specific registers. */ +#define MV88E1XXX_SPECIFIC_CNTRL_REGISTER 16 +#define MV88E1XXX_SPECIFIC_STATUS_REGISTER 17 +#define MV88E1XXX_INTERRUPT_ENABLE_REGISTER 18 +#define MV88E1XXX_INTERRUPT_STATUS_REGISTER 19 +#define MV88E1XXX_EXT_PHY_SPECIFIC_CNTRL_REGISTER 20 +#define MV88E1XXX_RECV_ERR_CNTR_REGISTER 21 +#define MV88E1XXX_RES_REGISTER 22 +#define MV88E1XXX_GLOBAL_STATUS_REGISTER 23 +#define MV88E1XXX_LED_CONTROL_REGISTER 24 +#define MV88E1XXX_MANUAL_LED_OVERRIDE_REGISTER 25 +#define MV88E1XXX_EXT_PHY_SPECIFIC_CNTRL_2_REGISTER 26 +#define MV88E1XXX_EXT_PHY_SPECIFIC_STATUS_REGISTER 27 +#define MV88E1XXX_VIRTUAL_CABLE_TESTER_REGISTER 28 +#define MV88E1XXX_EXTENDED_ADDR_REGISTER 29 +#define MV88E1XXX_EXTENDED_REGISTER 30 + +/* PHY specific control register fields */ +#define S_PSCR_MDI_XOVER_MODE 5 +#define M_PSCR_MDI_XOVER_MODE 0x3 +#define V_PSCR_MDI_XOVER_MODE(x) ((x) << S_PSCR_MDI_XOVER_MODE) +#define G_PSCR_MDI_XOVER_MODE(x) (((x) >> S_PSCR_MDI_XOVER_MODE) & M_PSCR_MDI_XOVER_MODE) + +/* Extended PHY specific control register fields */ +#define S_DOWNSHIFT_ENABLE 8 +#define V_DOWNSHIFT_ENABLE (1 << S_DOWNSHIFT_ENABLE) + +#define S_DOWNSHIFT_CNT 9 +#define M_DOWNSHIFT_CNT 0x7 +#define V_DOWNSHIFT_CNT(x) ((x) << S_DOWNSHIFT_CNT) +#define G_DOWNSHIFT_CNT(x) (((x) >> S_DOWNSHIFT_CNT) & M_DOWNSHIFT_CNT) + +/* PHY specific status register fields */ +#define S_PSSR_JABBER 0 +#define V_PSSR_JABBER (1 << S_PSSR_JABBER) + +#define S_PSSR_POLARITY 1 +#define V_PSSR_POLARITY (1 << S_PSSR_POLARITY) + +#define S_PSSR_RX_PAUSE 2 +#define V_PSSR_RX_PAUSE (1 << S_PSSR_RX_PAUSE) + +#define S_PSSR_TX_PAUSE 3 +#define V_PSSR_TX_PAUSE (1 << S_PSSR_TX_PAUSE) + +#define S_PSSR_ENERGY_DETECT 4 +#define V_PSSR_ENERGY_DETECT (1 << S_PSSR_ENERGY_DETECT) + +#define S_PSSR_DOWNSHIFT_STATUS 5 +#define V_PSSR_DOWNSHIFT_STATUS (1 << S_PSSR_DOWNSHIFT_STATUS) + +#define S_PSSR_MDI 6 +#define V_PSSR_MDI (1 << S_PSSR_MDI) + +#define S_PSSR_CABLE_LEN 7 +#define M_PSSR_CABLE_LEN 0x7 +#define V_PSSR_CABLE_LEN(x) ((x) << S_PSSR_CABLE_LEN) +#define G_PSSR_CABLE_LEN(x) (((x) >> S_PSSR_CABLE_LEN) & M_PSSR_CABLE_LEN) + +#define S_PSSR_LINK 10 +#define V_PSSR_LINK (1 << S_PSSR_LINK) + +#define S_PSSR_STATUS_RESOLVED 11 +#define V_PSSR_STATUS_RESOLVED (1 << S_PSSR_STATUS_RESOLVED) + +#define S_PSSR_PAGE_RECEIVED 12 +#define V_PSSR_PAGE_RECEIVED (1 << S_PSSR_PAGE_RECEIVED) + +#define S_PSSR_DUPLEX 13 +#define V_PSSR_DUPLEX (1 << S_PSSR_DUPLEX) + +#define S_PSSR_SPEED 14 +#define M_PSSR_SPEED 0x3 +#define V_PSSR_SPEED(x) ((x) << S_PSSR_SPEED) +#define G_PSSR_SPEED(x) (((x) >> S_PSSR_SPEED) & M_PSSR_SPEED) + +#endif diff --git a/drivers/net/ethernet/chelsio/cxgb/mv88x201x.c b/drivers/net/ethernet/chelsio/cxgb/mv88x201x.c new file mode 100644 index 000000000000..f7136b2fd1e5 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb/mv88x201x.c @@ -0,0 +1,260 @@ +/***************************************************************************** + * * + * File: mv88x201x.c * + * $Revision: 1.12 $ * + * $Date: 2005/04/15 19:27:14 $ * + * Description: * + * Marvell PHY (mv88x201x) functionality. * + * part of the Chelsio 10Gb Ethernet Driver. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License, version 2, as * + * published by the Free Software Foundation. * + * * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * + * * + * http://www.chelsio.com * + * * + * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * + * All rights reserved. * + * * + * Maintainers: maintainers@chelsio.com * + * * + * Authors: Dimitrios Michailidis * + * Tina Yang * + * Felix Marti * + * Scott Bardone * + * Kurt Ottaway * + * Frank DiMambro * + * * + * History: * + * * + ****************************************************************************/ + +#include "cphy.h" +#include "elmer0.h" + +/* + * The 88x2010 Rev C. requires some link status registers * to be read + * twice in order to get the right values. Future * revisions will fix + * this problem and then this macro * can disappear. + */ +#define MV88x2010_LINK_STATUS_BUGS 1 + +static int led_init(struct cphy *cphy) +{ + /* Setup the LED registers so we can turn on/off. + * Writing these bits maps control to another + * register. mmd(0x1) addr(0x7) + */ + cphy_mdio_write(cphy, MDIO_MMD_PCS, 0x8304, 0xdddd); + return 0; +} + +static int led_link(struct cphy *cphy, u32 do_enable) +{ + u32 led = 0; +#define LINK_ENABLE_BIT 0x1 + + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_CTRL2, &led); + + if (do_enable & LINK_ENABLE_BIT) { + led |= LINK_ENABLE_BIT; + cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, MDIO_CTRL2, led); + } else { + led &= ~LINK_ENABLE_BIT; + cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, MDIO_CTRL2, led); + } + return 0; +} + +/* Port Reset */ +static int mv88x201x_reset(struct cphy *cphy, int wait) +{ + /* This can be done through registers. It is not required since + * a full chip reset is used. + */ + return 0; +} + +static int mv88x201x_interrupt_enable(struct cphy *cphy) +{ + /* Enable PHY LASI interrupts. */ + cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, + MDIO_PMA_LASI_LSALARM); + + /* Enable Marvell interrupts through Elmer0. */ + if (t1_is_asic(cphy->adapter)) { + u32 elmer; + + t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer); + elmer |= ELMER0_GP_BIT6; + t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer); + } + return 0; +} + +static int mv88x201x_interrupt_disable(struct cphy *cphy) +{ + /* Disable PHY LASI interrupts. */ + cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, 0x0); + + /* Disable Marvell interrupts through Elmer0. */ + if (t1_is_asic(cphy->adapter)) { + u32 elmer; + + t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer); + elmer &= ~ELMER0_GP_BIT6; + t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer); + } + return 0; +} + +static int mv88x201x_interrupt_clear(struct cphy *cphy) +{ + u32 elmer; + u32 val; + +#ifdef MV88x2010_LINK_STATUS_BUGS + /* Required to read twice before clear takes affect. */ + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_RXSTAT, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_TXSTAT, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT, &val); + + /* Read this register after the others above it else + * the register doesn't clear correctly. + */ + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val); +#endif + + /* Clear link status. */ + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val); + /* Clear PHY LASI interrupts. */ + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT, &val); + +#ifdef MV88x2010_LINK_STATUS_BUGS + /* Do it again. */ + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_RXSTAT, &val); + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_TXSTAT, &val); +#endif + + /* Clear Marvell interrupts through Elmer0. */ + if (t1_is_asic(cphy->adapter)) { + t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer); + elmer |= ELMER0_GP_BIT6; + t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer); + } + return 0; +} + +static int mv88x201x_interrupt_handler(struct cphy *cphy) +{ + /* Clear interrupts */ + mv88x201x_interrupt_clear(cphy); + + /* We have only enabled link change interrupts and so + * cphy_cause must be a link change interrupt. + */ + return cphy_cause_link_change; +} + +static int mv88x201x_set_loopback(struct cphy *cphy, int on) +{ + return 0; +} + +static int mv88x201x_get_link_status(struct cphy *cphy, int *link_ok, + int *speed, int *duplex, int *fc) +{ + u32 val = 0; + + if (link_ok) { + /* Read link status. */ + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val); + val &= MDIO_STAT1_LSTATUS; + *link_ok = (val == MDIO_STAT1_LSTATUS); + /* Turn on/off Link LED */ + led_link(cphy, *link_ok); + } + if (speed) + *speed = SPEED_10000; + if (duplex) + *duplex = DUPLEX_FULL; + if (fc) + *fc = PAUSE_RX | PAUSE_TX; + return 0; +} + +static void mv88x201x_destroy(struct cphy *cphy) +{ + kfree(cphy); +} + +static struct cphy_ops mv88x201x_ops = { + .destroy = mv88x201x_destroy, + .reset = mv88x201x_reset, + .interrupt_enable = mv88x201x_interrupt_enable, + .interrupt_disable = mv88x201x_interrupt_disable, + .interrupt_clear = mv88x201x_interrupt_clear, + .interrupt_handler = mv88x201x_interrupt_handler, + .get_link_status = mv88x201x_get_link_status, + .set_loopback = mv88x201x_set_loopback, + .mmds = (MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | + MDIO_DEVS_PHYXS | MDIO_DEVS_WIS), +}; + +static struct cphy *mv88x201x_phy_create(struct net_device *dev, int phy_addr, + const struct mdio_ops *mdio_ops) +{ + u32 val; + struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL); + + if (!cphy) + return NULL; + + cphy_init(cphy, dev, phy_addr, &mv88x201x_ops, mdio_ops); + + /* Commands the PHY to enable XFP's clock. */ + cphy_mdio_read(cphy, MDIO_MMD_PCS, 0x8300, &val); + cphy_mdio_write(cphy, MDIO_MMD_PCS, 0x8300, val | 1); + + /* Clear link status. Required because of a bug in the PHY. */ + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT2, &val); + cphy_mdio_read(cphy, MDIO_MMD_PCS, MDIO_STAT2, &val); + + /* Allows for Link,Ack LED turn on/off */ + led_init(cphy); + return cphy; +} + +/* Chip Reset */ +static int mv88x201x_phy_reset(adapter_t *adapter) +{ + u32 val; + + t1_tpi_read(adapter, A_ELMER0_GPO, &val); + val &= ~4; + t1_tpi_write(adapter, A_ELMER0_GPO, val); + msleep(100); + + t1_tpi_write(adapter, A_ELMER0_GPO, val | 4); + msleep(1000); + + /* Now lets enable the Laser. Delay 100us */ + t1_tpi_read(adapter, A_ELMER0_GPO, &val); + val |= 0x8000; + t1_tpi_write(adapter, A_ELMER0_GPO, val); + udelay(100); + return 0; +} + +const struct gphy t1_mv88x201x_ops = { + .create = mv88x201x_phy_create, + .reset = mv88x201x_phy_reset +}; diff --git a/drivers/net/ethernet/chelsio/cxgb/my3126.c b/drivers/net/ethernet/chelsio/cxgb/my3126.c new file mode 100644 index 000000000000..a683fd3bb624 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb/my3126.c @@ -0,0 +1,209 @@ +/* $Date: 2005/11/12 02:13:49 $ $RCSfile: my3126.c,v $ $Revision: 1.15 $ */ +#include "cphy.h" +#include "elmer0.h" +#include "suni1x10gexp_regs.h" + +/* Port Reset */ +static int my3126_reset(struct cphy *cphy, int wait) +{ + /* + * This can be done through registers. It is not required since + * a full chip reset is used. + */ + return 0; +} + +static int my3126_interrupt_enable(struct cphy *cphy) +{ + schedule_delayed_work(&cphy->phy_update, HZ/30); + t1_tpi_read(cphy->adapter, A_ELMER0_GPO, &cphy->elmer_gpo); + return 0; +} + +static int my3126_interrupt_disable(struct cphy *cphy) +{ + cancel_delayed_work_sync(&cphy->phy_update); + return 0; +} + +static int my3126_interrupt_clear(struct cphy *cphy) +{ + return 0; +} + +#define OFFSET(REG_ADDR) (REG_ADDR << 2) + +static int my3126_interrupt_handler(struct cphy *cphy) +{ + u32 val; + u16 val16; + u16 status; + u32 act_count; + adapter_t *adapter; + adapter = cphy->adapter; + + if (cphy->count == 50) { + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val); + val16 = (u16) val; + status = cphy->bmsr ^ val16; + + if (status & MDIO_STAT1_LSTATUS) + t1_link_changed(adapter, 0); + cphy->bmsr = val16; + + /* We have only enabled link change interrupts so it + must be that + */ + cphy->count = 0; + } + + t1_tpi_write(adapter, OFFSET(SUNI1x10GEXP_REG_MSTAT_CONTROL), + SUNI1x10GEXP_BITMSK_MSTAT_SNAP); + t1_tpi_read(adapter, + OFFSET(SUNI1x10GEXP_REG_MSTAT_COUNTER_1_LOW), &act_count); + t1_tpi_read(adapter, + OFFSET(SUNI1x10GEXP_REG_MSTAT_COUNTER_33_LOW), &val); + act_count += val; + + /* Populate elmer_gpo with the register value */ + t1_tpi_read(adapter, A_ELMER0_GPO, &val); + cphy->elmer_gpo = val; + + if ( (val & (1 << 8)) || (val & (1 << 19)) || + (cphy->act_count == act_count) || cphy->act_on ) { + if (is_T2(adapter)) + val |= (1 << 9); + else if (t1_is_T1B(adapter)) + val |= (1 << 20); + cphy->act_on = 0; + } else { + if (is_T2(adapter)) + val &= ~(1 << 9); + else if (t1_is_T1B(adapter)) + val &= ~(1 << 20); + cphy->act_on = 1; + } + + t1_tpi_write(adapter, A_ELMER0_GPO, val); + + cphy->elmer_gpo = val; + cphy->act_count = act_count; + cphy->count++; + + return cphy_cause_link_change; +} + +static void my3216_poll(struct work_struct *work) +{ + struct cphy *cphy = container_of(work, struct cphy, phy_update.work); + + my3126_interrupt_handler(cphy); +} + +static int my3126_set_loopback(struct cphy *cphy, int on) +{ + return 0; +} + +/* To check the activity LED */ +static int my3126_get_link_status(struct cphy *cphy, + int *link_ok, int *speed, int *duplex, int *fc) +{ + u32 val; + u16 val16; + adapter_t *adapter; + + adapter = cphy->adapter; + cphy_mdio_read(cphy, MDIO_MMD_PMAPMD, MDIO_STAT1, &val); + val16 = (u16) val; + + /* Populate elmer_gpo with the register value */ + t1_tpi_read(adapter, A_ELMER0_GPO, &val); + cphy->elmer_gpo = val; + + *link_ok = (val16 & MDIO_STAT1_LSTATUS); + + if (*link_ok) { + /* Turn on the LED. */ + if (is_T2(adapter)) + val &= ~(1 << 8); + else if (t1_is_T1B(adapter)) + val &= ~(1 << 19); + } else { + /* Turn off the LED. */ + if (is_T2(adapter)) + val |= (1 << 8); + else if (t1_is_T1B(adapter)) + val |= (1 << 19); + } + + t1_tpi_write(adapter, A_ELMER0_GPO, val); + cphy->elmer_gpo = val; + *speed = SPEED_10000; + *duplex = DUPLEX_FULL; + + /* need to add flow control */ + if (fc) + *fc = PAUSE_RX | PAUSE_TX; + + return 0; +} + +static void my3126_destroy(struct cphy *cphy) +{ + kfree(cphy); +} + +static struct cphy_ops my3126_ops = { + .destroy = my3126_destroy, + .reset = my3126_reset, + .interrupt_enable = my3126_interrupt_enable, + .interrupt_disable = my3126_interrupt_disable, + .interrupt_clear = my3126_interrupt_clear, + .interrupt_handler = my3126_interrupt_handler, + .get_link_status = my3126_get_link_status, + .set_loopback = my3126_set_loopback, + .mmds = (MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | + MDIO_DEVS_PHYXS), +}; + +static struct cphy *my3126_phy_create(struct net_device *dev, + int phy_addr, const struct mdio_ops *mdio_ops) +{ + struct cphy *cphy = kzalloc(sizeof (*cphy), GFP_KERNEL); + + if (!cphy) + return NULL; + + cphy_init(cphy, dev, phy_addr, &my3126_ops, mdio_ops); + INIT_DELAYED_WORK(&cphy->phy_update, my3216_poll); + cphy->bmsr = 0; + + return cphy; +} + +/* Chip Reset */ +static int my3126_phy_reset(adapter_t * adapter) +{ + u32 val; + + t1_tpi_read(adapter, A_ELMER0_GPO, &val); + val &= ~4; + t1_tpi_write(adapter, A_ELMER0_GPO, val); + msleep(100); + + t1_tpi_write(adapter, A_ELMER0_GPO, val | 4); + msleep(1000); + + /* Now lets enable the Laser. Delay 100us */ + t1_tpi_read(adapter, A_ELMER0_GPO, &val); + val |= 0x8000; + t1_tpi_write(adapter, A_ELMER0_GPO, val); + udelay(100); + return 0; +} + +const struct gphy t1_my3126_ops = { + .create = my3126_phy_create, + .reset = my3126_phy_reset +}; diff --git a/drivers/net/ethernet/chelsio/cxgb/pm3393.c b/drivers/net/ethernet/chelsio/cxgb/pm3393.c new file mode 100644 index 000000000000..40c7b93ababc --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb/pm3393.c @@ -0,0 +1,796 @@ +/***************************************************************************** + * * + * File: pm3393.c * + * $Revision: 1.16 $ * + * $Date: 2005/05/14 00:59:32 $ * + * Description: * + * PMC/SIERRA (pm3393) MAC-PHY functionality. * + * part of the Chelsio 10Gb Ethernet Driver. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License, version 2, as * + * published by the Free Software Foundation. * + * * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * + * * + * http://www.chelsio.com * + * * + * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * + * All rights reserved. * + * * + * Maintainers: maintainers@chelsio.com * + * * + * Authors: Dimitrios Michailidis * + * Tina Yang * + * Felix Marti * + * Scott Bardone * + * Kurt Ottaway * + * Frank DiMambro * + * * + * History: * + * * + ****************************************************************************/ + +#include "common.h" +#include "regs.h" +#include "gmac.h" +#include "elmer0.h" +#include "suni1x10gexp_regs.h" + +#include +#include + +#define OFFSET(REG_ADDR) ((REG_ADDR) << 2) + +/* Max frame size PM3393 can handle. Includes Ethernet header and CRC. */ +#define MAX_FRAME_SIZE 9600 + +#define IPG 12 +#define TXXG_CONF1_VAL ((IPG << SUNI1x10GEXP_BITOFF_TXXG_IPGT) | \ + SUNI1x10GEXP_BITMSK_TXXG_32BIT_ALIGN | SUNI1x10GEXP_BITMSK_TXXG_CRCEN | \ + SUNI1x10GEXP_BITMSK_TXXG_PADEN) +#define RXXG_CONF1_VAL (SUNI1x10GEXP_BITMSK_RXXG_PUREP | 0x14 | \ + SUNI1x10GEXP_BITMSK_RXXG_FLCHK | SUNI1x10GEXP_BITMSK_RXXG_CRC_STRIP) + +/* Update statistics every 15 minutes */ +#define STATS_TICK_SECS (15 * 60) + +enum { /* RMON registers */ + RxOctetsReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_1_LOW, + RxUnicastFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_4_LOW, + RxMulticastFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_5_LOW, + RxBroadcastFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_6_LOW, + RxPAUSEMACCtrlFramesReceived = SUNI1x10GEXP_REG_MSTAT_COUNTER_8_LOW, + RxFrameCheckSequenceErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_10_LOW, + RxFramesLostDueToInternalMACErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_11_LOW, + RxSymbolErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_12_LOW, + RxInRangeLengthErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_13_LOW, + RxFramesTooLongErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_15_LOW, + RxJabbers = SUNI1x10GEXP_REG_MSTAT_COUNTER_16_LOW, + RxFragments = SUNI1x10GEXP_REG_MSTAT_COUNTER_17_LOW, + RxUndersizedFrames = SUNI1x10GEXP_REG_MSTAT_COUNTER_18_LOW, + RxJumboFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_25_LOW, + RxJumboOctetsReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_26_LOW, + + TxOctetsTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_33_LOW, + TxFramesLostDueToInternalMACTransmissionError = SUNI1x10GEXP_REG_MSTAT_COUNTER_35_LOW, + TxTransmitSystemError = SUNI1x10GEXP_REG_MSTAT_COUNTER_36_LOW, + TxUnicastFramesTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_38_LOW, + TxMulticastFramesTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_40_LOW, + TxBroadcastFramesTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_42_LOW, + TxPAUSEMACCtrlFramesTransmitted = SUNI1x10GEXP_REG_MSTAT_COUNTER_43_LOW, + TxJumboFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_51_LOW, + TxJumboOctetsReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_52_LOW +}; + +struct _cmac_instance { + u8 enabled; + u8 fc; + u8 mac_addr[6]; +}; + +static int pmread(struct cmac *cmac, u32 reg, u32 * data32) +{ + t1_tpi_read(cmac->adapter, OFFSET(reg), data32); + return 0; +} + +static int pmwrite(struct cmac *cmac, u32 reg, u32 data32) +{ + t1_tpi_write(cmac->adapter, OFFSET(reg), data32); + return 0; +} + +/* Port reset. */ +static int pm3393_reset(struct cmac *cmac) +{ + return 0; +} + +/* + * Enable interrupts for the PM3393 + * + * 1. Enable PM3393 BLOCK interrupts. + * 2. Enable PM3393 Master Interrupt bit(INTE) + * 3. Enable ELMER's PM3393 bit. + * 4. Enable Terminator external interrupt. + */ +static int pm3393_interrupt_enable(struct cmac *cmac) +{ + u32 pl_intr; + + /* PM3393 - Enabling all hardware block interrupts. + */ + pmwrite(cmac, SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_ENABLE, 0xffff); + pmwrite(cmac, SUNI1x10GEXP_REG_XRF_INTERRUPT_ENABLE, 0xffff); + pmwrite(cmac, SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_ENABLE, 0xffff); + pmwrite(cmac, SUNI1x10GEXP_REG_RXOAM_INTERRUPT_ENABLE, 0xffff); + + /* Don't interrupt on statistics overflow, we are polling */ + pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_0, 0); + pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_1, 0); + pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_2, 0); + pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_3, 0); + + pmwrite(cmac, SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_ENABLE, 0xffff); + pmwrite(cmac, SUNI1x10GEXP_REG_PL4ODP_INTERRUPT_MASK, 0xffff); + pmwrite(cmac, SUNI1x10GEXP_REG_XTEF_INTERRUPT_ENABLE, 0xffff); + pmwrite(cmac, SUNI1x10GEXP_REG_TXOAM_INTERRUPT_ENABLE, 0xffff); + pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_3, 0xffff); + pmwrite(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_MASK, 0xffff); + pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_3, 0xffff); + pmwrite(cmac, SUNI1x10GEXP_REG_PL4IDU_INTERRUPT_MASK, 0xffff); + pmwrite(cmac, SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_ENABLE, 0xffff); + + /* PM3393 - Global interrupt enable + */ + /* TBD XXX Disable for now until we figure out why error interrupts keep asserting. */ + pmwrite(cmac, SUNI1x10GEXP_REG_GLOBAL_INTERRUPT_ENABLE, + 0 /*SUNI1x10GEXP_BITMSK_TOP_INTE */ ); + + /* TERMINATOR - PL_INTERUPTS_EXT */ + pl_intr = readl(cmac->adapter->regs + A_PL_ENABLE); + pl_intr |= F_PL_INTR_EXT; + writel(pl_intr, cmac->adapter->regs + A_PL_ENABLE); + return 0; +} + +static int pm3393_interrupt_disable(struct cmac *cmac) +{ + u32 elmer; + + /* PM3393 - Enabling HW interrupt blocks. */ + pmwrite(cmac, SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_ENABLE, 0); + pmwrite(cmac, SUNI1x10GEXP_REG_XRF_INTERRUPT_ENABLE, 0); + pmwrite(cmac, SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_ENABLE, 0); + pmwrite(cmac, SUNI1x10GEXP_REG_RXOAM_INTERRUPT_ENABLE, 0); + pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_0, 0); + pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_1, 0); + pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_2, 0); + pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_3, 0); + pmwrite(cmac, SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_ENABLE, 0); + pmwrite(cmac, SUNI1x10GEXP_REG_PL4ODP_INTERRUPT_MASK, 0); + pmwrite(cmac, SUNI1x10GEXP_REG_XTEF_INTERRUPT_ENABLE, 0); + pmwrite(cmac, SUNI1x10GEXP_REG_TXOAM_INTERRUPT_ENABLE, 0); + pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_3, 0); + pmwrite(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_MASK, 0); + pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_3, 0); + pmwrite(cmac, SUNI1x10GEXP_REG_PL4IDU_INTERRUPT_MASK, 0); + pmwrite(cmac, SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_ENABLE, 0); + + /* PM3393 - Global interrupt enable */ + pmwrite(cmac, SUNI1x10GEXP_REG_GLOBAL_INTERRUPT_ENABLE, 0); + + /* ELMER - External chip interrupts. */ + t1_tpi_read(cmac->adapter, A_ELMER0_INT_ENABLE, &elmer); + elmer &= ~ELMER0_GP_BIT1; + t1_tpi_write(cmac->adapter, A_ELMER0_INT_ENABLE, elmer); + + /* TERMINATOR - PL_INTERUPTS_EXT */ + /* DO NOT DISABLE TERMINATOR's EXTERNAL INTERRUPTS. ANOTHER CHIP + * COULD WANT THEM ENABLED. We disable PM3393 at the ELMER level. + */ + + return 0; +} + +static int pm3393_interrupt_clear(struct cmac *cmac) +{ + u32 elmer; + u32 pl_intr; + u32 val32; + + /* PM3393 - Clearing HW interrupt blocks. Note, this assumes + * bit WCIMODE=0 for a clear-on-read. + */ + pmread(cmac, SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_STATUS, &val32); + pmread(cmac, SUNI1x10GEXP_REG_XRF_INTERRUPT_STATUS, &val32); + pmread(cmac, SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_STATUS, &val32); + pmread(cmac, SUNI1x10GEXP_REG_RXOAM_INTERRUPT_STATUS, &val32); + pmread(cmac, SUNI1x10GEXP_REG_PL4ODP_INTERRUPT, &val32); + pmread(cmac, SUNI1x10GEXP_REG_XTEF_INTERRUPT_STATUS, &val32); + pmread(cmac, SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_INTERRUPT, &val32); + pmread(cmac, SUNI1x10GEXP_REG_TXOAM_INTERRUPT_STATUS, &val32); + pmread(cmac, SUNI1x10GEXP_REG_RXXG_INTERRUPT, &val32); + pmread(cmac, SUNI1x10GEXP_REG_TXXG_INTERRUPT, &val32); + pmread(cmac, SUNI1x10GEXP_REG_PL4IDU_INTERRUPT, &val32); + pmread(cmac, SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_INDICATION, + &val32); + pmread(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_STATUS, &val32); + pmread(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_CHANGE, &val32); + + /* PM3393 - Global interrupt status + */ + pmread(cmac, SUNI1x10GEXP_REG_MASTER_INTERRUPT_STATUS, &val32); + + /* ELMER - External chip interrupts. + */ + t1_tpi_read(cmac->adapter, A_ELMER0_INT_CAUSE, &elmer); + elmer |= ELMER0_GP_BIT1; + t1_tpi_write(cmac->adapter, A_ELMER0_INT_CAUSE, elmer); + + /* TERMINATOR - PL_INTERUPTS_EXT + */ + pl_intr = readl(cmac->adapter->regs + A_PL_CAUSE); + pl_intr |= F_PL_INTR_EXT; + writel(pl_intr, cmac->adapter->regs + A_PL_CAUSE); + + return 0; +} + +/* Interrupt handler */ +static int pm3393_interrupt_handler(struct cmac *cmac) +{ + u32 master_intr_status; + + /* Read the master interrupt status register. */ + pmread(cmac, SUNI1x10GEXP_REG_MASTER_INTERRUPT_STATUS, + &master_intr_status); + if (netif_msg_intr(cmac->adapter)) + dev_dbg(&cmac->adapter->pdev->dev, "PM3393 intr cause 0x%x\n", + master_intr_status); + + /* TBD XXX Lets just clear everything for now */ + pm3393_interrupt_clear(cmac); + + return 0; +} + +static int pm3393_enable(struct cmac *cmac, int which) +{ + if (which & MAC_DIRECTION_RX) + pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_1, + (RXXG_CONF1_VAL | SUNI1x10GEXP_BITMSK_RXXG_RXEN)); + + if (which & MAC_DIRECTION_TX) { + u32 val = TXXG_CONF1_VAL | SUNI1x10GEXP_BITMSK_TXXG_TXEN0; + + if (cmac->instance->fc & PAUSE_RX) + val |= SUNI1x10GEXP_BITMSK_TXXG_FCRX; + if (cmac->instance->fc & PAUSE_TX) + val |= SUNI1x10GEXP_BITMSK_TXXG_FCTX; + pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_1, val); + } + + cmac->instance->enabled |= which; + return 0; +} + +static int pm3393_enable_port(struct cmac *cmac, int which) +{ + /* Clear port statistics */ + pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_CONTROL, + SUNI1x10GEXP_BITMSK_MSTAT_CLEAR); + udelay(2); + memset(&cmac->stats, 0, sizeof(struct cmac_statistics)); + + pm3393_enable(cmac, which); + + /* + * XXX This should be done by the PHY and preferably not at all. + * The PHY doesn't give us link status indication on its own so have + * the link management code query it instead. + */ + t1_link_changed(cmac->adapter, 0); + return 0; +} + +static int pm3393_disable(struct cmac *cmac, int which) +{ + if (which & MAC_DIRECTION_RX) + pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_1, RXXG_CONF1_VAL); + if (which & MAC_DIRECTION_TX) + pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_1, TXXG_CONF1_VAL); + + /* + * The disable is graceful. Give the PM3393 time. Can't wait very + * long here, we may be holding locks. + */ + udelay(20); + + cmac->instance->enabled &= ~which; + return 0; +} + +static int pm3393_loopback_enable(struct cmac *cmac) +{ + return 0; +} + +static int pm3393_loopback_disable(struct cmac *cmac) +{ + return 0; +} + +static int pm3393_set_mtu(struct cmac *cmac, int mtu) +{ + int enabled = cmac->instance->enabled; + + /* MAX_FRAME_SIZE includes header + FCS, mtu doesn't */ + mtu += 14 + 4; + if (mtu > MAX_FRAME_SIZE) + return -EINVAL; + + /* Disable Rx/Tx MAC before configuring it. */ + if (enabled) + pm3393_disable(cmac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); + + pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MAX_FRAME_LENGTH, mtu); + pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_MAX_FRAME_SIZE, mtu); + + if (enabled) + pm3393_enable(cmac, enabled); + return 0; +} + +static int pm3393_set_rx_mode(struct cmac *cmac, struct t1_rx_mode *rm) +{ + int enabled = cmac->instance->enabled & MAC_DIRECTION_RX; + u32 rx_mode; + + /* Disable MAC RX before reconfiguring it */ + if (enabled) + pm3393_disable(cmac, MAC_DIRECTION_RX); + + pmread(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_2, &rx_mode); + rx_mode &= ~(SUNI1x10GEXP_BITMSK_RXXG_PMODE | + SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN); + pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_2, + (u16)rx_mode); + + if (t1_rx_mode_promisc(rm)) { + /* Promiscuous mode. */ + rx_mode |= SUNI1x10GEXP_BITMSK_RXXG_PMODE; + } + if (t1_rx_mode_allmulti(rm)) { + /* Accept all multicast. */ + pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_LOW, 0xffff); + pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDLOW, 0xffff); + pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDHIGH, 0xffff); + pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_HIGH, 0xffff); + rx_mode |= SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN; + } else if (t1_rx_mode_mc_cnt(rm)) { + /* Accept one or more multicast(s). */ + struct netdev_hw_addr *ha; + int bit; + u16 mc_filter[4] = { 0, }; + + netdev_for_each_mc_addr(ha, t1_get_netdev(rm)) { + /* bit[23:28] */ + bit = (ether_crc(ETH_ALEN, ha->addr) >> 23) & 0x3f; + mc_filter[bit >> 4] |= 1 << (bit & 0xf); + } + pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_LOW, mc_filter[0]); + pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDLOW, mc_filter[1]); + pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDHIGH, mc_filter[2]); + pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_HIGH, mc_filter[3]); + rx_mode |= SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN; + } + + pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_2, (u16)rx_mode); + + if (enabled) + pm3393_enable(cmac, MAC_DIRECTION_RX); + + return 0; +} + +static int pm3393_get_speed_duplex_fc(struct cmac *cmac, int *speed, + int *duplex, int *fc) +{ + if (speed) + *speed = SPEED_10000; + if (duplex) + *duplex = DUPLEX_FULL; + if (fc) + *fc = cmac->instance->fc; + return 0; +} + +static int pm3393_set_speed_duplex_fc(struct cmac *cmac, int speed, int duplex, + int fc) +{ + if (speed >= 0 && speed != SPEED_10000) + return -1; + if (duplex >= 0 && duplex != DUPLEX_FULL) + return -1; + if (fc & ~(PAUSE_TX | PAUSE_RX)) + return -1; + + if (fc != cmac->instance->fc) { + cmac->instance->fc = (u8) fc; + if (cmac->instance->enabled & MAC_DIRECTION_TX) + pm3393_enable(cmac, MAC_DIRECTION_TX); + } + return 0; +} + +#define RMON_UPDATE(mac, name, stat_name) \ +{ \ + t1_tpi_read((mac)->adapter, OFFSET(name), &val0); \ + t1_tpi_read((mac)->adapter, OFFSET((name)+1), &val1); \ + t1_tpi_read((mac)->adapter, OFFSET((name)+2), &val2); \ + (mac)->stats.stat_name = (u64)(val0 & 0xffff) | \ + ((u64)(val1 & 0xffff) << 16) | \ + ((u64)(val2 & 0xff) << 32) | \ + ((mac)->stats.stat_name & \ + 0xffffff0000000000ULL); \ + if (ro & \ + (1ULL << ((name - SUNI1x10GEXP_REG_MSTAT_COUNTER_0_LOW) >> 2))) \ + (mac)->stats.stat_name += 1ULL << 40; \ +} + +static const struct cmac_statistics *pm3393_update_statistics(struct cmac *mac, + int flag) +{ + u64 ro; + u32 val0, val1, val2, val3; + + /* Snap the counters */ + pmwrite(mac, SUNI1x10GEXP_REG_MSTAT_CONTROL, + SUNI1x10GEXP_BITMSK_MSTAT_SNAP); + + /* Counter rollover, clear on read */ + pmread(mac, SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_0, &val0); + pmread(mac, SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_1, &val1); + pmread(mac, SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_2, &val2); + pmread(mac, SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_3, &val3); + ro = ((u64)val0 & 0xffff) | (((u64)val1 & 0xffff) << 16) | + (((u64)val2 & 0xffff) << 32) | (((u64)val3 & 0xffff) << 48); + + /* Rx stats */ + RMON_UPDATE(mac, RxOctetsReceivedOK, RxOctetsOK); + RMON_UPDATE(mac, RxUnicastFramesReceivedOK, RxUnicastFramesOK); + RMON_UPDATE(mac, RxMulticastFramesReceivedOK, RxMulticastFramesOK); + RMON_UPDATE(mac, RxBroadcastFramesReceivedOK, RxBroadcastFramesOK); + RMON_UPDATE(mac, RxPAUSEMACCtrlFramesReceived, RxPauseFrames); + RMON_UPDATE(mac, RxFrameCheckSequenceErrors, RxFCSErrors); + RMON_UPDATE(mac, RxFramesLostDueToInternalMACErrors, + RxInternalMACRcvError); + RMON_UPDATE(mac, RxSymbolErrors, RxSymbolErrors); + RMON_UPDATE(mac, RxInRangeLengthErrors, RxInRangeLengthErrors); + RMON_UPDATE(mac, RxFramesTooLongErrors , RxFrameTooLongErrors); + RMON_UPDATE(mac, RxJabbers, RxJabberErrors); + RMON_UPDATE(mac, RxFragments, RxRuntErrors); + RMON_UPDATE(mac, RxUndersizedFrames, RxRuntErrors); + RMON_UPDATE(mac, RxJumboFramesReceivedOK, RxJumboFramesOK); + RMON_UPDATE(mac, RxJumboOctetsReceivedOK, RxJumboOctetsOK); + + /* Tx stats */ + RMON_UPDATE(mac, TxOctetsTransmittedOK, TxOctetsOK); + RMON_UPDATE(mac, TxFramesLostDueToInternalMACTransmissionError, + TxInternalMACXmitError); + RMON_UPDATE(mac, TxTransmitSystemError, TxFCSErrors); + RMON_UPDATE(mac, TxUnicastFramesTransmittedOK, TxUnicastFramesOK); + RMON_UPDATE(mac, TxMulticastFramesTransmittedOK, TxMulticastFramesOK); + RMON_UPDATE(mac, TxBroadcastFramesTransmittedOK, TxBroadcastFramesOK); + RMON_UPDATE(mac, TxPAUSEMACCtrlFramesTransmitted, TxPauseFrames); + RMON_UPDATE(mac, TxJumboFramesReceivedOK, TxJumboFramesOK); + RMON_UPDATE(mac, TxJumboOctetsReceivedOK, TxJumboOctetsOK); + + return &mac->stats; +} + +static int pm3393_macaddress_get(struct cmac *cmac, u8 mac_addr[6]) +{ + memcpy(mac_addr, cmac->instance->mac_addr, 6); + return 0; +} + +static int pm3393_macaddress_set(struct cmac *cmac, u8 ma[6]) +{ + u32 val, lo, mid, hi, enabled = cmac->instance->enabled; + + /* + * MAC addr: 00:07:43:00:13:09 + * + * ma[5] = 0x09 + * ma[4] = 0x13 + * ma[3] = 0x00 + * ma[2] = 0x43 + * ma[1] = 0x07 + * ma[0] = 0x00 + * + * The PM3393 requires byte swapping and reverse order entry + * when programming MAC addresses: + * + * low_bits[15:0] = ma[1]:ma[0] + * mid_bits[31:16] = ma[3]:ma[2] + * high_bits[47:32] = ma[5]:ma[4] + */ + + /* Store local copy */ + memcpy(cmac->instance->mac_addr, ma, 6); + + lo = ((u32) ma[1] << 8) | (u32) ma[0]; + mid = ((u32) ma[3] << 8) | (u32) ma[2]; + hi = ((u32) ma[5] << 8) | (u32) ma[4]; + + /* Disable Rx/Tx MAC before configuring it. */ + if (enabled) + pm3393_disable(cmac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); + + /* Set RXXG Station Address */ + pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_SA_15_0, lo); + pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_SA_31_16, mid); + pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_SA_47_32, hi); + + /* Set TXXG Station Address */ + pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_SA_15_0, lo); + pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_SA_31_16, mid); + pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_SA_47_32, hi); + + /* Setup Exact Match Filter 1 with our MAC address + * + * Must disable exact match filter before configuring it. + */ + pmread(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_0, &val); + val &= 0xff0f; + pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_0, val); + + pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_LOW, lo); + pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_MID, mid); + pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_HIGH, hi); + + val |= 0x0090; + pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_0, val); + + if (enabled) + pm3393_enable(cmac, enabled); + return 0; +} + +static void pm3393_destroy(struct cmac *cmac) +{ + kfree(cmac); +} + +static struct cmac_ops pm3393_ops = { + .destroy = pm3393_destroy, + .reset = pm3393_reset, + .interrupt_enable = pm3393_interrupt_enable, + .interrupt_disable = pm3393_interrupt_disable, + .interrupt_clear = pm3393_interrupt_clear, + .interrupt_handler = pm3393_interrupt_handler, + .enable = pm3393_enable_port, + .disable = pm3393_disable, + .loopback_enable = pm3393_loopback_enable, + .loopback_disable = pm3393_loopback_disable, + .set_mtu = pm3393_set_mtu, + .set_rx_mode = pm3393_set_rx_mode, + .get_speed_duplex_fc = pm3393_get_speed_duplex_fc, + .set_speed_duplex_fc = pm3393_set_speed_duplex_fc, + .statistics_update = pm3393_update_statistics, + .macaddress_get = pm3393_macaddress_get, + .macaddress_set = pm3393_macaddress_set +}; + +static struct cmac *pm3393_mac_create(adapter_t *adapter, int index) +{ + struct cmac *cmac; + + cmac = kzalloc(sizeof(*cmac) + sizeof(cmac_instance), GFP_KERNEL); + if (!cmac) + return NULL; + + cmac->ops = &pm3393_ops; + cmac->instance = (cmac_instance *) (cmac + 1); + cmac->adapter = adapter; + cmac->instance->fc = PAUSE_TX | PAUSE_RX; + + t1_tpi_write(adapter, OFFSET(0x0001), 0x00008000); + t1_tpi_write(adapter, OFFSET(0x0001), 0x00000000); + t1_tpi_write(adapter, OFFSET(0x2308), 0x00009800); + t1_tpi_write(adapter, OFFSET(0x2305), 0x00001001); /* PL4IO Enable */ + t1_tpi_write(adapter, OFFSET(0x2320), 0x00008800); + t1_tpi_write(adapter, OFFSET(0x2321), 0x00008800); + t1_tpi_write(adapter, OFFSET(0x2322), 0x00008800); + t1_tpi_write(adapter, OFFSET(0x2323), 0x00008800); + t1_tpi_write(adapter, OFFSET(0x2324), 0x00008800); + t1_tpi_write(adapter, OFFSET(0x2325), 0x00008800); + t1_tpi_write(adapter, OFFSET(0x2326), 0x00008800); + t1_tpi_write(adapter, OFFSET(0x2327), 0x00008800); + t1_tpi_write(adapter, OFFSET(0x2328), 0x00008800); + t1_tpi_write(adapter, OFFSET(0x2329), 0x00008800); + t1_tpi_write(adapter, OFFSET(0x232a), 0x00008800); + t1_tpi_write(adapter, OFFSET(0x232b), 0x00008800); + t1_tpi_write(adapter, OFFSET(0x232c), 0x00008800); + t1_tpi_write(adapter, OFFSET(0x232d), 0x00008800); + t1_tpi_write(adapter, OFFSET(0x232e), 0x00008800); + t1_tpi_write(adapter, OFFSET(0x232f), 0x00008800); + t1_tpi_write(adapter, OFFSET(0x230d), 0x00009c00); + t1_tpi_write(adapter, OFFSET(0x2304), 0x00000202); /* PL4IO Calendar Repetitions */ + + t1_tpi_write(adapter, OFFSET(0x3200), 0x00008080); /* EFLX Enable */ + t1_tpi_write(adapter, OFFSET(0x3210), 0x00000000); /* EFLX Channel Deprovision */ + t1_tpi_write(adapter, OFFSET(0x3203), 0x00000000); /* EFLX Low Limit */ + t1_tpi_write(adapter, OFFSET(0x3204), 0x00000040); /* EFLX High Limit */ + t1_tpi_write(adapter, OFFSET(0x3205), 0x000002cc); /* EFLX Almost Full */ + t1_tpi_write(adapter, OFFSET(0x3206), 0x00000199); /* EFLX Almost Empty */ + t1_tpi_write(adapter, OFFSET(0x3207), 0x00000240); /* EFLX Cut Through Threshold */ + t1_tpi_write(adapter, OFFSET(0x3202), 0x00000000); /* EFLX Indirect Register Update */ + t1_tpi_write(adapter, OFFSET(0x3210), 0x00000001); /* EFLX Channel Provision */ + t1_tpi_write(adapter, OFFSET(0x3208), 0x0000ffff); /* EFLX Undocumented */ + t1_tpi_write(adapter, OFFSET(0x320a), 0x0000ffff); /* EFLX Undocumented */ + t1_tpi_write(adapter, OFFSET(0x320c), 0x0000ffff); /* EFLX enable overflow interrupt The other bit are undocumented */ + t1_tpi_write(adapter, OFFSET(0x320e), 0x0000ffff); /* EFLX Undocumented */ + + t1_tpi_write(adapter, OFFSET(0x2200), 0x0000c000); /* IFLX Configuration - enable */ + t1_tpi_write(adapter, OFFSET(0x2201), 0x00000000); /* IFLX Channel Deprovision */ + t1_tpi_write(adapter, OFFSET(0x220e), 0x00000000); /* IFLX Low Limit */ + t1_tpi_write(adapter, OFFSET(0x220f), 0x00000100); /* IFLX High Limit */ + t1_tpi_write(adapter, OFFSET(0x2210), 0x00000c00); /* IFLX Almost Full Limit */ + t1_tpi_write(adapter, OFFSET(0x2211), 0x00000599); /* IFLX Almost Empty Limit */ + t1_tpi_write(adapter, OFFSET(0x220d), 0x00000000); /* IFLX Indirect Register Update */ + t1_tpi_write(adapter, OFFSET(0x2201), 0x00000001); /* IFLX Channel Provision */ + t1_tpi_write(adapter, OFFSET(0x2203), 0x0000ffff); /* IFLX Undocumented */ + t1_tpi_write(adapter, OFFSET(0x2205), 0x0000ffff); /* IFLX Undocumented */ + t1_tpi_write(adapter, OFFSET(0x2209), 0x0000ffff); /* IFLX Enable overflow interrupt. The other bit are undocumented */ + + t1_tpi_write(adapter, OFFSET(0x2241), 0xfffffffe); /* PL4MOS Undocumented */ + t1_tpi_write(adapter, OFFSET(0x2242), 0x0000ffff); /* PL4MOS Undocumented */ + t1_tpi_write(adapter, OFFSET(0x2243), 0x00000008); /* PL4MOS Starving Burst Size */ + t1_tpi_write(adapter, OFFSET(0x2244), 0x00000008); /* PL4MOS Hungry Burst Size */ + t1_tpi_write(adapter, OFFSET(0x2245), 0x00000008); /* PL4MOS Transfer Size */ + t1_tpi_write(adapter, OFFSET(0x2240), 0x00000005); /* PL4MOS Disable */ + + t1_tpi_write(adapter, OFFSET(0x2280), 0x00002103); /* PL4ODP Training Repeat and SOP rule */ + t1_tpi_write(adapter, OFFSET(0x2284), 0x00000000); /* PL4ODP MAX_T setting */ + + t1_tpi_write(adapter, OFFSET(0x3280), 0x00000087); /* PL4IDU Enable data forward, port state machine. Set ALLOW_NON_ZERO_OLB */ + t1_tpi_write(adapter, OFFSET(0x3282), 0x0000001f); /* PL4IDU Enable Dip4 check error interrupts */ + + t1_tpi_write(adapter, OFFSET(0x3040), 0x0c32); /* # TXXG Config */ + /* For T1 use timer based Mac flow control. */ + t1_tpi_write(adapter, OFFSET(0x304d), 0x8000); + t1_tpi_write(adapter, OFFSET(0x2040), 0x059c); /* # RXXG Config */ + t1_tpi_write(adapter, OFFSET(0x2049), 0x0001); /* # RXXG Cut Through */ + t1_tpi_write(adapter, OFFSET(0x2070), 0x0000); /* # Disable promiscuous mode */ + + /* Setup Exact Match Filter 0 to allow broadcast packets. + */ + t1_tpi_write(adapter, OFFSET(0x206e), 0x0000); /* # Disable Match Enable bit */ + t1_tpi_write(adapter, OFFSET(0x204a), 0xffff); /* # low addr */ + t1_tpi_write(adapter, OFFSET(0x204b), 0xffff); /* # mid addr */ + t1_tpi_write(adapter, OFFSET(0x204c), 0xffff); /* # high addr */ + t1_tpi_write(adapter, OFFSET(0x206e), 0x0009); /* # Enable Match Enable bit */ + + t1_tpi_write(adapter, OFFSET(0x0003), 0x0000); /* # NO SOP/ PAD_EN setup */ + t1_tpi_write(adapter, OFFSET(0x0100), 0x0ff0); /* # RXEQB disabled */ + t1_tpi_write(adapter, OFFSET(0x0101), 0x0f0f); /* # No Preemphasis */ + + return cmac; +} + +static int pm3393_mac_reset(adapter_t * adapter) +{ + u32 val; + u32 x; + u32 is_pl4_reset_finished; + u32 is_pl4_outof_lock; + u32 is_xaui_mabc_pll_locked; + u32 successful_reset; + int i; + + /* The following steps are required to properly reset + * the PM3393. This information is provided in the + * PM3393 datasheet (Issue 2: November 2002) + * section 13.1 -- Device Reset. + * + * The PM3393 has three types of components that are + * individually reset: + * + * DRESETB - Digital circuitry + * PL4_ARESETB - PL4 analog circuitry + * XAUI_ARESETB - XAUI bus analog circuitry + * + * Steps to reset PM3393 using RSTB pin: + * + * 1. Assert RSTB pin low ( write 0 ) + * 2. Wait at least 1ms to initiate a complete initialization of device. + * 3. Wait until all external clocks and REFSEL are stable. + * 4. Wait minimum of 1ms. (after external clocks and REFEL are stable) + * 5. De-assert RSTB ( write 1 ) + * 6. Wait until internal timers to expires after ~14ms. + * - Allows analog clock synthesizer(PL4CSU) to stabilize to + * selected reference frequency before allowing the digital + * portion of the device to operate. + * 7. Wait at least 200us for XAUI interface to stabilize. + * 8. Verify the PM3393 came out of reset successfully. + * Set successful reset flag if everything worked else try again + * a few more times. + */ + + successful_reset = 0; + for (i = 0; i < 3 && !successful_reset; i++) { + /* 1 */ + t1_tpi_read(adapter, A_ELMER0_GPO, &val); + val &= ~1; + t1_tpi_write(adapter, A_ELMER0_GPO, val); + + /* 2 */ + msleep(1); + + /* 3 */ + msleep(1); + + /* 4 */ + msleep(2 /*1 extra ms for safety */ ); + + /* 5 */ + val |= 1; + t1_tpi_write(adapter, A_ELMER0_GPO, val); + + /* 6 */ + msleep(15 /*1 extra ms for safety */ ); + + /* 7 */ + msleep(1); + + /* 8 */ + + /* Has PL4 analog block come out of reset correctly? */ + t1_tpi_read(adapter, OFFSET(SUNI1x10GEXP_REG_DEVICE_STATUS), &val); + is_pl4_reset_finished = (val & SUNI1x10GEXP_BITMSK_TOP_EXPIRED); + + /* TBD XXX SUNI1x10GEXP_BITMSK_TOP_PL4_IS_DOOL gets locked later in the init sequence + * figure out why? */ + + /* Have all PL4 block clocks locked? */ + x = (SUNI1x10GEXP_BITMSK_TOP_PL4_ID_DOOL + /*| SUNI1x10GEXP_BITMSK_TOP_PL4_IS_DOOL */ | + SUNI1x10GEXP_BITMSK_TOP_PL4_ID_ROOL | + SUNI1x10GEXP_BITMSK_TOP_PL4_IS_ROOL | + SUNI1x10GEXP_BITMSK_TOP_PL4_OUT_ROOL); + is_pl4_outof_lock = (val & x); + + /* ??? If this fails, might be able to software reset the XAUI part + * and try to recover... thus saving us from doing another HW reset */ + /* Has the XAUI MABC PLL circuitry stablized? */ + is_xaui_mabc_pll_locked = + (val & SUNI1x10GEXP_BITMSK_TOP_SXRA_EXPIRED); + + successful_reset = (is_pl4_reset_finished && !is_pl4_outof_lock + && is_xaui_mabc_pll_locked); + + if (netif_msg_hw(adapter)) + dev_dbg(&adapter->pdev->dev, + "PM3393 HW reset %d: pl4_reset 0x%x, val 0x%x, " + "is_pl4_outof_lock 0x%x, xaui_locked 0x%x\n", + i, is_pl4_reset_finished, val, + is_pl4_outof_lock, is_xaui_mabc_pll_locked); + } + return successful_reset ? 0 : 1; +} + +const struct gmac t1_pm3393_ops = { + .stats_update_period = STATS_TICK_SECS, + .create = pm3393_mac_create, + .reset = pm3393_mac_reset, +}; diff --git a/drivers/net/ethernet/chelsio/cxgb/regs.h b/drivers/net/ethernet/chelsio/cxgb/regs.h new file mode 100644 index 000000000000..c80bf4d6d0a6 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb/regs.h @@ -0,0 +1,2168 @@ +/***************************************************************************** + * * + * File: regs.h * + * $Revision: 1.8 $ * + * $Date: 2005/06/21 18:29:48 $ * + * Description: * + * part of the Chelsio 10Gb Ethernet Driver. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License, version 2, as * + * published by the Free Software Foundation. * + * * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * + * * + * http://www.chelsio.com * + * * + * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * + * All rights reserved. * + * * + * Maintainers: maintainers@chelsio.com * + * * + * Authors: Dimitrios Michailidis * + * Tina Yang * + * Felix Marti * + * Scott Bardone * + * Kurt Ottaway * + * Frank DiMambro * + * * + * History: * + * * + ****************************************************************************/ + +#ifndef _CXGB_REGS_H_ +#define _CXGB_REGS_H_ + +/* SGE registers */ +#define A_SG_CONTROL 0x0 + +#define S_CMDQ0_ENABLE 0 +#define V_CMDQ0_ENABLE(x) ((x) << S_CMDQ0_ENABLE) +#define F_CMDQ0_ENABLE V_CMDQ0_ENABLE(1U) + +#define S_CMDQ1_ENABLE 1 +#define V_CMDQ1_ENABLE(x) ((x) << S_CMDQ1_ENABLE) +#define F_CMDQ1_ENABLE V_CMDQ1_ENABLE(1U) + +#define S_FL0_ENABLE 2 +#define V_FL0_ENABLE(x) ((x) << S_FL0_ENABLE) +#define F_FL0_ENABLE V_FL0_ENABLE(1U) + +#define S_FL1_ENABLE 3 +#define V_FL1_ENABLE(x) ((x) << S_FL1_ENABLE) +#define F_FL1_ENABLE V_FL1_ENABLE(1U) + +#define S_CPL_ENABLE 4 +#define V_CPL_ENABLE(x) ((x) << S_CPL_ENABLE) +#define F_CPL_ENABLE V_CPL_ENABLE(1U) + +#define S_RESPONSE_QUEUE_ENABLE 5 +#define V_RESPONSE_QUEUE_ENABLE(x) ((x) << S_RESPONSE_QUEUE_ENABLE) +#define F_RESPONSE_QUEUE_ENABLE V_RESPONSE_QUEUE_ENABLE(1U) + +#define S_CMDQ_PRIORITY 6 +#define M_CMDQ_PRIORITY 0x3 +#define V_CMDQ_PRIORITY(x) ((x) << S_CMDQ_PRIORITY) +#define G_CMDQ_PRIORITY(x) (((x) >> S_CMDQ_PRIORITY) & M_CMDQ_PRIORITY) + +#define S_DISABLE_CMDQ0_GTS 8 +#define V_DISABLE_CMDQ0_GTS(x) ((x) << S_DISABLE_CMDQ0_GTS) +#define F_DISABLE_CMDQ0_GTS V_DISABLE_CMDQ0_GTS(1U) + +#define S_DISABLE_CMDQ1_GTS 9 +#define V_DISABLE_CMDQ1_GTS(x) ((x) << S_DISABLE_CMDQ1_GTS) +#define F_DISABLE_CMDQ1_GTS V_DISABLE_CMDQ1_GTS(1U) + +#define S_DISABLE_FL0_GTS 10 +#define V_DISABLE_FL0_GTS(x) ((x) << S_DISABLE_FL0_GTS) +#define F_DISABLE_FL0_GTS V_DISABLE_FL0_GTS(1U) + +#define S_DISABLE_FL1_GTS 11 +#define V_DISABLE_FL1_GTS(x) ((x) << S_DISABLE_FL1_GTS) +#define F_DISABLE_FL1_GTS V_DISABLE_FL1_GTS(1U) + +#define S_ENABLE_BIG_ENDIAN 12 +#define V_ENABLE_BIG_ENDIAN(x) ((x) << S_ENABLE_BIG_ENDIAN) +#define F_ENABLE_BIG_ENDIAN V_ENABLE_BIG_ENDIAN(1U) + +#define S_FL_SELECTION_CRITERIA 13 +#define V_FL_SELECTION_CRITERIA(x) ((x) << S_FL_SELECTION_CRITERIA) +#define F_FL_SELECTION_CRITERIA V_FL_SELECTION_CRITERIA(1U) + +#define S_ISCSI_COALESCE 14 +#define V_ISCSI_COALESCE(x) ((x) << S_ISCSI_COALESCE) +#define F_ISCSI_COALESCE V_ISCSI_COALESCE(1U) + +#define S_RX_PKT_OFFSET 15 +#define M_RX_PKT_OFFSET 0x7 +#define V_RX_PKT_OFFSET(x) ((x) << S_RX_PKT_OFFSET) +#define G_RX_PKT_OFFSET(x) (((x) >> S_RX_PKT_OFFSET) & M_RX_PKT_OFFSET) + +#define S_VLAN_XTRACT 18 +#define V_VLAN_XTRACT(x) ((x) << S_VLAN_XTRACT) +#define F_VLAN_XTRACT V_VLAN_XTRACT(1U) + +#define A_SG_DOORBELL 0x4 +#define A_SG_CMD0BASELWR 0x8 +#define A_SG_CMD0BASEUPR 0xc +#define A_SG_CMD1BASELWR 0x10 +#define A_SG_CMD1BASEUPR 0x14 +#define A_SG_FL0BASELWR 0x18 +#define A_SG_FL0BASEUPR 0x1c +#define A_SG_FL1BASELWR 0x20 +#define A_SG_FL1BASEUPR 0x24 +#define A_SG_CMD0SIZE 0x28 + +#define S_CMDQ0_SIZE 0 +#define M_CMDQ0_SIZE 0x1ffff +#define V_CMDQ0_SIZE(x) ((x) << S_CMDQ0_SIZE) +#define G_CMDQ0_SIZE(x) (((x) >> S_CMDQ0_SIZE) & M_CMDQ0_SIZE) + +#define A_SG_FL0SIZE 0x2c + +#define S_FL0_SIZE 0 +#define M_FL0_SIZE 0x1ffff +#define V_FL0_SIZE(x) ((x) << S_FL0_SIZE) +#define G_FL0_SIZE(x) (((x) >> S_FL0_SIZE) & M_FL0_SIZE) + +#define A_SG_RSPSIZE 0x30 + +#define S_RESPQ_SIZE 0 +#define M_RESPQ_SIZE 0x1ffff +#define V_RESPQ_SIZE(x) ((x) << S_RESPQ_SIZE) +#define G_RESPQ_SIZE(x) (((x) >> S_RESPQ_SIZE) & M_RESPQ_SIZE) + +#define A_SG_RSPBASELWR 0x34 +#define A_SG_RSPBASEUPR 0x38 +#define A_SG_FLTHRESHOLD 0x3c + +#define S_FL_THRESHOLD 0 +#define M_FL_THRESHOLD 0xffff +#define V_FL_THRESHOLD(x) ((x) << S_FL_THRESHOLD) +#define G_FL_THRESHOLD(x) (((x) >> S_FL_THRESHOLD) & M_FL_THRESHOLD) + +#define A_SG_RSPQUEUECREDIT 0x40 + +#define S_RESPQ_CREDIT 0 +#define M_RESPQ_CREDIT 0x1ffff +#define V_RESPQ_CREDIT(x) ((x) << S_RESPQ_CREDIT) +#define G_RESPQ_CREDIT(x) (((x) >> S_RESPQ_CREDIT) & M_RESPQ_CREDIT) + +#define A_SG_SLEEPING 0x48 + +#define S_SLEEPING 0 +#define M_SLEEPING 0xffff +#define V_SLEEPING(x) ((x) << S_SLEEPING) +#define G_SLEEPING(x) (((x) >> S_SLEEPING) & M_SLEEPING) + +#define A_SG_INTRTIMER 0x4c + +#define S_INTERRUPT_TIMER_COUNT 0 +#define M_INTERRUPT_TIMER_COUNT 0xffffff +#define V_INTERRUPT_TIMER_COUNT(x) ((x) << S_INTERRUPT_TIMER_COUNT) +#define G_INTERRUPT_TIMER_COUNT(x) (((x) >> S_INTERRUPT_TIMER_COUNT) & M_INTERRUPT_TIMER_COUNT) + +#define A_SG_CMD0PTR 0x50 + +#define S_CMDQ0_POINTER 0 +#define M_CMDQ0_POINTER 0xffff +#define V_CMDQ0_POINTER(x) ((x) << S_CMDQ0_POINTER) +#define G_CMDQ0_POINTER(x) (((x) >> S_CMDQ0_POINTER) & M_CMDQ0_POINTER) + +#define S_CURRENT_GENERATION_BIT 16 +#define V_CURRENT_GENERATION_BIT(x) ((x) << S_CURRENT_GENERATION_BIT) +#define F_CURRENT_GENERATION_BIT V_CURRENT_GENERATION_BIT(1U) + +#define A_SG_CMD1PTR 0x54 + +#define S_CMDQ1_POINTER 0 +#define M_CMDQ1_POINTER 0xffff +#define V_CMDQ1_POINTER(x) ((x) << S_CMDQ1_POINTER) +#define G_CMDQ1_POINTER(x) (((x) >> S_CMDQ1_POINTER) & M_CMDQ1_POINTER) + +#define A_SG_FL0PTR 0x58 + +#define S_FL0_POINTER 0 +#define M_FL0_POINTER 0xffff +#define V_FL0_POINTER(x) ((x) << S_FL0_POINTER) +#define G_FL0_POINTER(x) (((x) >> S_FL0_POINTER) & M_FL0_POINTER) + +#define A_SG_FL1PTR 0x5c + +#define S_FL1_POINTER 0 +#define M_FL1_POINTER 0xffff +#define V_FL1_POINTER(x) ((x) << S_FL1_POINTER) +#define G_FL1_POINTER(x) (((x) >> S_FL1_POINTER) & M_FL1_POINTER) + +#define A_SG_VERSION 0x6c + +#define S_DAY 0 +#define M_DAY 0x1f +#define V_DAY(x) ((x) << S_DAY) +#define G_DAY(x) (((x) >> S_DAY) & M_DAY) + +#define S_MONTH 5 +#define M_MONTH 0xf +#define V_MONTH(x) ((x) << S_MONTH) +#define G_MONTH(x) (((x) >> S_MONTH) & M_MONTH) + +#define A_SG_CMD1SIZE 0xb0 + +#define S_CMDQ1_SIZE 0 +#define M_CMDQ1_SIZE 0x1ffff +#define V_CMDQ1_SIZE(x) ((x) << S_CMDQ1_SIZE) +#define G_CMDQ1_SIZE(x) (((x) >> S_CMDQ1_SIZE) & M_CMDQ1_SIZE) + +#define A_SG_FL1SIZE 0xb4 + +#define S_FL1_SIZE 0 +#define M_FL1_SIZE 0x1ffff +#define V_FL1_SIZE(x) ((x) << S_FL1_SIZE) +#define G_FL1_SIZE(x) (((x) >> S_FL1_SIZE) & M_FL1_SIZE) + +#define A_SG_INT_ENABLE 0xb8 + +#define S_RESPQ_EXHAUSTED 0 +#define V_RESPQ_EXHAUSTED(x) ((x) << S_RESPQ_EXHAUSTED) +#define F_RESPQ_EXHAUSTED V_RESPQ_EXHAUSTED(1U) + +#define S_RESPQ_OVERFLOW 1 +#define V_RESPQ_OVERFLOW(x) ((x) << S_RESPQ_OVERFLOW) +#define F_RESPQ_OVERFLOW V_RESPQ_OVERFLOW(1U) + +#define S_FL_EXHAUSTED 2 +#define V_FL_EXHAUSTED(x) ((x) << S_FL_EXHAUSTED) +#define F_FL_EXHAUSTED V_FL_EXHAUSTED(1U) + +#define S_PACKET_TOO_BIG 3 +#define V_PACKET_TOO_BIG(x) ((x) << S_PACKET_TOO_BIG) +#define F_PACKET_TOO_BIG V_PACKET_TOO_BIG(1U) + +#define S_PACKET_MISMATCH 4 +#define V_PACKET_MISMATCH(x) ((x) << S_PACKET_MISMATCH) +#define F_PACKET_MISMATCH V_PACKET_MISMATCH(1U) + +#define A_SG_INT_CAUSE 0xbc +#define A_SG_RESPACCUTIMER 0xc0 + +/* MC3 registers */ +#define A_MC3_CFG 0x100 + +#define S_CLK_ENABLE 0 +#define V_CLK_ENABLE(x) ((x) << S_CLK_ENABLE) +#define F_CLK_ENABLE V_CLK_ENABLE(1U) + +#define S_READY 1 +#define V_READY(x) ((x) << S_READY) +#define F_READY V_READY(1U) + +#define S_READ_TO_WRITE_DELAY 2 +#define M_READ_TO_WRITE_DELAY 0x7 +#define V_READ_TO_WRITE_DELAY(x) ((x) << S_READ_TO_WRITE_DELAY) +#define G_READ_TO_WRITE_DELAY(x) (((x) >> S_READ_TO_WRITE_DELAY) & M_READ_TO_WRITE_DELAY) + +#define S_WRITE_TO_READ_DELAY 5 +#define M_WRITE_TO_READ_DELAY 0x7 +#define V_WRITE_TO_READ_DELAY(x) ((x) << S_WRITE_TO_READ_DELAY) +#define G_WRITE_TO_READ_DELAY(x) (((x) >> S_WRITE_TO_READ_DELAY) & M_WRITE_TO_READ_DELAY) + +#define S_MC3_BANK_CYCLE 8 +#define M_MC3_BANK_CYCLE 0xf +#define V_MC3_BANK_CYCLE(x) ((x) << S_MC3_BANK_CYCLE) +#define G_MC3_BANK_CYCLE(x) (((x) >> S_MC3_BANK_CYCLE) & M_MC3_BANK_CYCLE) + +#define S_REFRESH_CYCLE 12 +#define M_REFRESH_CYCLE 0xf +#define V_REFRESH_CYCLE(x) ((x) << S_REFRESH_CYCLE) +#define G_REFRESH_CYCLE(x) (((x) >> S_REFRESH_CYCLE) & M_REFRESH_CYCLE) + +#define S_PRECHARGE_CYCLE 16 +#define M_PRECHARGE_CYCLE 0x3 +#define V_PRECHARGE_CYCLE(x) ((x) << S_PRECHARGE_CYCLE) +#define G_PRECHARGE_CYCLE(x) (((x) >> S_PRECHARGE_CYCLE) & M_PRECHARGE_CYCLE) + +#define S_ACTIVE_TO_READ_WRITE_DELAY 18 +#define V_ACTIVE_TO_READ_WRITE_DELAY(x) ((x) << S_ACTIVE_TO_READ_WRITE_DELAY) +#define F_ACTIVE_TO_READ_WRITE_DELAY V_ACTIVE_TO_READ_WRITE_DELAY(1U) + +#define S_ACTIVE_TO_PRECHARGE_DELAY 19 +#define M_ACTIVE_TO_PRECHARGE_DELAY 0x7 +#define V_ACTIVE_TO_PRECHARGE_DELAY(x) ((x) << S_ACTIVE_TO_PRECHARGE_DELAY) +#define G_ACTIVE_TO_PRECHARGE_DELAY(x) (((x) >> S_ACTIVE_TO_PRECHARGE_DELAY) & M_ACTIVE_TO_PRECHARGE_DELAY) + +#define S_WRITE_RECOVERY_DELAY 22 +#define M_WRITE_RECOVERY_DELAY 0x3 +#define V_WRITE_RECOVERY_DELAY(x) ((x) << S_WRITE_RECOVERY_DELAY) +#define G_WRITE_RECOVERY_DELAY(x) (((x) >> S_WRITE_RECOVERY_DELAY) & M_WRITE_RECOVERY_DELAY) + +#define S_DENSITY 24 +#define M_DENSITY 0x3 +#define V_DENSITY(x) ((x) << S_DENSITY) +#define G_DENSITY(x) (((x) >> S_DENSITY) & M_DENSITY) + +#define S_ORGANIZATION 26 +#define V_ORGANIZATION(x) ((x) << S_ORGANIZATION) +#define F_ORGANIZATION V_ORGANIZATION(1U) + +#define S_BANKS 27 +#define V_BANKS(x) ((x) << S_BANKS) +#define F_BANKS V_BANKS(1U) + +#define S_UNREGISTERED 28 +#define V_UNREGISTERED(x) ((x) << S_UNREGISTERED) +#define F_UNREGISTERED V_UNREGISTERED(1U) + +#define S_MC3_WIDTH 29 +#define M_MC3_WIDTH 0x3 +#define V_MC3_WIDTH(x) ((x) << S_MC3_WIDTH) +#define G_MC3_WIDTH(x) (((x) >> S_MC3_WIDTH) & M_MC3_WIDTH) + +#define S_MC3_SLOW 31 +#define V_MC3_SLOW(x) ((x) << S_MC3_SLOW) +#define F_MC3_SLOW V_MC3_SLOW(1U) + +#define A_MC3_MODE 0x104 + +#define S_MC3_MODE 0 +#define M_MC3_MODE 0x3fff +#define V_MC3_MODE(x) ((x) << S_MC3_MODE) +#define G_MC3_MODE(x) (((x) >> S_MC3_MODE) & M_MC3_MODE) + +#define S_BUSY 31 +#define V_BUSY(x) ((x) << S_BUSY) +#define F_BUSY V_BUSY(1U) + +#define A_MC3_EXT_MODE 0x108 + +#define S_MC3_EXTENDED_MODE 0 +#define M_MC3_EXTENDED_MODE 0x3fff +#define V_MC3_EXTENDED_MODE(x) ((x) << S_MC3_EXTENDED_MODE) +#define G_MC3_EXTENDED_MODE(x) (((x) >> S_MC3_EXTENDED_MODE) & M_MC3_EXTENDED_MODE) + +#define A_MC3_PRECHARG 0x10c +#define A_MC3_REFRESH 0x110 + +#define S_REFRESH_ENABLE 0 +#define V_REFRESH_ENABLE(x) ((x) << S_REFRESH_ENABLE) +#define F_REFRESH_ENABLE V_REFRESH_ENABLE(1U) + +#define S_REFRESH_DIVISOR 1 +#define M_REFRESH_DIVISOR 0x3fff +#define V_REFRESH_DIVISOR(x) ((x) << S_REFRESH_DIVISOR) +#define G_REFRESH_DIVISOR(x) (((x) >> S_REFRESH_DIVISOR) & M_REFRESH_DIVISOR) + +#define A_MC3_STROBE 0x114 + +#define S_MASTER_DLL_RESET 0 +#define V_MASTER_DLL_RESET(x) ((x) << S_MASTER_DLL_RESET) +#define F_MASTER_DLL_RESET V_MASTER_DLL_RESET(1U) + +#define S_MASTER_DLL_TAP_COUNT 1 +#define M_MASTER_DLL_TAP_COUNT 0xff +#define V_MASTER_DLL_TAP_COUNT(x) ((x) << S_MASTER_DLL_TAP_COUNT) +#define G_MASTER_DLL_TAP_COUNT(x) (((x) >> S_MASTER_DLL_TAP_COUNT) & M_MASTER_DLL_TAP_COUNT) + +#define S_MASTER_DLL_LOCKED 9 +#define V_MASTER_DLL_LOCKED(x) ((x) << S_MASTER_DLL_LOCKED) +#define F_MASTER_DLL_LOCKED V_MASTER_DLL_LOCKED(1U) + +#define S_MASTER_DLL_MAX_TAP_COUNT 10 +#define V_MASTER_DLL_MAX_TAP_COUNT(x) ((x) << S_MASTER_DLL_MAX_TAP_COUNT) +#define F_MASTER_DLL_MAX_TAP_COUNT V_MASTER_DLL_MAX_TAP_COUNT(1U) + +#define S_MASTER_DLL_TAP_COUNT_OFFSET 11 +#define M_MASTER_DLL_TAP_COUNT_OFFSET 0x3f +#define V_MASTER_DLL_TAP_COUNT_OFFSET(x) ((x) << S_MASTER_DLL_TAP_COUNT_OFFSET) +#define G_MASTER_DLL_TAP_COUNT_OFFSET(x) (((x) >> S_MASTER_DLL_TAP_COUNT_OFFSET) & M_MASTER_DLL_TAP_COUNT_OFFSET) + +#define S_SLAVE_DLL_RESET 11 +#define V_SLAVE_DLL_RESET(x) ((x) << S_SLAVE_DLL_RESET) +#define F_SLAVE_DLL_RESET V_SLAVE_DLL_RESET(1U) + +#define S_SLAVE_DLL_DELTA 12 +#define M_SLAVE_DLL_DELTA 0xf +#define V_SLAVE_DLL_DELTA(x) ((x) << S_SLAVE_DLL_DELTA) +#define G_SLAVE_DLL_DELTA(x) (((x) >> S_SLAVE_DLL_DELTA) & M_SLAVE_DLL_DELTA) + +#define S_SLAVE_DELAY_LINE_MANUAL_TAP_COUNT 17 +#define M_SLAVE_DELAY_LINE_MANUAL_TAP_COUNT 0x3f +#define V_SLAVE_DELAY_LINE_MANUAL_TAP_COUNT(x) ((x) << S_SLAVE_DELAY_LINE_MANUAL_TAP_COUNT) +#define G_SLAVE_DELAY_LINE_MANUAL_TAP_COUNT(x) (((x) >> S_SLAVE_DELAY_LINE_MANUAL_TAP_COUNT) & M_SLAVE_DELAY_LINE_MANUAL_TAP_COUNT) + +#define S_SLAVE_DELAY_LINE_MANUAL_TAP_COUNT_ENABLE 23 +#define V_SLAVE_DELAY_LINE_MANUAL_TAP_COUNT_ENABLE(x) ((x) << S_SLAVE_DELAY_LINE_MANUAL_TAP_COUNT_ENABLE) +#define F_SLAVE_DELAY_LINE_MANUAL_TAP_COUNT_ENABLE V_SLAVE_DELAY_LINE_MANUAL_TAP_COUNT_ENABLE(1U) + +#define S_SLAVE_DELAY_LINE_TAP_COUNT 24 +#define M_SLAVE_DELAY_LINE_TAP_COUNT 0x3f +#define V_SLAVE_DELAY_LINE_TAP_COUNT(x) ((x) << S_SLAVE_DELAY_LINE_TAP_COUNT) +#define G_SLAVE_DELAY_LINE_TAP_COUNT(x) (((x) >> S_SLAVE_DELAY_LINE_TAP_COUNT) & M_SLAVE_DELAY_LINE_TAP_COUNT) + +#define A_MC3_ECC_CNTL 0x118 + +#define S_ECC_GENERATION_ENABLE 0 +#define V_ECC_GENERATION_ENABLE(x) ((x) << S_ECC_GENERATION_ENABLE) +#define F_ECC_GENERATION_ENABLE V_ECC_GENERATION_ENABLE(1U) + +#define S_ECC_CHECK_ENABLE 1 +#define V_ECC_CHECK_ENABLE(x) ((x) << S_ECC_CHECK_ENABLE) +#define F_ECC_CHECK_ENABLE V_ECC_CHECK_ENABLE(1U) + +#define S_CORRECTABLE_ERROR_COUNT 2 +#define M_CORRECTABLE_ERROR_COUNT 0xff +#define V_CORRECTABLE_ERROR_COUNT(x) ((x) << S_CORRECTABLE_ERROR_COUNT) +#define G_CORRECTABLE_ERROR_COUNT(x) (((x) >> S_CORRECTABLE_ERROR_COUNT) & M_CORRECTABLE_ERROR_COUNT) + +#define S_UNCORRECTABLE_ERROR_COUNT 10 +#define M_UNCORRECTABLE_ERROR_COUNT 0xff +#define V_UNCORRECTABLE_ERROR_COUNT(x) ((x) << S_UNCORRECTABLE_ERROR_COUNT) +#define G_UNCORRECTABLE_ERROR_COUNT(x) (((x) >> S_UNCORRECTABLE_ERROR_COUNT) & M_UNCORRECTABLE_ERROR_COUNT) + +#define A_MC3_CE_ADDR 0x11c + +#define S_MC3_CE_ADDR 4 +#define M_MC3_CE_ADDR 0xfffffff +#define V_MC3_CE_ADDR(x) ((x) << S_MC3_CE_ADDR) +#define G_MC3_CE_ADDR(x) (((x) >> S_MC3_CE_ADDR) & M_MC3_CE_ADDR) + +#define A_MC3_CE_DATA0 0x120 +#define A_MC3_CE_DATA1 0x124 +#define A_MC3_CE_DATA2 0x128 +#define A_MC3_CE_DATA3 0x12c +#define A_MC3_CE_DATA4 0x130 +#define A_MC3_UE_ADDR 0x134 + +#define S_MC3_UE_ADDR 4 +#define M_MC3_UE_ADDR 0xfffffff +#define V_MC3_UE_ADDR(x) ((x) << S_MC3_UE_ADDR) +#define G_MC3_UE_ADDR(x) (((x) >> S_MC3_UE_ADDR) & M_MC3_UE_ADDR) + +#define A_MC3_UE_DATA0 0x138 +#define A_MC3_UE_DATA1 0x13c +#define A_MC3_UE_DATA2 0x140 +#define A_MC3_UE_DATA3 0x144 +#define A_MC3_UE_DATA4 0x148 +#define A_MC3_BD_ADDR 0x14c +#define A_MC3_BD_DATA0 0x150 +#define A_MC3_BD_DATA1 0x154 +#define A_MC3_BD_DATA2 0x158 +#define A_MC3_BD_DATA3 0x15c +#define A_MC3_BD_DATA4 0x160 +#define A_MC3_BD_OP 0x164 + +#define S_BACK_DOOR_OPERATION 0 +#define V_BACK_DOOR_OPERATION(x) ((x) << S_BACK_DOOR_OPERATION) +#define F_BACK_DOOR_OPERATION V_BACK_DOOR_OPERATION(1U) + +#define A_MC3_BIST_ADDR_BEG 0x168 +#define A_MC3_BIST_ADDR_END 0x16c +#define A_MC3_BIST_DATA 0x170 +#define A_MC3_BIST_OP 0x174 + +#define S_OP 0 +#define V_OP(x) ((x) << S_OP) +#define F_OP V_OP(1U) + +#define S_DATA_PATTERN 1 +#define M_DATA_PATTERN 0x3 +#define V_DATA_PATTERN(x) ((x) << S_DATA_PATTERN) +#define G_DATA_PATTERN(x) (((x) >> S_DATA_PATTERN) & M_DATA_PATTERN) + +#define S_CONTINUOUS 3 +#define V_CONTINUOUS(x) ((x) << S_CONTINUOUS) +#define F_CONTINUOUS V_CONTINUOUS(1U) + +#define A_MC3_INT_ENABLE 0x178 + +#define S_MC3_CORR_ERR 0 +#define V_MC3_CORR_ERR(x) ((x) << S_MC3_CORR_ERR) +#define F_MC3_CORR_ERR V_MC3_CORR_ERR(1U) + +#define S_MC3_UNCORR_ERR 1 +#define V_MC3_UNCORR_ERR(x) ((x) << S_MC3_UNCORR_ERR) +#define F_MC3_UNCORR_ERR V_MC3_UNCORR_ERR(1U) + +#define S_MC3_PARITY_ERR 2 +#define M_MC3_PARITY_ERR 0xff +#define V_MC3_PARITY_ERR(x) ((x) << S_MC3_PARITY_ERR) +#define G_MC3_PARITY_ERR(x) (((x) >> S_MC3_PARITY_ERR) & M_MC3_PARITY_ERR) + +#define S_MC3_ADDR_ERR 10 +#define V_MC3_ADDR_ERR(x) ((x) << S_MC3_ADDR_ERR) +#define F_MC3_ADDR_ERR V_MC3_ADDR_ERR(1U) + +#define A_MC3_INT_CAUSE 0x17c + +/* MC4 registers */ +#define A_MC4_CFG 0x180 + +#define S_POWER_UP 0 +#define V_POWER_UP(x) ((x) << S_POWER_UP) +#define F_POWER_UP V_POWER_UP(1U) + +#define S_MC4_BANK_CYCLE 8 +#define M_MC4_BANK_CYCLE 0x7 +#define V_MC4_BANK_CYCLE(x) ((x) << S_MC4_BANK_CYCLE) +#define G_MC4_BANK_CYCLE(x) (((x) >> S_MC4_BANK_CYCLE) & M_MC4_BANK_CYCLE) + +#define S_MC4_NARROW 24 +#define V_MC4_NARROW(x) ((x) << S_MC4_NARROW) +#define F_MC4_NARROW V_MC4_NARROW(1U) + +#define S_MC4_SLOW 25 +#define V_MC4_SLOW(x) ((x) << S_MC4_SLOW) +#define F_MC4_SLOW V_MC4_SLOW(1U) + +#define S_MC4A_WIDTH 24 +#define M_MC4A_WIDTH 0x3 +#define V_MC4A_WIDTH(x) ((x) << S_MC4A_WIDTH) +#define G_MC4A_WIDTH(x) (((x) >> S_MC4A_WIDTH) & M_MC4A_WIDTH) + +#define S_MC4A_SLOW 26 +#define V_MC4A_SLOW(x) ((x) << S_MC4A_SLOW) +#define F_MC4A_SLOW V_MC4A_SLOW(1U) + +#define A_MC4_MODE 0x184 + +#define S_MC4_MODE 0 +#define M_MC4_MODE 0x7fff +#define V_MC4_MODE(x) ((x) << S_MC4_MODE) +#define G_MC4_MODE(x) (((x) >> S_MC4_MODE) & M_MC4_MODE) + +#define A_MC4_EXT_MODE 0x188 + +#define S_MC4_EXTENDED_MODE 0 +#define M_MC4_EXTENDED_MODE 0x7fff +#define V_MC4_EXTENDED_MODE(x) ((x) << S_MC4_EXTENDED_MODE) +#define G_MC4_EXTENDED_MODE(x) (((x) >> S_MC4_EXTENDED_MODE) & M_MC4_EXTENDED_MODE) + +#define A_MC4_REFRESH 0x190 +#define A_MC4_STROBE 0x194 +#define A_MC4_ECC_CNTL 0x198 +#define A_MC4_CE_ADDR 0x19c + +#define S_MC4_CE_ADDR 4 +#define M_MC4_CE_ADDR 0xffffff +#define V_MC4_CE_ADDR(x) ((x) << S_MC4_CE_ADDR) +#define G_MC4_CE_ADDR(x) (((x) >> S_MC4_CE_ADDR) & M_MC4_CE_ADDR) + +#define A_MC4_CE_DATA0 0x1a0 +#define A_MC4_CE_DATA1 0x1a4 +#define A_MC4_CE_DATA2 0x1a8 +#define A_MC4_CE_DATA3 0x1ac +#define A_MC4_CE_DATA4 0x1b0 +#define A_MC4_UE_ADDR 0x1b4 + +#define S_MC4_UE_ADDR 4 +#define M_MC4_UE_ADDR 0xffffff +#define V_MC4_UE_ADDR(x) ((x) << S_MC4_UE_ADDR) +#define G_MC4_UE_ADDR(x) (((x) >> S_MC4_UE_ADDR) & M_MC4_UE_ADDR) + +#define A_MC4_UE_DATA0 0x1b8 +#define A_MC4_UE_DATA1 0x1bc +#define A_MC4_UE_DATA2 0x1c0 +#define A_MC4_UE_DATA3 0x1c4 +#define A_MC4_UE_DATA4 0x1c8 +#define A_MC4_BD_ADDR 0x1cc + +#define S_MC4_BACK_DOOR_ADDR 0 +#define M_MC4_BACK_DOOR_ADDR 0xfffffff +#define V_MC4_BACK_DOOR_ADDR(x) ((x) << S_MC4_BACK_DOOR_ADDR) +#define G_MC4_BACK_DOOR_ADDR(x) (((x) >> S_MC4_BACK_DOOR_ADDR) & M_MC4_BACK_DOOR_ADDR) + +#define A_MC4_BD_DATA0 0x1d0 +#define A_MC4_BD_DATA1 0x1d4 +#define A_MC4_BD_DATA2 0x1d8 +#define A_MC4_BD_DATA3 0x1dc +#define A_MC4_BD_DATA4 0x1e0 +#define A_MC4_BD_OP 0x1e4 + +#define S_OPERATION 0 +#define V_OPERATION(x) ((x) << S_OPERATION) +#define F_OPERATION V_OPERATION(1U) + +#define A_MC4_BIST_ADDR_BEG 0x1e8 +#define A_MC4_BIST_ADDR_END 0x1ec +#define A_MC4_BIST_DATA 0x1f0 +#define A_MC4_BIST_OP 0x1f4 +#define A_MC4_INT_ENABLE 0x1f8 + +#define S_MC4_CORR_ERR 0 +#define V_MC4_CORR_ERR(x) ((x) << S_MC4_CORR_ERR) +#define F_MC4_CORR_ERR V_MC4_CORR_ERR(1U) + +#define S_MC4_UNCORR_ERR 1 +#define V_MC4_UNCORR_ERR(x) ((x) << S_MC4_UNCORR_ERR) +#define F_MC4_UNCORR_ERR V_MC4_UNCORR_ERR(1U) + +#define S_MC4_ADDR_ERR 2 +#define V_MC4_ADDR_ERR(x) ((x) << S_MC4_ADDR_ERR) +#define F_MC4_ADDR_ERR V_MC4_ADDR_ERR(1U) + +#define A_MC4_INT_CAUSE 0x1fc + +/* TPI registers */ +#define A_TPI_ADDR 0x280 + +#define S_TPI_ADDRESS 0 +#define M_TPI_ADDRESS 0xffffff +#define V_TPI_ADDRESS(x) ((x) << S_TPI_ADDRESS) +#define G_TPI_ADDRESS(x) (((x) >> S_TPI_ADDRESS) & M_TPI_ADDRESS) + +#define A_TPI_WR_DATA 0x284 +#define A_TPI_RD_DATA 0x288 +#define A_TPI_CSR 0x28c + +#define S_TPIWR 0 +#define V_TPIWR(x) ((x) << S_TPIWR) +#define F_TPIWR V_TPIWR(1U) + +#define S_TPIRDY 1 +#define V_TPIRDY(x) ((x) << S_TPIRDY) +#define F_TPIRDY V_TPIRDY(1U) + +#define S_INT_DIR 31 +#define V_INT_DIR(x) ((x) << S_INT_DIR) +#define F_INT_DIR V_INT_DIR(1U) + +#define A_TPI_PAR 0x29c + +#define S_TPIPAR 0 +#define M_TPIPAR 0x7f +#define V_TPIPAR(x) ((x) << S_TPIPAR) +#define G_TPIPAR(x) (((x) >> S_TPIPAR) & M_TPIPAR) + + +/* TP registers */ +#define A_TP_IN_CONFIG 0x300 + +#define S_TP_IN_CSPI_TUNNEL 0 +#define V_TP_IN_CSPI_TUNNEL(x) ((x) << S_TP_IN_CSPI_TUNNEL) +#define F_TP_IN_CSPI_TUNNEL V_TP_IN_CSPI_TUNNEL(1U) + +#define S_TP_IN_CSPI_ETHERNET 1 +#define V_TP_IN_CSPI_ETHERNET(x) ((x) << S_TP_IN_CSPI_ETHERNET) +#define F_TP_IN_CSPI_ETHERNET V_TP_IN_CSPI_ETHERNET(1U) + +#define S_TP_IN_CSPI_CPL 3 +#define V_TP_IN_CSPI_CPL(x) ((x) << S_TP_IN_CSPI_CPL) +#define F_TP_IN_CSPI_CPL V_TP_IN_CSPI_CPL(1U) + +#define S_TP_IN_CSPI_POS 4 +#define V_TP_IN_CSPI_POS(x) ((x) << S_TP_IN_CSPI_POS) +#define F_TP_IN_CSPI_POS V_TP_IN_CSPI_POS(1U) + +#define S_TP_IN_CSPI_CHECK_IP_CSUM 5 +#define V_TP_IN_CSPI_CHECK_IP_CSUM(x) ((x) << S_TP_IN_CSPI_CHECK_IP_CSUM) +#define F_TP_IN_CSPI_CHECK_IP_CSUM V_TP_IN_CSPI_CHECK_IP_CSUM(1U) + +#define S_TP_IN_CSPI_CHECK_TCP_CSUM 6 +#define V_TP_IN_CSPI_CHECK_TCP_CSUM(x) ((x) << S_TP_IN_CSPI_CHECK_TCP_CSUM) +#define F_TP_IN_CSPI_CHECK_TCP_CSUM V_TP_IN_CSPI_CHECK_TCP_CSUM(1U) + +#define S_TP_IN_ESPI_TUNNEL 7 +#define V_TP_IN_ESPI_TUNNEL(x) ((x) << S_TP_IN_ESPI_TUNNEL) +#define F_TP_IN_ESPI_TUNNEL V_TP_IN_ESPI_TUNNEL(1U) + +#define S_TP_IN_ESPI_ETHERNET 8 +#define V_TP_IN_ESPI_ETHERNET(x) ((x) << S_TP_IN_ESPI_ETHERNET) +#define F_TP_IN_ESPI_ETHERNET V_TP_IN_ESPI_ETHERNET(1U) + +#define S_TP_IN_ESPI_CPL 10 +#define V_TP_IN_ESPI_CPL(x) ((x) << S_TP_IN_ESPI_CPL) +#define F_TP_IN_ESPI_CPL V_TP_IN_ESPI_CPL(1U) + +#define S_TP_IN_ESPI_POS 11 +#define V_TP_IN_ESPI_POS(x) ((x) << S_TP_IN_ESPI_POS) +#define F_TP_IN_ESPI_POS V_TP_IN_ESPI_POS(1U) + +#define S_TP_IN_ESPI_CHECK_IP_CSUM 12 +#define V_TP_IN_ESPI_CHECK_IP_CSUM(x) ((x) << S_TP_IN_ESPI_CHECK_IP_CSUM) +#define F_TP_IN_ESPI_CHECK_IP_CSUM V_TP_IN_ESPI_CHECK_IP_CSUM(1U) + +#define S_TP_IN_ESPI_CHECK_TCP_CSUM 13 +#define V_TP_IN_ESPI_CHECK_TCP_CSUM(x) ((x) << S_TP_IN_ESPI_CHECK_TCP_CSUM) +#define F_TP_IN_ESPI_CHECK_TCP_CSUM V_TP_IN_ESPI_CHECK_TCP_CSUM(1U) + +#define S_OFFLOAD_DISABLE 14 +#define V_OFFLOAD_DISABLE(x) ((x) << S_OFFLOAD_DISABLE) +#define F_OFFLOAD_DISABLE V_OFFLOAD_DISABLE(1U) + +#define A_TP_OUT_CONFIG 0x304 + +#define S_TP_OUT_C_ETH 0 +#define V_TP_OUT_C_ETH(x) ((x) << S_TP_OUT_C_ETH) +#define F_TP_OUT_C_ETH V_TP_OUT_C_ETH(1U) + +#define S_TP_OUT_CSPI_CPL 2 +#define V_TP_OUT_CSPI_CPL(x) ((x) << S_TP_OUT_CSPI_CPL) +#define F_TP_OUT_CSPI_CPL V_TP_OUT_CSPI_CPL(1U) + +#define S_TP_OUT_CSPI_POS 3 +#define V_TP_OUT_CSPI_POS(x) ((x) << S_TP_OUT_CSPI_POS) +#define F_TP_OUT_CSPI_POS V_TP_OUT_CSPI_POS(1U) + +#define S_TP_OUT_CSPI_GENERATE_IP_CSUM 4 +#define V_TP_OUT_CSPI_GENERATE_IP_CSUM(x) ((x) << S_TP_OUT_CSPI_GENERATE_IP_CSUM) +#define F_TP_OUT_CSPI_GENERATE_IP_CSUM V_TP_OUT_CSPI_GENERATE_IP_CSUM(1U) + +#define S_TP_OUT_CSPI_GENERATE_TCP_CSUM 5 +#define V_TP_OUT_CSPI_GENERATE_TCP_CSUM(x) ((x) << S_TP_OUT_CSPI_GENERATE_TCP_CSUM) +#define F_TP_OUT_CSPI_GENERATE_TCP_CSUM V_TP_OUT_CSPI_GENERATE_TCP_CSUM(1U) + +#define S_TP_OUT_ESPI_ETHERNET 6 +#define V_TP_OUT_ESPI_ETHERNET(x) ((x) << S_TP_OUT_ESPI_ETHERNET) +#define F_TP_OUT_ESPI_ETHERNET V_TP_OUT_ESPI_ETHERNET(1U) + +#define S_TP_OUT_ESPI_TAG_ETHERNET 7 +#define V_TP_OUT_ESPI_TAG_ETHERNET(x) ((x) << S_TP_OUT_ESPI_TAG_ETHERNET) +#define F_TP_OUT_ESPI_TAG_ETHERNET V_TP_OUT_ESPI_TAG_ETHERNET(1U) + +#define S_TP_OUT_ESPI_CPL 8 +#define V_TP_OUT_ESPI_CPL(x) ((x) << S_TP_OUT_ESPI_CPL) +#define F_TP_OUT_ESPI_CPL V_TP_OUT_ESPI_CPL(1U) + +#define S_TP_OUT_ESPI_POS 9 +#define V_TP_OUT_ESPI_POS(x) ((x) << S_TP_OUT_ESPI_POS) +#define F_TP_OUT_ESPI_POS V_TP_OUT_ESPI_POS(1U) + +#define S_TP_OUT_ESPI_GENERATE_IP_CSUM 10 +#define V_TP_OUT_ESPI_GENERATE_IP_CSUM(x) ((x) << S_TP_OUT_ESPI_GENERATE_IP_CSUM) +#define F_TP_OUT_ESPI_GENERATE_IP_CSUM V_TP_OUT_ESPI_GENERATE_IP_CSUM(1U) + +#define S_TP_OUT_ESPI_GENERATE_TCP_CSUM 11 +#define V_TP_OUT_ESPI_GENERATE_TCP_CSUM(x) ((x) << S_TP_OUT_ESPI_GENERATE_TCP_CSUM) +#define F_TP_OUT_ESPI_GENERATE_TCP_CSUM V_TP_OUT_ESPI_GENERATE_TCP_CSUM(1U) + +#define A_TP_GLOBAL_CONFIG 0x308 + +#define S_IP_TTL 0 +#define M_IP_TTL 0xff +#define V_IP_TTL(x) ((x) << S_IP_TTL) +#define G_IP_TTL(x) (((x) >> S_IP_TTL) & M_IP_TTL) + +#define S_TCAM_SERVER_REGION_USAGE 8 +#define M_TCAM_SERVER_REGION_USAGE 0x3 +#define V_TCAM_SERVER_REGION_USAGE(x) ((x) << S_TCAM_SERVER_REGION_USAGE) +#define G_TCAM_SERVER_REGION_USAGE(x) (((x) >> S_TCAM_SERVER_REGION_USAGE) & M_TCAM_SERVER_REGION_USAGE) + +#define S_QOS_MAPPING 10 +#define V_QOS_MAPPING(x) ((x) << S_QOS_MAPPING) +#define F_QOS_MAPPING V_QOS_MAPPING(1U) + +#define S_TCP_CSUM 11 +#define V_TCP_CSUM(x) ((x) << S_TCP_CSUM) +#define F_TCP_CSUM V_TCP_CSUM(1U) + +#define S_UDP_CSUM 12 +#define V_UDP_CSUM(x) ((x) << S_UDP_CSUM) +#define F_UDP_CSUM V_UDP_CSUM(1U) + +#define S_IP_CSUM 13 +#define V_IP_CSUM(x) ((x) << S_IP_CSUM) +#define F_IP_CSUM V_IP_CSUM(1U) + +#define S_IP_ID_SPLIT 14 +#define V_IP_ID_SPLIT(x) ((x) << S_IP_ID_SPLIT) +#define F_IP_ID_SPLIT V_IP_ID_SPLIT(1U) + +#define S_PATH_MTU 15 +#define V_PATH_MTU(x) ((x) << S_PATH_MTU) +#define F_PATH_MTU V_PATH_MTU(1U) + +#define S_5TUPLE_LOOKUP 17 +#define M_5TUPLE_LOOKUP 0x3 +#define V_5TUPLE_LOOKUP(x) ((x) << S_5TUPLE_LOOKUP) +#define G_5TUPLE_LOOKUP(x) (((x) >> S_5TUPLE_LOOKUP) & M_5TUPLE_LOOKUP) + +#define S_IP_FRAGMENT_DROP 19 +#define V_IP_FRAGMENT_DROP(x) ((x) << S_IP_FRAGMENT_DROP) +#define F_IP_FRAGMENT_DROP V_IP_FRAGMENT_DROP(1U) + +#define S_PING_DROP 20 +#define V_PING_DROP(x) ((x) << S_PING_DROP) +#define F_PING_DROP V_PING_DROP(1U) + +#define S_PROTECT_MODE 21 +#define V_PROTECT_MODE(x) ((x) << S_PROTECT_MODE) +#define F_PROTECT_MODE V_PROTECT_MODE(1U) + +#define S_SYN_COOKIE_ALGORITHM 22 +#define V_SYN_COOKIE_ALGORITHM(x) ((x) << S_SYN_COOKIE_ALGORITHM) +#define F_SYN_COOKIE_ALGORITHM V_SYN_COOKIE_ALGORITHM(1U) + +#define S_ATTACK_FILTER 23 +#define V_ATTACK_FILTER(x) ((x) << S_ATTACK_FILTER) +#define F_ATTACK_FILTER V_ATTACK_FILTER(1U) + +#define S_INTERFACE_TYPE 24 +#define V_INTERFACE_TYPE(x) ((x) << S_INTERFACE_TYPE) +#define F_INTERFACE_TYPE V_INTERFACE_TYPE(1U) + +#define S_DISABLE_RX_FLOW_CONTROL 25 +#define V_DISABLE_RX_FLOW_CONTROL(x) ((x) << S_DISABLE_RX_FLOW_CONTROL) +#define F_DISABLE_RX_FLOW_CONTROL V_DISABLE_RX_FLOW_CONTROL(1U) + +#define S_SYN_COOKIE_PARAMETER 26 +#define M_SYN_COOKIE_PARAMETER 0x3f +#define V_SYN_COOKIE_PARAMETER(x) ((x) << S_SYN_COOKIE_PARAMETER) +#define G_SYN_COOKIE_PARAMETER(x) (((x) >> S_SYN_COOKIE_PARAMETER) & M_SYN_COOKIE_PARAMETER) + +#define A_TP_GLOBAL_RX_CREDITS 0x30c +#define A_TP_CM_SIZE 0x310 +#define A_TP_CM_MM_BASE 0x314 + +#define S_CM_MEMMGR_BASE 0 +#define M_CM_MEMMGR_BASE 0xfffffff +#define V_CM_MEMMGR_BASE(x) ((x) << S_CM_MEMMGR_BASE) +#define G_CM_MEMMGR_BASE(x) (((x) >> S_CM_MEMMGR_BASE) & M_CM_MEMMGR_BASE) + +#define A_TP_CM_TIMER_BASE 0x318 + +#define S_CM_TIMER_BASE 0 +#define M_CM_TIMER_BASE 0xfffffff +#define V_CM_TIMER_BASE(x) ((x) << S_CM_TIMER_BASE) +#define G_CM_TIMER_BASE(x) (((x) >> S_CM_TIMER_BASE) & M_CM_TIMER_BASE) + +#define A_TP_PM_SIZE 0x31c +#define A_TP_PM_TX_BASE 0x320 +#define A_TP_PM_DEFRAG_BASE 0x324 +#define A_TP_PM_RX_BASE 0x328 +#define A_TP_PM_RX_PG_SIZE 0x32c +#define A_TP_PM_RX_MAX_PGS 0x330 +#define A_TP_PM_TX_PG_SIZE 0x334 +#define A_TP_PM_TX_MAX_PGS 0x338 +#define A_TP_TCP_OPTIONS 0x340 + +#define S_TIMESTAMP 0 +#define M_TIMESTAMP 0x3 +#define V_TIMESTAMP(x) ((x) << S_TIMESTAMP) +#define G_TIMESTAMP(x) (((x) >> S_TIMESTAMP) & M_TIMESTAMP) + +#define S_WINDOW_SCALE 2 +#define M_WINDOW_SCALE 0x3 +#define V_WINDOW_SCALE(x) ((x) << S_WINDOW_SCALE) +#define G_WINDOW_SCALE(x) (((x) >> S_WINDOW_SCALE) & M_WINDOW_SCALE) + +#define S_SACK 4 +#define M_SACK 0x3 +#define V_SACK(x) ((x) << S_SACK) +#define G_SACK(x) (((x) >> S_SACK) & M_SACK) + +#define S_ECN 6 +#define M_ECN 0x3 +#define V_ECN(x) ((x) << S_ECN) +#define G_ECN(x) (((x) >> S_ECN) & M_ECN) + +#define S_SACK_ALGORITHM 8 +#define M_SACK_ALGORITHM 0x3 +#define V_SACK_ALGORITHM(x) ((x) << S_SACK_ALGORITHM) +#define G_SACK_ALGORITHM(x) (((x) >> S_SACK_ALGORITHM) & M_SACK_ALGORITHM) + +#define S_MSS 10 +#define V_MSS(x) ((x) << S_MSS) +#define F_MSS V_MSS(1U) + +#define S_DEFAULT_PEER_MSS 16 +#define M_DEFAULT_PEER_MSS 0xffff +#define V_DEFAULT_PEER_MSS(x) ((x) << S_DEFAULT_PEER_MSS) +#define G_DEFAULT_PEER_MSS(x) (((x) >> S_DEFAULT_PEER_MSS) & M_DEFAULT_PEER_MSS) + +#define A_TP_DACK_CONFIG 0x344 + +#define S_DACK_MODE 0 +#define V_DACK_MODE(x) ((x) << S_DACK_MODE) +#define F_DACK_MODE V_DACK_MODE(1U) + +#define S_DACK_AUTO_MGMT 1 +#define V_DACK_AUTO_MGMT(x) ((x) << S_DACK_AUTO_MGMT) +#define F_DACK_AUTO_MGMT V_DACK_AUTO_MGMT(1U) + +#define S_DACK_AUTO_CAREFUL 2 +#define V_DACK_AUTO_CAREFUL(x) ((x) << S_DACK_AUTO_CAREFUL) +#define F_DACK_AUTO_CAREFUL V_DACK_AUTO_CAREFUL(1U) + +#define S_DACK_MSS_SELECTOR 3 +#define M_DACK_MSS_SELECTOR 0x3 +#define V_DACK_MSS_SELECTOR(x) ((x) << S_DACK_MSS_SELECTOR) +#define G_DACK_MSS_SELECTOR(x) (((x) >> S_DACK_MSS_SELECTOR) & M_DACK_MSS_SELECTOR) + +#define S_DACK_BYTE_THRESHOLD 5 +#define M_DACK_BYTE_THRESHOLD 0xfffff +#define V_DACK_BYTE_THRESHOLD(x) ((x) << S_DACK_BYTE_THRESHOLD) +#define G_DACK_BYTE_THRESHOLD(x) (((x) >> S_DACK_BYTE_THRESHOLD) & M_DACK_BYTE_THRESHOLD) + +#define A_TP_PC_CONFIG 0x348 + +#define S_TP_ACCESS_LATENCY 0 +#define M_TP_ACCESS_LATENCY 0xf +#define V_TP_ACCESS_LATENCY(x) ((x) << S_TP_ACCESS_LATENCY) +#define G_TP_ACCESS_LATENCY(x) (((x) >> S_TP_ACCESS_LATENCY) & M_TP_ACCESS_LATENCY) + +#define S_HELD_FIN_DISABLE 4 +#define V_HELD_FIN_DISABLE(x) ((x) << S_HELD_FIN_DISABLE) +#define F_HELD_FIN_DISABLE V_HELD_FIN_DISABLE(1U) + +#define S_DDP_FC_ENABLE 5 +#define V_DDP_FC_ENABLE(x) ((x) << S_DDP_FC_ENABLE) +#define F_DDP_FC_ENABLE V_DDP_FC_ENABLE(1U) + +#define S_RDMA_ERR_ENABLE 6 +#define V_RDMA_ERR_ENABLE(x) ((x) << S_RDMA_ERR_ENABLE) +#define F_RDMA_ERR_ENABLE V_RDMA_ERR_ENABLE(1U) + +#define S_FAST_PDU_DELIVERY 7 +#define V_FAST_PDU_DELIVERY(x) ((x) << S_FAST_PDU_DELIVERY) +#define F_FAST_PDU_DELIVERY V_FAST_PDU_DELIVERY(1U) + +#define S_CLEAR_FIN 8 +#define V_CLEAR_FIN(x) ((x) << S_CLEAR_FIN) +#define F_CLEAR_FIN V_CLEAR_FIN(1U) + +#define S_DIS_TX_FILL_WIN_PUSH 12 +#define V_DIS_TX_FILL_WIN_PUSH(x) ((x) << S_DIS_TX_FILL_WIN_PUSH) +#define F_DIS_TX_FILL_WIN_PUSH V_DIS_TX_FILL_WIN_PUSH(1U) + +#define S_TP_PC_REV 30 +#define M_TP_PC_REV 0x3 +#define V_TP_PC_REV(x) ((x) << S_TP_PC_REV) +#define G_TP_PC_REV(x) (((x) >> S_TP_PC_REV) & M_TP_PC_REV) + +#define A_TP_BACKOFF0 0x350 + +#define S_ELEMENT0 0 +#define M_ELEMENT0 0xff +#define V_ELEMENT0(x) ((x) << S_ELEMENT0) +#define G_ELEMENT0(x) (((x) >> S_ELEMENT0) & M_ELEMENT0) + +#define S_ELEMENT1 8 +#define M_ELEMENT1 0xff +#define V_ELEMENT1(x) ((x) << S_ELEMENT1) +#define G_ELEMENT1(x) (((x) >> S_ELEMENT1) & M_ELEMENT1) + +#define S_ELEMENT2 16 +#define M_ELEMENT2 0xff +#define V_ELEMENT2(x) ((x) << S_ELEMENT2) +#define G_ELEMENT2(x) (((x) >> S_ELEMENT2) & M_ELEMENT2) + +#define S_ELEMENT3 24 +#define M_ELEMENT3 0xff +#define V_ELEMENT3(x) ((x) << S_ELEMENT3) +#define G_ELEMENT3(x) (((x) >> S_ELEMENT3) & M_ELEMENT3) + +#define A_TP_BACKOFF1 0x354 +#define A_TP_BACKOFF2 0x358 +#define A_TP_BACKOFF3 0x35c +#define A_TP_PARA_REG0 0x360 + +#define S_VAR_MULT 0 +#define M_VAR_MULT 0xf +#define V_VAR_MULT(x) ((x) << S_VAR_MULT) +#define G_VAR_MULT(x) (((x) >> S_VAR_MULT) & M_VAR_MULT) + +#define S_VAR_GAIN 4 +#define M_VAR_GAIN 0xf +#define V_VAR_GAIN(x) ((x) << S_VAR_GAIN) +#define G_VAR_GAIN(x) (((x) >> S_VAR_GAIN) & M_VAR_GAIN) + +#define S_SRTT_GAIN 8 +#define M_SRTT_GAIN 0xf +#define V_SRTT_GAIN(x) ((x) << S_SRTT_GAIN) +#define G_SRTT_GAIN(x) (((x) >> S_SRTT_GAIN) & M_SRTT_GAIN) + +#define S_RTTVAR_INIT 12 +#define M_RTTVAR_INIT 0xf +#define V_RTTVAR_INIT(x) ((x) << S_RTTVAR_INIT) +#define G_RTTVAR_INIT(x) (((x) >> S_RTTVAR_INIT) & M_RTTVAR_INIT) + +#define S_DUP_THRESH 20 +#define M_DUP_THRESH 0xf +#define V_DUP_THRESH(x) ((x) << S_DUP_THRESH) +#define G_DUP_THRESH(x) (((x) >> S_DUP_THRESH) & M_DUP_THRESH) + +#define S_INIT_CONG_WIN 24 +#define M_INIT_CONG_WIN 0x7 +#define V_INIT_CONG_WIN(x) ((x) << S_INIT_CONG_WIN) +#define G_INIT_CONG_WIN(x) (((x) >> S_INIT_CONG_WIN) & M_INIT_CONG_WIN) + +#define A_TP_PARA_REG1 0x364 + +#define S_INITIAL_SLOW_START_THRESHOLD 0 +#define M_INITIAL_SLOW_START_THRESHOLD 0xffff +#define V_INITIAL_SLOW_START_THRESHOLD(x) ((x) << S_INITIAL_SLOW_START_THRESHOLD) +#define G_INITIAL_SLOW_START_THRESHOLD(x) (((x) >> S_INITIAL_SLOW_START_THRESHOLD) & M_INITIAL_SLOW_START_THRESHOLD) + +#define S_RECEIVE_BUFFER_SIZE 16 +#define M_RECEIVE_BUFFER_SIZE 0xffff +#define V_RECEIVE_BUFFER_SIZE(x) ((x) << S_RECEIVE_BUFFER_SIZE) +#define G_RECEIVE_BUFFER_SIZE(x) (((x) >> S_RECEIVE_BUFFER_SIZE) & M_RECEIVE_BUFFER_SIZE) + +#define A_TP_PARA_REG2 0x368 + +#define S_RX_COALESCE_SIZE 0 +#define M_RX_COALESCE_SIZE 0xffff +#define V_RX_COALESCE_SIZE(x) ((x) << S_RX_COALESCE_SIZE) +#define G_RX_COALESCE_SIZE(x) (((x) >> S_RX_COALESCE_SIZE) & M_RX_COALESCE_SIZE) + +#define S_MAX_RX_SIZE 16 +#define M_MAX_RX_SIZE 0xffff +#define V_MAX_RX_SIZE(x) ((x) << S_MAX_RX_SIZE) +#define G_MAX_RX_SIZE(x) (((x) >> S_MAX_RX_SIZE) & M_MAX_RX_SIZE) + +#define A_TP_PARA_REG3 0x36c + +#define S_RX_COALESCING_PSH_DELIVER 0 +#define V_RX_COALESCING_PSH_DELIVER(x) ((x) << S_RX_COALESCING_PSH_DELIVER) +#define F_RX_COALESCING_PSH_DELIVER V_RX_COALESCING_PSH_DELIVER(1U) + +#define S_RX_COALESCING_ENABLE 1 +#define V_RX_COALESCING_ENABLE(x) ((x) << S_RX_COALESCING_ENABLE) +#define F_RX_COALESCING_ENABLE V_RX_COALESCING_ENABLE(1U) + +#define S_TAHOE_ENABLE 2 +#define V_TAHOE_ENABLE(x) ((x) << S_TAHOE_ENABLE) +#define F_TAHOE_ENABLE V_TAHOE_ENABLE(1U) + +#define S_MAX_REORDER_FRAGMENTS 12 +#define M_MAX_REORDER_FRAGMENTS 0x7 +#define V_MAX_REORDER_FRAGMENTS(x) ((x) << S_MAX_REORDER_FRAGMENTS) +#define G_MAX_REORDER_FRAGMENTS(x) (((x) >> S_MAX_REORDER_FRAGMENTS) & M_MAX_REORDER_FRAGMENTS) + +#define A_TP_TIMER_RESOLUTION 0x390 + +#define S_DELAYED_ACK_TIMER_RESOLUTION 0 +#define M_DELAYED_ACK_TIMER_RESOLUTION 0x3f +#define V_DELAYED_ACK_TIMER_RESOLUTION(x) ((x) << S_DELAYED_ACK_TIMER_RESOLUTION) +#define G_DELAYED_ACK_TIMER_RESOLUTION(x) (((x) >> S_DELAYED_ACK_TIMER_RESOLUTION) & M_DELAYED_ACK_TIMER_RESOLUTION) + +#define S_GENERIC_TIMER_RESOLUTION 16 +#define M_GENERIC_TIMER_RESOLUTION 0x3f +#define V_GENERIC_TIMER_RESOLUTION(x) ((x) << S_GENERIC_TIMER_RESOLUTION) +#define G_GENERIC_TIMER_RESOLUTION(x) (((x) >> S_GENERIC_TIMER_RESOLUTION) & M_GENERIC_TIMER_RESOLUTION) + +#define A_TP_2MSL 0x394 + +#define S_2MSL 0 +#define M_2MSL 0x3fffffff +#define V_2MSL(x) ((x) << S_2MSL) +#define G_2MSL(x) (((x) >> S_2MSL) & M_2MSL) + +#define A_TP_RXT_MIN 0x398 + +#define S_RETRANSMIT_TIMER_MIN 0 +#define M_RETRANSMIT_TIMER_MIN 0xffff +#define V_RETRANSMIT_TIMER_MIN(x) ((x) << S_RETRANSMIT_TIMER_MIN) +#define G_RETRANSMIT_TIMER_MIN(x) (((x) >> S_RETRANSMIT_TIMER_MIN) & M_RETRANSMIT_TIMER_MIN) + +#define A_TP_RXT_MAX 0x39c + +#define S_RETRANSMIT_TIMER_MAX 0 +#define M_RETRANSMIT_TIMER_MAX 0x3fffffff +#define V_RETRANSMIT_TIMER_MAX(x) ((x) << S_RETRANSMIT_TIMER_MAX) +#define G_RETRANSMIT_TIMER_MAX(x) (((x) >> S_RETRANSMIT_TIMER_MAX) & M_RETRANSMIT_TIMER_MAX) + +#define A_TP_PERS_MIN 0x3a0 + +#define S_PERSIST_TIMER_MIN 0 +#define M_PERSIST_TIMER_MIN 0xffff +#define V_PERSIST_TIMER_MIN(x) ((x) << S_PERSIST_TIMER_MIN) +#define G_PERSIST_TIMER_MIN(x) (((x) >> S_PERSIST_TIMER_MIN) & M_PERSIST_TIMER_MIN) + +#define A_TP_PERS_MAX 0x3a4 + +#define S_PERSIST_TIMER_MAX 0 +#define M_PERSIST_TIMER_MAX 0x3fffffff +#define V_PERSIST_TIMER_MAX(x) ((x) << S_PERSIST_TIMER_MAX) +#define G_PERSIST_TIMER_MAX(x) (((x) >> S_PERSIST_TIMER_MAX) & M_PERSIST_TIMER_MAX) + +#define A_TP_KEEP_IDLE 0x3ac + +#define S_KEEP_ALIVE_IDLE_TIME 0 +#define M_KEEP_ALIVE_IDLE_TIME 0x3fffffff +#define V_KEEP_ALIVE_IDLE_TIME(x) ((x) << S_KEEP_ALIVE_IDLE_TIME) +#define G_KEEP_ALIVE_IDLE_TIME(x) (((x) >> S_KEEP_ALIVE_IDLE_TIME) & M_KEEP_ALIVE_IDLE_TIME) + +#define A_TP_KEEP_INTVL 0x3b0 + +#define S_KEEP_ALIVE_INTERVAL_TIME 0 +#define M_KEEP_ALIVE_INTERVAL_TIME 0x3fffffff +#define V_KEEP_ALIVE_INTERVAL_TIME(x) ((x) << S_KEEP_ALIVE_INTERVAL_TIME) +#define G_KEEP_ALIVE_INTERVAL_TIME(x) (((x) >> S_KEEP_ALIVE_INTERVAL_TIME) & M_KEEP_ALIVE_INTERVAL_TIME) + +#define A_TP_INIT_SRTT 0x3b4 + +#define S_INITIAL_SRTT 0 +#define M_INITIAL_SRTT 0xffff +#define V_INITIAL_SRTT(x) ((x) << S_INITIAL_SRTT) +#define G_INITIAL_SRTT(x) (((x) >> S_INITIAL_SRTT) & M_INITIAL_SRTT) + +#define A_TP_DACK_TIME 0x3b8 + +#define S_DELAYED_ACK_TIME 0 +#define M_DELAYED_ACK_TIME 0x7ff +#define V_DELAYED_ACK_TIME(x) ((x) << S_DELAYED_ACK_TIME) +#define G_DELAYED_ACK_TIME(x) (((x) >> S_DELAYED_ACK_TIME) & M_DELAYED_ACK_TIME) + +#define A_TP_FINWAIT2_TIME 0x3bc + +#define S_FINWAIT2_TIME 0 +#define M_FINWAIT2_TIME 0x3fffffff +#define V_FINWAIT2_TIME(x) ((x) << S_FINWAIT2_TIME) +#define G_FINWAIT2_TIME(x) (((x) >> S_FINWAIT2_TIME) & M_FINWAIT2_TIME) + +#define A_TP_FAST_FINWAIT2_TIME 0x3c0 + +#define S_FAST_FINWAIT2_TIME 0 +#define M_FAST_FINWAIT2_TIME 0x3fffffff +#define V_FAST_FINWAIT2_TIME(x) ((x) << S_FAST_FINWAIT2_TIME) +#define G_FAST_FINWAIT2_TIME(x) (((x) >> S_FAST_FINWAIT2_TIME) & M_FAST_FINWAIT2_TIME) + +#define A_TP_SHIFT_CNT 0x3c4 + +#define S_KEEPALIVE_MAX 0 +#define M_KEEPALIVE_MAX 0xff +#define V_KEEPALIVE_MAX(x) ((x) << S_KEEPALIVE_MAX) +#define G_KEEPALIVE_MAX(x) (((x) >> S_KEEPALIVE_MAX) & M_KEEPALIVE_MAX) + +#define S_WINDOWPROBE_MAX 8 +#define M_WINDOWPROBE_MAX 0xff +#define V_WINDOWPROBE_MAX(x) ((x) << S_WINDOWPROBE_MAX) +#define G_WINDOWPROBE_MAX(x) (((x) >> S_WINDOWPROBE_MAX) & M_WINDOWPROBE_MAX) + +#define S_RETRANSMISSION_MAX 16 +#define M_RETRANSMISSION_MAX 0xff +#define V_RETRANSMISSION_MAX(x) ((x) << S_RETRANSMISSION_MAX) +#define G_RETRANSMISSION_MAX(x) (((x) >> S_RETRANSMISSION_MAX) & M_RETRANSMISSION_MAX) + +#define S_SYN_MAX 24 +#define M_SYN_MAX 0xff +#define V_SYN_MAX(x) ((x) << S_SYN_MAX) +#define G_SYN_MAX(x) (((x) >> S_SYN_MAX) & M_SYN_MAX) + +#define A_TP_QOS_REG0 0x3e0 + +#define S_L3_VALUE 0 +#define M_L3_VALUE 0x3f +#define V_L3_VALUE(x) ((x) << S_L3_VALUE) +#define G_L3_VALUE(x) (((x) >> S_L3_VALUE) & M_L3_VALUE) + +#define A_TP_QOS_REG1 0x3e4 +#define A_TP_QOS_REG2 0x3e8 +#define A_TP_QOS_REG3 0x3ec +#define A_TP_QOS_REG4 0x3f0 +#define A_TP_QOS_REG5 0x3f4 +#define A_TP_QOS_REG6 0x3f8 +#define A_TP_QOS_REG7 0x3fc +#define A_TP_MTU_REG0 0x404 +#define A_TP_MTU_REG1 0x408 +#define A_TP_MTU_REG2 0x40c +#define A_TP_MTU_REG3 0x410 +#define A_TP_MTU_REG4 0x414 +#define A_TP_MTU_REG5 0x418 +#define A_TP_MTU_REG6 0x41c +#define A_TP_MTU_REG7 0x420 +#define A_TP_RESET 0x44c + +#define S_TP_RESET 0 +#define V_TP_RESET(x) ((x) << S_TP_RESET) +#define F_TP_RESET V_TP_RESET(1U) + +#define S_CM_MEMMGR_INIT 1 +#define V_CM_MEMMGR_INIT(x) ((x) << S_CM_MEMMGR_INIT) +#define F_CM_MEMMGR_INIT V_CM_MEMMGR_INIT(1U) + +#define A_TP_MIB_INDEX 0x450 +#define A_TP_MIB_DATA 0x454 +#define A_TP_SYNC_TIME_HI 0x458 +#define A_TP_SYNC_TIME_LO 0x45c +#define A_TP_CM_MM_RX_FLST_BASE 0x460 + +#define S_CM_MEMMGR_RX_FREE_LIST_BASE 0 +#define M_CM_MEMMGR_RX_FREE_LIST_BASE 0xfffffff +#define V_CM_MEMMGR_RX_FREE_LIST_BASE(x) ((x) << S_CM_MEMMGR_RX_FREE_LIST_BASE) +#define G_CM_MEMMGR_RX_FREE_LIST_BASE(x) (((x) >> S_CM_MEMMGR_RX_FREE_LIST_BASE) & M_CM_MEMMGR_RX_FREE_LIST_BASE) + +#define A_TP_CM_MM_TX_FLST_BASE 0x464 + +#define S_CM_MEMMGR_TX_FREE_LIST_BASE 0 +#define M_CM_MEMMGR_TX_FREE_LIST_BASE 0xfffffff +#define V_CM_MEMMGR_TX_FREE_LIST_BASE(x) ((x) << S_CM_MEMMGR_TX_FREE_LIST_BASE) +#define G_CM_MEMMGR_TX_FREE_LIST_BASE(x) (((x) >> S_CM_MEMMGR_TX_FREE_LIST_BASE) & M_CM_MEMMGR_TX_FREE_LIST_BASE) + +#define A_TP_CM_MM_P_FLST_BASE 0x468 + +#define S_CM_MEMMGR_PSTRUCT_FREE_LIST_BASE 0 +#define M_CM_MEMMGR_PSTRUCT_FREE_LIST_BASE 0xfffffff +#define V_CM_MEMMGR_PSTRUCT_FREE_LIST_BASE(x) ((x) << S_CM_MEMMGR_PSTRUCT_FREE_LIST_BASE) +#define G_CM_MEMMGR_PSTRUCT_FREE_LIST_BASE(x) (((x) >> S_CM_MEMMGR_PSTRUCT_FREE_LIST_BASE) & M_CM_MEMMGR_PSTRUCT_FREE_LIST_BASE) + +#define A_TP_CM_MM_MAX_P 0x46c + +#define S_CM_MEMMGR_MAX_PSTRUCT 0 +#define M_CM_MEMMGR_MAX_PSTRUCT 0xfffffff +#define V_CM_MEMMGR_MAX_PSTRUCT(x) ((x) << S_CM_MEMMGR_MAX_PSTRUCT) +#define G_CM_MEMMGR_MAX_PSTRUCT(x) (((x) >> S_CM_MEMMGR_MAX_PSTRUCT) & M_CM_MEMMGR_MAX_PSTRUCT) + +#define A_TP_INT_ENABLE 0x470 + +#define S_TX_FREE_LIST_EMPTY 0 +#define V_TX_FREE_LIST_EMPTY(x) ((x) << S_TX_FREE_LIST_EMPTY) +#define F_TX_FREE_LIST_EMPTY V_TX_FREE_LIST_EMPTY(1U) + +#define S_RX_FREE_LIST_EMPTY 1 +#define V_RX_FREE_LIST_EMPTY(x) ((x) << S_RX_FREE_LIST_EMPTY) +#define F_RX_FREE_LIST_EMPTY V_RX_FREE_LIST_EMPTY(1U) + +#define A_TP_INT_CAUSE 0x474 +#define A_TP_TIMER_SEPARATOR 0x4a4 + +#define S_DISABLE_PAST_TIMER_INSERTION 0 +#define V_DISABLE_PAST_TIMER_INSERTION(x) ((x) << S_DISABLE_PAST_TIMER_INSERTION) +#define F_DISABLE_PAST_TIMER_INSERTION V_DISABLE_PAST_TIMER_INSERTION(1U) + +#define S_MODULATION_TIMER_SEPARATOR 1 +#define M_MODULATION_TIMER_SEPARATOR 0x7fff +#define V_MODULATION_TIMER_SEPARATOR(x) ((x) << S_MODULATION_TIMER_SEPARATOR) +#define G_MODULATION_TIMER_SEPARATOR(x) (((x) >> S_MODULATION_TIMER_SEPARATOR) & M_MODULATION_TIMER_SEPARATOR) + +#define S_GLOBAL_TIMER_SEPARATOR 16 +#define M_GLOBAL_TIMER_SEPARATOR 0xffff +#define V_GLOBAL_TIMER_SEPARATOR(x) ((x) << S_GLOBAL_TIMER_SEPARATOR) +#define G_GLOBAL_TIMER_SEPARATOR(x) (((x) >> S_GLOBAL_TIMER_SEPARATOR) & M_GLOBAL_TIMER_SEPARATOR) + +#define A_TP_CM_FC_MODE 0x4b0 +#define A_TP_PC_CONGESTION_CNTL 0x4b4 +#define A_TP_TX_DROP_CONFIG 0x4b8 + +#define S_ENABLE_TX_DROP 31 +#define V_ENABLE_TX_DROP(x) ((x) << S_ENABLE_TX_DROP) +#define F_ENABLE_TX_DROP V_ENABLE_TX_DROP(1U) + +#define S_ENABLE_TX_ERROR 30 +#define V_ENABLE_TX_ERROR(x) ((x) << S_ENABLE_TX_ERROR) +#define F_ENABLE_TX_ERROR V_ENABLE_TX_ERROR(1U) + +#define S_DROP_TICKS_CNT 4 +#define M_DROP_TICKS_CNT 0x3ffffff +#define V_DROP_TICKS_CNT(x) ((x) << S_DROP_TICKS_CNT) +#define G_DROP_TICKS_CNT(x) (((x) >> S_DROP_TICKS_CNT) & M_DROP_TICKS_CNT) + +#define S_NUM_PKTS_DROPPED 0 +#define M_NUM_PKTS_DROPPED 0xf +#define V_NUM_PKTS_DROPPED(x) ((x) << S_NUM_PKTS_DROPPED) +#define G_NUM_PKTS_DROPPED(x) (((x) >> S_NUM_PKTS_DROPPED) & M_NUM_PKTS_DROPPED) + +#define A_TP_TX_DROP_COUNT 0x4bc + +/* RAT registers */ +#define A_RAT_ROUTE_CONTROL 0x580 + +#define S_USE_ROUTE_TABLE 0 +#define V_USE_ROUTE_TABLE(x) ((x) << S_USE_ROUTE_TABLE) +#define F_USE_ROUTE_TABLE V_USE_ROUTE_TABLE(1U) + +#define S_ENABLE_CSPI 1 +#define V_ENABLE_CSPI(x) ((x) << S_ENABLE_CSPI) +#define F_ENABLE_CSPI V_ENABLE_CSPI(1U) + +#define S_ENABLE_PCIX 2 +#define V_ENABLE_PCIX(x) ((x) << S_ENABLE_PCIX) +#define F_ENABLE_PCIX V_ENABLE_PCIX(1U) + +#define A_RAT_ROUTE_TABLE_INDEX 0x584 + +#define S_ROUTE_TABLE_INDEX 0 +#define M_ROUTE_TABLE_INDEX 0xf +#define V_ROUTE_TABLE_INDEX(x) ((x) << S_ROUTE_TABLE_INDEX) +#define G_ROUTE_TABLE_INDEX(x) (((x) >> S_ROUTE_TABLE_INDEX) & M_ROUTE_TABLE_INDEX) + +#define A_RAT_ROUTE_TABLE_DATA 0x588 +#define A_RAT_NO_ROUTE 0x58c + +#define S_CPL_OPCODE 0 +#define M_CPL_OPCODE 0xff +#define V_CPL_OPCODE(x) ((x) << S_CPL_OPCODE) +#define G_CPL_OPCODE(x) (((x) >> S_CPL_OPCODE) & M_CPL_OPCODE) + +#define A_RAT_INTR_ENABLE 0x590 + +#define S_ZEROROUTEERROR 0 +#define V_ZEROROUTEERROR(x) ((x) << S_ZEROROUTEERROR) +#define F_ZEROROUTEERROR V_ZEROROUTEERROR(1U) + +#define S_CSPIFRAMINGERROR 1 +#define V_CSPIFRAMINGERROR(x) ((x) << S_CSPIFRAMINGERROR) +#define F_CSPIFRAMINGERROR V_CSPIFRAMINGERROR(1U) + +#define S_SGEFRAMINGERROR 2 +#define V_SGEFRAMINGERROR(x) ((x) << S_SGEFRAMINGERROR) +#define F_SGEFRAMINGERROR V_SGEFRAMINGERROR(1U) + +#define S_TPFRAMINGERROR 3 +#define V_TPFRAMINGERROR(x) ((x) << S_TPFRAMINGERROR) +#define F_TPFRAMINGERROR V_TPFRAMINGERROR(1U) + +#define A_RAT_INTR_CAUSE 0x594 + +/* CSPI registers */ +#define A_CSPI_RX_AE_WM 0x810 +#define A_CSPI_RX_AF_WM 0x814 +#define A_CSPI_CALENDAR_LEN 0x818 + +#define S_CALENDARLENGTH 0 +#define M_CALENDARLENGTH 0xffff +#define V_CALENDARLENGTH(x) ((x) << S_CALENDARLENGTH) +#define G_CALENDARLENGTH(x) (((x) >> S_CALENDARLENGTH) & M_CALENDARLENGTH) + +#define A_CSPI_FIFO_STATUS_ENABLE 0x820 + +#define S_FIFOSTATUSENABLE 0 +#define V_FIFOSTATUSENABLE(x) ((x) << S_FIFOSTATUSENABLE) +#define F_FIFOSTATUSENABLE V_FIFOSTATUSENABLE(1U) + +#define A_CSPI_MAXBURST1_MAXBURST2 0x828 + +#define S_MAXBURST1 0 +#define M_MAXBURST1 0xffff +#define V_MAXBURST1(x) ((x) << S_MAXBURST1) +#define G_MAXBURST1(x) (((x) >> S_MAXBURST1) & M_MAXBURST1) + +#define S_MAXBURST2 16 +#define M_MAXBURST2 0xffff +#define V_MAXBURST2(x) ((x) << S_MAXBURST2) +#define G_MAXBURST2(x) (((x) >> S_MAXBURST2) & M_MAXBURST2) + +#define A_CSPI_TRAIN 0x82c + +#define S_CSPI_TRAIN_ALPHA 0 +#define M_CSPI_TRAIN_ALPHA 0xffff +#define V_CSPI_TRAIN_ALPHA(x) ((x) << S_CSPI_TRAIN_ALPHA) +#define G_CSPI_TRAIN_ALPHA(x) (((x) >> S_CSPI_TRAIN_ALPHA) & M_CSPI_TRAIN_ALPHA) + +#define S_CSPI_TRAIN_DATA_MAXT 16 +#define M_CSPI_TRAIN_DATA_MAXT 0xffff +#define V_CSPI_TRAIN_DATA_MAXT(x) ((x) << S_CSPI_TRAIN_DATA_MAXT) +#define G_CSPI_TRAIN_DATA_MAXT(x) (((x) >> S_CSPI_TRAIN_DATA_MAXT) & M_CSPI_TRAIN_DATA_MAXT) + +#define A_CSPI_INTR_STATUS 0x848 + +#define S_DIP4ERR 0 +#define V_DIP4ERR(x) ((x) << S_DIP4ERR) +#define F_DIP4ERR V_DIP4ERR(1U) + +#define S_RXDROP 1 +#define V_RXDROP(x) ((x) << S_RXDROP) +#define F_RXDROP V_RXDROP(1U) + +#define S_TXDROP 2 +#define V_TXDROP(x) ((x) << S_TXDROP) +#define F_TXDROP V_TXDROP(1U) + +#define S_RXOVERFLOW 3 +#define V_RXOVERFLOW(x) ((x) << S_RXOVERFLOW) +#define F_RXOVERFLOW V_RXOVERFLOW(1U) + +#define S_RAMPARITYERR 4 +#define V_RAMPARITYERR(x) ((x) << S_RAMPARITYERR) +#define F_RAMPARITYERR V_RAMPARITYERR(1U) + +#define A_CSPI_INTR_ENABLE 0x84c + +/* ESPI registers */ +#define A_ESPI_SCH_TOKEN0 0x880 + +#define S_SCHTOKEN0 0 +#define M_SCHTOKEN0 0xffff +#define V_SCHTOKEN0(x) ((x) << S_SCHTOKEN0) +#define G_SCHTOKEN0(x) (((x) >> S_SCHTOKEN0) & M_SCHTOKEN0) + +#define A_ESPI_SCH_TOKEN1 0x884 + +#define S_SCHTOKEN1 0 +#define M_SCHTOKEN1 0xffff +#define V_SCHTOKEN1(x) ((x) << S_SCHTOKEN1) +#define G_SCHTOKEN1(x) (((x) >> S_SCHTOKEN1) & M_SCHTOKEN1) + +#define A_ESPI_SCH_TOKEN2 0x888 + +#define S_SCHTOKEN2 0 +#define M_SCHTOKEN2 0xffff +#define V_SCHTOKEN2(x) ((x) << S_SCHTOKEN2) +#define G_SCHTOKEN2(x) (((x) >> S_SCHTOKEN2) & M_SCHTOKEN2) + +#define A_ESPI_SCH_TOKEN3 0x88c + +#define S_SCHTOKEN3 0 +#define M_SCHTOKEN3 0xffff +#define V_SCHTOKEN3(x) ((x) << S_SCHTOKEN3) +#define G_SCHTOKEN3(x) (((x) >> S_SCHTOKEN3) & M_SCHTOKEN3) + +#define A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK 0x890 + +#define S_ALMOSTEMPTY 0 +#define M_ALMOSTEMPTY 0xffff +#define V_ALMOSTEMPTY(x) ((x) << S_ALMOSTEMPTY) +#define G_ALMOSTEMPTY(x) (((x) >> S_ALMOSTEMPTY) & M_ALMOSTEMPTY) + +#define A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK 0x894 + +#define S_ALMOSTFULL 0 +#define M_ALMOSTFULL 0xffff +#define V_ALMOSTFULL(x) ((x) << S_ALMOSTFULL) +#define G_ALMOSTFULL(x) (((x) >> S_ALMOSTFULL) & M_ALMOSTFULL) + +#define A_ESPI_CALENDAR_LENGTH 0x898 +#define A_PORT_CONFIG 0x89c + +#define S_RX_NPORTS 0 +#define M_RX_NPORTS 0xff +#define V_RX_NPORTS(x) ((x) << S_RX_NPORTS) +#define G_RX_NPORTS(x) (((x) >> S_RX_NPORTS) & M_RX_NPORTS) + +#define S_TX_NPORTS 8 +#define M_TX_NPORTS 0xff +#define V_TX_NPORTS(x) ((x) << S_TX_NPORTS) +#define G_TX_NPORTS(x) (((x) >> S_TX_NPORTS) & M_TX_NPORTS) + +#define A_ESPI_FIFO_STATUS_ENABLE 0x8a0 + +#define S_RXSTATUSENABLE 0 +#define V_RXSTATUSENABLE(x) ((x) << S_RXSTATUSENABLE) +#define F_RXSTATUSENABLE V_RXSTATUSENABLE(1U) + +#define S_TXDROPENABLE 1 +#define V_TXDROPENABLE(x) ((x) << S_TXDROPENABLE) +#define F_TXDROPENABLE V_TXDROPENABLE(1U) + +#define S_RXENDIANMODE 2 +#define V_RXENDIANMODE(x) ((x) << S_RXENDIANMODE) +#define F_RXENDIANMODE V_RXENDIANMODE(1U) + +#define S_TXENDIANMODE 3 +#define V_TXENDIANMODE(x) ((x) << S_TXENDIANMODE) +#define F_TXENDIANMODE V_TXENDIANMODE(1U) + +#define S_INTEL1010MODE 4 +#define V_INTEL1010MODE(x) ((x) << S_INTEL1010MODE) +#define F_INTEL1010MODE V_INTEL1010MODE(1U) + +#define A_ESPI_MAXBURST1_MAXBURST2 0x8a8 +#define A_ESPI_TRAIN 0x8ac + +#define S_MAXTRAINALPHA 0 +#define M_MAXTRAINALPHA 0xffff +#define V_MAXTRAINALPHA(x) ((x) << S_MAXTRAINALPHA) +#define G_MAXTRAINALPHA(x) (((x) >> S_MAXTRAINALPHA) & M_MAXTRAINALPHA) + +#define S_MAXTRAINDATA 16 +#define M_MAXTRAINDATA 0xffff +#define V_MAXTRAINDATA(x) ((x) << S_MAXTRAINDATA) +#define G_MAXTRAINDATA(x) (((x) >> S_MAXTRAINDATA) & M_MAXTRAINDATA) + +#define A_RAM_STATUS 0x8b0 + +#define S_RXFIFOPARITYERROR 0 +#define M_RXFIFOPARITYERROR 0x3ff +#define V_RXFIFOPARITYERROR(x) ((x) << S_RXFIFOPARITYERROR) +#define G_RXFIFOPARITYERROR(x) (((x) >> S_RXFIFOPARITYERROR) & M_RXFIFOPARITYERROR) + +#define S_TXFIFOPARITYERROR 10 +#define M_TXFIFOPARITYERROR 0x3ff +#define V_TXFIFOPARITYERROR(x) ((x) << S_TXFIFOPARITYERROR) +#define G_TXFIFOPARITYERROR(x) (((x) >> S_TXFIFOPARITYERROR) & M_TXFIFOPARITYERROR) + +#define S_RXFIFOOVERFLOW 20 +#define M_RXFIFOOVERFLOW 0x3ff +#define V_RXFIFOOVERFLOW(x) ((x) << S_RXFIFOOVERFLOW) +#define G_RXFIFOOVERFLOW(x) (((x) >> S_RXFIFOOVERFLOW) & M_RXFIFOOVERFLOW) + +#define A_TX_DROP_COUNT0 0x8b4 + +#define S_TXPORT0DROPCNT 0 +#define M_TXPORT0DROPCNT 0xffff +#define V_TXPORT0DROPCNT(x) ((x) << S_TXPORT0DROPCNT) +#define G_TXPORT0DROPCNT(x) (((x) >> S_TXPORT0DROPCNT) & M_TXPORT0DROPCNT) + +#define S_TXPORT1DROPCNT 16 +#define M_TXPORT1DROPCNT 0xffff +#define V_TXPORT1DROPCNT(x) ((x) << S_TXPORT1DROPCNT) +#define G_TXPORT1DROPCNT(x) (((x) >> S_TXPORT1DROPCNT) & M_TXPORT1DROPCNT) + +#define A_TX_DROP_COUNT1 0x8b8 + +#define S_TXPORT2DROPCNT 0 +#define M_TXPORT2DROPCNT 0xffff +#define V_TXPORT2DROPCNT(x) ((x) << S_TXPORT2DROPCNT) +#define G_TXPORT2DROPCNT(x) (((x) >> S_TXPORT2DROPCNT) & M_TXPORT2DROPCNT) + +#define S_TXPORT3DROPCNT 16 +#define M_TXPORT3DROPCNT 0xffff +#define V_TXPORT3DROPCNT(x) ((x) << S_TXPORT3DROPCNT) +#define G_TXPORT3DROPCNT(x) (((x) >> S_TXPORT3DROPCNT) & M_TXPORT3DROPCNT) + +#define A_RX_DROP_COUNT0 0x8bc + +#define S_RXPORT0DROPCNT 0 +#define M_RXPORT0DROPCNT 0xffff +#define V_RXPORT0DROPCNT(x) ((x) << S_RXPORT0DROPCNT) +#define G_RXPORT0DROPCNT(x) (((x) >> S_RXPORT0DROPCNT) & M_RXPORT0DROPCNT) + +#define S_RXPORT1DROPCNT 16 +#define M_RXPORT1DROPCNT 0xffff +#define V_RXPORT1DROPCNT(x) ((x) << S_RXPORT1DROPCNT) +#define G_RXPORT1DROPCNT(x) (((x) >> S_RXPORT1DROPCNT) & M_RXPORT1DROPCNT) + +#define A_RX_DROP_COUNT1 0x8c0 + +#define S_RXPORT2DROPCNT 0 +#define M_RXPORT2DROPCNT 0xffff +#define V_RXPORT2DROPCNT(x) ((x) << S_RXPORT2DROPCNT) +#define G_RXPORT2DROPCNT(x) (((x) >> S_RXPORT2DROPCNT) & M_RXPORT2DROPCNT) + +#define S_RXPORT3DROPCNT 16 +#define M_RXPORT3DROPCNT 0xffff +#define V_RXPORT3DROPCNT(x) ((x) << S_RXPORT3DROPCNT) +#define G_RXPORT3DROPCNT(x) (((x) >> S_RXPORT3DROPCNT) & M_RXPORT3DROPCNT) + +#define A_DIP4_ERROR_COUNT 0x8c4 + +#define S_DIP4ERRORCNT 0 +#define M_DIP4ERRORCNT 0xfff +#define V_DIP4ERRORCNT(x) ((x) << S_DIP4ERRORCNT) +#define G_DIP4ERRORCNT(x) (((x) >> S_DIP4ERRORCNT) & M_DIP4ERRORCNT) + +#define S_DIP4ERRORCNTSHADOW 12 +#define M_DIP4ERRORCNTSHADOW 0xfff +#define V_DIP4ERRORCNTSHADOW(x) ((x) << S_DIP4ERRORCNTSHADOW) +#define G_DIP4ERRORCNTSHADOW(x) (((x) >> S_DIP4ERRORCNTSHADOW) & M_DIP4ERRORCNTSHADOW) + +#define S_TRICN_RX_TRAIN_ERR 24 +#define V_TRICN_RX_TRAIN_ERR(x) ((x) << S_TRICN_RX_TRAIN_ERR) +#define F_TRICN_RX_TRAIN_ERR V_TRICN_RX_TRAIN_ERR(1U) + +#define S_TRICN_RX_TRAINING 25 +#define V_TRICN_RX_TRAINING(x) ((x) << S_TRICN_RX_TRAINING) +#define F_TRICN_RX_TRAINING V_TRICN_RX_TRAINING(1U) + +#define S_TRICN_RX_TRAIN_OK 26 +#define V_TRICN_RX_TRAIN_OK(x) ((x) << S_TRICN_RX_TRAIN_OK) +#define F_TRICN_RX_TRAIN_OK V_TRICN_RX_TRAIN_OK(1U) + +#define A_ESPI_INTR_STATUS 0x8c8 + +#define S_DIP2PARITYERR 5 +#define V_DIP2PARITYERR(x) ((x) << S_DIP2PARITYERR) +#define F_DIP2PARITYERR V_DIP2PARITYERR(1U) + +#define A_ESPI_INTR_ENABLE 0x8cc +#define A_RX_DROP_THRESHOLD 0x8d0 +#define A_ESPI_RX_RESET 0x8ec + +#define S_ESPI_RX_LNK_RST 0 +#define V_ESPI_RX_LNK_RST(x) ((x) << S_ESPI_RX_LNK_RST) +#define F_ESPI_RX_LNK_RST V_ESPI_RX_LNK_RST(1U) + +#define S_ESPI_RX_CORE_RST 1 +#define V_ESPI_RX_CORE_RST(x) ((x) << S_ESPI_RX_CORE_RST) +#define F_ESPI_RX_CORE_RST V_ESPI_RX_CORE_RST(1U) + +#define S_RX_CLK_STATUS 2 +#define V_RX_CLK_STATUS(x) ((x) << S_RX_CLK_STATUS) +#define F_RX_CLK_STATUS V_RX_CLK_STATUS(1U) + +#define A_ESPI_MISC_CONTROL 0x8f0 + +#define S_OUT_OF_SYNC_COUNT 0 +#define M_OUT_OF_SYNC_COUNT 0xf +#define V_OUT_OF_SYNC_COUNT(x) ((x) << S_OUT_OF_SYNC_COUNT) +#define G_OUT_OF_SYNC_COUNT(x) (((x) >> S_OUT_OF_SYNC_COUNT) & M_OUT_OF_SYNC_COUNT) + +#define S_DIP2_COUNT_MODE_ENABLE 4 +#define V_DIP2_COUNT_MODE_ENABLE(x) ((x) << S_DIP2_COUNT_MODE_ENABLE) +#define F_DIP2_COUNT_MODE_ENABLE V_DIP2_COUNT_MODE_ENABLE(1U) + +#define S_DIP2_PARITY_ERR_THRES 5 +#define M_DIP2_PARITY_ERR_THRES 0xf +#define V_DIP2_PARITY_ERR_THRES(x) ((x) << S_DIP2_PARITY_ERR_THRES) +#define G_DIP2_PARITY_ERR_THRES(x) (((x) >> S_DIP2_PARITY_ERR_THRES) & M_DIP2_PARITY_ERR_THRES) + +#define S_DIP4_THRES 9 +#define M_DIP4_THRES 0xfff +#define V_DIP4_THRES(x) ((x) << S_DIP4_THRES) +#define G_DIP4_THRES(x) (((x) >> S_DIP4_THRES) & M_DIP4_THRES) + +#define S_DIP4_THRES_ENABLE 21 +#define V_DIP4_THRES_ENABLE(x) ((x) << S_DIP4_THRES_ENABLE) +#define F_DIP4_THRES_ENABLE V_DIP4_THRES_ENABLE(1U) + +#define S_FORCE_DISABLE_STATUS 22 +#define V_FORCE_DISABLE_STATUS(x) ((x) << S_FORCE_DISABLE_STATUS) +#define F_FORCE_DISABLE_STATUS V_FORCE_DISABLE_STATUS(1U) + +#define S_DYNAMIC_DESKEW 23 +#define V_DYNAMIC_DESKEW(x) ((x) << S_DYNAMIC_DESKEW) +#define F_DYNAMIC_DESKEW V_DYNAMIC_DESKEW(1U) + +#define S_MONITORED_PORT_NUM 25 +#define M_MONITORED_PORT_NUM 0x3 +#define V_MONITORED_PORT_NUM(x) ((x) << S_MONITORED_PORT_NUM) +#define G_MONITORED_PORT_NUM(x) (((x) >> S_MONITORED_PORT_NUM) & M_MONITORED_PORT_NUM) + +#define S_MONITORED_DIRECTION 27 +#define V_MONITORED_DIRECTION(x) ((x) << S_MONITORED_DIRECTION) +#define F_MONITORED_DIRECTION V_MONITORED_DIRECTION(1U) + +#define S_MONITORED_INTERFACE 28 +#define V_MONITORED_INTERFACE(x) ((x) << S_MONITORED_INTERFACE) +#define F_MONITORED_INTERFACE V_MONITORED_INTERFACE(1U) + +#define A_ESPI_DIP2_ERR_COUNT 0x8f4 + +#define S_DIP2_ERR_CNT 0 +#define M_DIP2_ERR_CNT 0xf +#define V_DIP2_ERR_CNT(x) ((x) << S_DIP2_ERR_CNT) +#define G_DIP2_ERR_CNT(x) (((x) >> S_DIP2_ERR_CNT) & M_DIP2_ERR_CNT) + +#define A_ESPI_CMD_ADDR 0x8f8 + +#define S_WRITE_DATA 0 +#define M_WRITE_DATA 0xff +#define V_WRITE_DATA(x) ((x) << S_WRITE_DATA) +#define G_WRITE_DATA(x) (((x) >> S_WRITE_DATA) & M_WRITE_DATA) + +#define S_REGISTER_OFFSET 8 +#define M_REGISTER_OFFSET 0xf +#define V_REGISTER_OFFSET(x) ((x) << S_REGISTER_OFFSET) +#define G_REGISTER_OFFSET(x) (((x) >> S_REGISTER_OFFSET) & M_REGISTER_OFFSET) + +#define S_CHANNEL_ADDR 12 +#define M_CHANNEL_ADDR 0xf +#define V_CHANNEL_ADDR(x) ((x) << S_CHANNEL_ADDR) +#define G_CHANNEL_ADDR(x) (((x) >> S_CHANNEL_ADDR) & M_CHANNEL_ADDR) + +#define S_MODULE_ADDR 16 +#define M_MODULE_ADDR 0x3 +#define V_MODULE_ADDR(x) ((x) << S_MODULE_ADDR) +#define G_MODULE_ADDR(x) (((x) >> S_MODULE_ADDR) & M_MODULE_ADDR) + +#define S_BUNDLE_ADDR 20 +#define M_BUNDLE_ADDR 0x3 +#define V_BUNDLE_ADDR(x) ((x) << S_BUNDLE_ADDR) +#define G_BUNDLE_ADDR(x) (((x) >> S_BUNDLE_ADDR) & M_BUNDLE_ADDR) + +#define S_SPI4_COMMAND 24 +#define M_SPI4_COMMAND 0xff +#define V_SPI4_COMMAND(x) ((x) << S_SPI4_COMMAND) +#define G_SPI4_COMMAND(x) (((x) >> S_SPI4_COMMAND) & M_SPI4_COMMAND) + +#define A_ESPI_GOSTAT 0x8fc + +#define S_READ_DATA 0 +#define M_READ_DATA 0xff +#define V_READ_DATA(x) ((x) << S_READ_DATA) +#define G_READ_DATA(x) (((x) >> S_READ_DATA) & M_READ_DATA) + +#define S_ESPI_CMD_BUSY 8 +#define V_ESPI_CMD_BUSY(x) ((x) << S_ESPI_CMD_BUSY) +#define F_ESPI_CMD_BUSY V_ESPI_CMD_BUSY(1U) + +#define S_ERROR_ACK 9 +#define V_ERROR_ACK(x) ((x) << S_ERROR_ACK) +#define F_ERROR_ACK V_ERROR_ACK(1U) + +#define S_UNMAPPED_ERR 10 +#define V_UNMAPPED_ERR(x) ((x) << S_UNMAPPED_ERR) +#define F_UNMAPPED_ERR V_UNMAPPED_ERR(1U) + +#define S_TRANSACTION_TIMER 16 +#define M_TRANSACTION_TIMER 0xff +#define V_TRANSACTION_TIMER(x) ((x) << S_TRANSACTION_TIMER) +#define G_TRANSACTION_TIMER(x) (((x) >> S_TRANSACTION_TIMER) & M_TRANSACTION_TIMER) + + +/* ULP registers */ +#define A_ULP_ULIMIT 0x980 +#define A_ULP_TAGMASK 0x984 +#define A_ULP_HREG_INDEX 0x988 +#define A_ULP_HREG_DATA 0x98c +#define A_ULP_INT_ENABLE 0x990 +#define A_ULP_INT_CAUSE 0x994 + +#define S_HREG_PAR_ERR 0 +#define V_HREG_PAR_ERR(x) ((x) << S_HREG_PAR_ERR) +#define F_HREG_PAR_ERR V_HREG_PAR_ERR(1U) + +#define S_EGRS_DATA_PAR_ERR 1 +#define V_EGRS_DATA_PAR_ERR(x) ((x) << S_EGRS_DATA_PAR_ERR) +#define F_EGRS_DATA_PAR_ERR V_EGRS_DATA_PAR_ERR(1U) + +#define S_INGRS_DATA_PAR_ERR 2 +#define V_INGRS_DATA_PAR_ERR(x) ((x) << S_INGRS_DATA_PAR_ERR) +#define F_INGRS_DATA_PAR_ERR V_INGRS_DATA_PAR_ERR(1U) + +#define S_PM_INTR 3 +#define V_PM_INTR(x) ((x) << S_PM_INTR) +#define F_PM_INTR V_PM_INTR(1U) + +#define S_PM_E2C_SYNC_ERR 4 +#define V_PM_E2C_SYNC_ERR(x) ((x) << S_PM_E2C_SYNC_ERR) +#define F_PM_E2C_SYNC_ERR V_PM_E2C_SYNC_ERR(1U) + +#define S_PM_C2E_SYNC_ERR 5 +#define V_PM_C2E_SYNC_ERR(x) ((x) << S_PM_C2E_SYNC_ERR) +#define F_PM_C2E_SYNC_ERR V_PM_C2E_SYNC_ERR(1U) + +#define S_PM_E2C_EMPTY_ERR 6 +#define V_PM_E2C_EMPTY_ERR(x) ((x) << S_PM_E2C_EMPTY_ERR) +#define F_PM_E2C_EMPTY_ERR V_PM_E2C_EMPTY_ERR(1U) + +#define S_PM_C2E_EMPTY_ERR 7 +#define V_PM_C2E_EMPTY_ERR(x) ((x) << S_PM_C2E_EMPTY_ERR) +#define F_PM_C2E_EMPTY_ERR V_PM_C2E_EMPTY_ERR(1U) + +#define S_PM_PAR_ERR 8 +#define M_PM_PAR_ERR 0xffff +#define V_PM_PAR_ERR(x) ((x) << S_PM_PAR_ERR) +#define G_PM_PAR_ERR(x) (((x) >> S_PM_PAR_ERR) & M_PM_PAR_ERR) + +#define S_PM_E2C_WRT_FULL 24 +#define V_PM_E2C_WRT_FULL(x) ((x) << S_PM_E2C_WRT_FULL) +#define F_PM_E2C_WRT_FULL V_PM_E2C_WRT_FULL(1U) + +#define S_PM_C2E_WRT_FULL 25 +#define V_PM_C2E_WRT_FULL(x) ((x) << S_PM_C2E_WRT_FULL) +#define F_PM_C2E_WRT_FULL V_PM_C2E_WRT_FULL(1U) + +#define A_ULP_PIO_CTRL 0x998 + +/* PL registers */ +#define A_PL_ENABLE 0xa00 + +#define S_PL_INTR_SGE_ERR 0 +#define V_PL_INTR_SGE_ERR(x) ((x) << S_PL_INTR_SGE_ERR) +#define F_PL_INTR_SGE_ERR V_PL_INTR_SGE_ERR(1U) + +#define S_PL_INTR_SGE_DATA 1 +#define V_PL_INTR_SGE_DATA(x) ((x) << S_PL_INTR_SGE_DATA) +#define F_PL_INTR_SGE_DATA V_PL_INTR_SGE_DATA(1U) + +#define S_PL_INTR_MC3 2 +#define V_PL_INTR_MC3(x) ((x) << S_PL_INTR_MC3) +#define F_PL_INTR_MC3 V_PL_INTR_MC3(1U) + +#define S_PL_INTR_MC4 3 +#define V_PL_INTR_MC4(x) ((x) << S_PL_INTR_MC4) +#define F_PL_INTR_MC4 V_PL_INTR_MC4(1U) + +#define S_PL_INTR_MC5 4 +#define V_PL_INTR_MC5(x) ((x) << S_PL_INTR_MC5) +#define F_PL_INTR_MC5 V_PL_INTR_MC5(1U) + +#define S_PL_INTR_RAT 5 +#define V_PL_INTR_RAT(x) ((x) << S_PL_INTR_RAT) +#define F_PL_INTR_RAT V_PL_INTR_RAT(1U) + +#define S_PL_INTR_TP 6 +#define V_PL_INTR_TP(x) ((x) << S_PL_INTR_TP) +#define F_PL_INTR_TP V_PL_INTR_TP(1U) + +#define S_PL_INTR_ULP 7 +#define V_PL_INTR_ULP(x) ((x) << S_PL_INTR_ULP) +#define F_PL_INTR_ULP V_PL_INTR_ULP(1U) + +#define S_PL_INTR_ESPI 8 +#define V_PL_INTR_ESPI(x) ((x) << S_PL_INTR_ESPI) +#define F_PL_INTR_ESPI V_PL_INTR_ESPI(1U) + +#define S_PL_INTR_CSPI 9 +#define V_PL_INTR_CSPI(x) ((x) << S_PL_INTR_CSPI) +#define F_PL_INTR_CSPI V_PL_INTR_CSPI(1U) + +#define S_PL_INTR_PCIX 10 +#define V_PL_INTR_PCIX(x) ((x) << S_PL_INTR_PCIX) +#define F_PL_INTR_PCIX V_PL_INTR_PCIX(1U) + +#define S_PL_INTR_EXT 11 +#define V_PL_INTR_EXT(x) ((x) << S_PL_INTR_EXT) +#define F_PL_INTR_EXT V_PL_INTR_EXT(1U) + +#define A_PL_CAUSE 0xa04 + +/* MC5 registers */ +#define A_MC5_CONFIG 0xc04 + +#define S_MODE 0 +#define V_MODE(x) ((x) << S_MODE) +#define F_MODE V_MODE(1U) + +#define S_TCAM_RESET 1 +#define V_TCAM_RESET(x) ((x) << S_TCAM_RESET) +#define F_TCAM_RESET V_TCAM_RESET(1U) + +#define S_TCAM_READY 2 +#define V_TCAM_READY(x) ((x) << S_TCAM_READY) +#define F_TCAM_READY V_TCAM_READY(1U) + +#define S_DBGI_ENABLE 4 +#define V_DBGI_ENABLE(x) ((x) << S_DBGI_ENABLE) +#define F_DBGI_ENABLE V_DBGI_ENABLE(1U) + +#define S_M_BUS_ENABLE 5 +#define V_M_BUS_ENABLE(x) ((x) << S_M_BUS_ENABLE) +#define F_M_BUS_ENABLE V_M_BUS_ENABLE(1U) + +#define S_PARITY_ENABLE 6 +#define V_PARITY_ENABLE(x) ((x) << S_PARITY_ENABLE) +#define F_PARITY_ENABLE V_PARITY_ENABLE(1U) + +#define S_SYN_ISSUE_MODE 7 +#define M_SYN_ISSUE_MODE 0x3 +#define V_SYN_ISSUE_MODE(x) ((x) << S_SYN_ISSUE_MODE) +#define G_SYN_ISSUE_MODE(x) (((x) >> S_SYN_ISSUE_MODE) & M_SYN_ISSUE_MODE) + +#define S_BUILD 16 +#define V_BUILD(x) ((x) << S_BUILD) +#define F_BUILD V_BUILD(1U) + +#define S_COMPRESSION_ENABLE 17 +#define V_COMPRESSION_ENABLE(x) ((x) << S_COMPRESSION_ENABLE) +#define F_COMPRESSION_ENABLE V_COMPRESSION_ENABLE(1U) + +#define S_NUM_LIP 18 +#define M_NUM_LIP 0x3f +#define V_NUM_LIP(x) ((x) << S_NUM_LIP) +#define G_NUM_LIP(x) (((x) >> S_NUM_LIP) & M_NUM_LIP) + +#define S_TCAM_PART_CNT 24 +#define M_TCAM_PART_CNT 0x3 +#define V_TCAM_PART_CNT(x) ((x) << S_TCAM_PART_CNT) +#define G_TCAM_PART_CNT(x) (((x) >> S_TCAM_PART_CNT) & M_TCAM_PART_CNT) + +#define S_TCAM_PART_TYPE 26 +#define M_TCAM_PART_TYPE 0x3 +#define V_TCAM_PART_TYPE(x) ((x) << S_TCAM_PART_TYPE) +#define G_TCAM_PART_TYPE(x) (((x) >> S_TCAM_PART_TYPE) & M_TCAM_PART_TYPE) + +#define S_TCAM_PART_SIZE 28 +#define M_TCAM_PART_SIZE 0x3 +#define V_TCAM_PART_SIZE(x) ((x) << S_TCAM_PART_SIZE) +#define G_TCAM_PART_SIZE(x) (((x) >> S_TCAM_PART_SIZE) & M_TCAM_PART_SIZE) + +#define S_TCAM_PART_TYPE_HI 30 +#define V_TCAM_PART_TYPE_HI(x) ((x) << S_TCAM_PART_TYPE_HI) +#define F_TCAM_PART_TYPE_HI V_TCAM_PART_TYPE_HI(1U) + +#define A_MC5_SIZE 0xc08 + +#define S_SIZE 0 +#define M_SIZE 0x3fffff +#define V_SIZE(x) ((x) << S_SIZE) +#define G_SIZE(x) (((x) >> S_SIZE) & M_SIZE) + +#define A_MC5_ROUTING_TABLE_INDEX 0xc0c + +#define S_START_OF_ROUTING_TABLE 0 +#define M_START_OF_ROUTING_TABLE 0x3fffff +#define V_START_OF_ROUTING_TABLE(x) ((x) << S_START_OF_ROUTING_TABLE) +#define G_START_OF_ROUTING_TABLE(x) (((x) >> S_START_OF_ROUTING_TABLE) & M_START_OF_ROUTING_TABLE) + +#define A_MC5_SERVER_INDEX 0xc14 + +#define S_START_OF_SERVER_INDEX 0 +#define M_START_OF_SERVER_INDEX 0x3fffff +#define V_START_OF_SERVER_INDEX(x) ((x) << S_START_OF_SERVER_INDEX) +#define G_START_OF_SERVER_INDEX(x) (((x) >> S_START_OF_SERVER_INDEX) & M_START_OF_SERVER_INDEX) + +#define A_MC5_LIP_RAM_ADDR 0xc18 + +#define S_LOCAL_IP_RAM_ADDR 0 +#define M_LOCAL_IP_RAM_ADDR 0x3f +#define V_LOCAL_IP_RAM_ADDR(x) ((x) << S_LOCAL_IP_RAM_ADDR) +#define G_LOCAL_IP_RAM_ADDR(x) (((x) >> S_LOCAL_IP_RAM_ADDR) & M_LOCAL_IP_RAM_ADDR) + +#define S_RAM_WRITE_ENABLE 8 +#define V_RAM_WRITE_ENABLE(x) ((x) << S_RAM_WRITE_ENABLE) +#define F_RAM_WRITE_ENABLE V_RAM_WRITE_ENABLE(1U) + +#define A_MC5_LIP_RAM_DATA 0xc1c +#define A_MC5_RSP_LATENCY 0xc20 + +#define S_SEARCH_RESPONSE_LATENCY 0 +#define M_SEARCH_RESPONSE_LATENCY 0x1f +#define V_SEARCH_RESPONSE_LATENCY(x) ((x) << S_SEARCH_RESPONSE_LATENCY) +#define G_SEARCH_RESPONSE_LATENCY(x) (((x) >> S_SEARCH_RESPONSE_LATENCY) & M_SEARCH_RESPONSE_LATENCY) + +#define S_LEARN_RESPONSE_LATENCY 8 +#define M_LEARN_RESPONSE_LATENCY 0x1f +#define V_LEARN_RESPONSE_LATENCY(x) ((x) << S_LEARN_RESPONSE_LATENCY) +#define G_LEARN_RESPONSE_LATENCY(x) (((x) >> S_LEARN_RESPONSE_LATENCY) & M_LEARN_RESPONSE_LATENCY) + +#define A_MC5_PARITY_LATENCY 0xc24 + +#define S_SRCHLAT 0 +#define M_SRCHLAT 0x1f +#define V_SRCHLAT(x) ((x) << S_SRCHLAT) +#define G_SRCHLAT(x) (((x) >> S_SRCHLAT) & M_SRCHLAT) + +#define S_PARLAT 8 +#define M_PARLAT 0x1f +#define V_PARLAT(x) ((x) << S_PARLAT) +#define G_PARLAT(x) (((x) >> S_PARLAT) & M_PARLAT) + +#define A_MC5_WR_LRN_VERIFY 0xc28 + +#define S_POVEREN 0 +#define V_POVEREN(x) ((x) << S_POVEREN) +#define F_POVEREN V_POVEREN(1U) + +#define S_LRNVEREN 1 +#define V_LRNVEREN(x) ((x) << S_LRNVEREN) +#define F_LRNVEREN V_LRNVEREN(1U) + +#define S_VWVEREN 2 +#define V_VWVEREN(x) ((x) << S_VWVEREN) +#define F_VWVEREN V_VWVEREN(1U) + +#define A_MC5_PART_ID_INDEX 0xc2c + +#define S_IDINDEX 0 +#define M_IDINDEX 0xf +#define V_IDINDEX(x) ((x) << S_IDINDEX) +#define G_IDINDEX(x) (((x) >> S_IDINDEX) & M_IDINDEX) + +#define A_MC5_RESET_MAX 0xc30 + +#define S_RSTMAX 0 +#define M_RSTMAX 0x1ff +#define V_RSTMAX(x) ((x) << S_RSTMAX) +#define G_RSTMAX(x) (((x) >> S_RSTMAX) & M_RSTMAX) + +#define A_MC5_INT_ENABLE 0xc40 + +#define S_MC5_INT_HIT_OUT_ACTIVE_REGION_ERR 0 +#define V_MC5_INT_HIT_OUT_ACTIVE_REGION_ERR(x) ((x) << S_MC5_INT_HIT_OUT_ACTIVE_REGION_ERR) +#define F_MC5_INT_HIT_OUT_ACTIVE_REGION_ERR V_MC5_INT_HIT_OUT_ACTIVE_REGION_ERR(1U) + +#define S_MC5_INT_HIT_IN_ACTIVE_REGION_ERR 1 +#define V_MC5_INT_HIT_IN_ACTIVE_REGION_ERR(x) ((x) << S_MC5_INT_HIT_IN_ACTIVE_REGION_ERR) +#define F_MC5_INT_HIT_IN_ACTIVE_REGION_ERR V_MC5_INT_HIT_IN_ACTIVE_REGION_ERR(1U) + +#define S_MC5_INT_HIT_IN_RT_REGION_ERR 2 +#define V_MC5_INT_HIT_IN_RT_REGION_ERR(x) ((x) << S_MC5_INT_HIT_IN_RT_REGION_ERR) +#define F_MC5_INT_HIT_IN_RT_REGION_ERR V_MC5_INT_HIT_IN_RT_REGION_ERR(1U) + +#define S_MC5_INT_MISS_ERR 3 +#define V_MC5_INT_MISS_ERR(x) ((x) << S_MC5_INT_MISS_ERR) +#define F_MC5_INT_MISS_ERR V_MC5_INT_MISS_ERR(1U) + +#define S_MC5_INT_LIP0_ERR 4 +#define V_MC5_INT_LIP0_ERR(x) ((x) << S_MC5_INT_LIP0_ERR) +#define F_MC5_INT_LIP0_ERR V_MC5_INT_LIP0_ERR(1U) + +#define S_MC5_INT_LIP_MISS_ERR 5 +#define V_MC5_INT_LIP_MISS_ERR(x) ((x) << S_MC5_INT_LIP_MISS_ERR) +#define F_MC5_INT_LIP_MISS_ERR V_MC5_INT_LIP_MISS_ERR(1U) + +#define S_MC5_INT_PARITY_ERR 6 +#define V_MC5_INT_PARITY_ERR(x) ((x) << S_MC5_INT_PARITY_ERR) +#define F_MC5_INT_PARITY_ERR V_MC5_INT_PARITY_ERR(1U) + +#define S_MC5_INT_ACTIVE_REGION_FULL 7 +#define V_MC5_INT_ACTIVE_REGION_FULL(x) ((x) << S_MC5_INT_ACTIVE_REGION_FULL) +#define F_MC5_INT_ACTIVE_REGION_FULL V_MC5_INT_ACTIVE_REGION_FULL(1U) + +#define S_MC5_INT_NFA_SRCH_ERR 8 +#define V_MC5_INT_NFA_SRCH_ERR(x) ((x) << S_MC5_INT_NFA_SRCH_ERR) +#define F_MC5_INT_NFA_SRCH_ERR V_MC5_INT_NFA_SRCH_ERR(1U) + +#define S_MC5_INT_SYN_COOKIE 9 +#define V_MC5_INT_SYN_COOKIE(x) ((x) << S_MC5_INT_SYN_COOKIE) +#define F_MC5_INT_SYN_COOKIE V_MC5_INT_SYN_COOKIE(1U) + +#define S_MC5_INT_SYN_COOKIE_BAD 10 +#define V_MC5_INT_SYN_COOKIE_BAD(x) ((x) << S_MC5_INT_SYN_COOKIE_BAD) +#define F_MC5_INT_SYN_COOKIE_BAD V_MC5_INT_SYN_COOKIE_BAD(1U) + +#define S_MC5_INT_SYN_COOKIE_OFF 11 +#define V_MC5_INT_SYN_COOKIE_OFF(x) ((x) << S_MC5_INT_SYN_COOKIE_OFF) +#define F_MC5_INT_SYN_COOKIE_OFF V_MC5_INT_SYN_COOKIE_OFF(1U) + +#define S_MC5_INT_UNKNOWN_CMD 15 +#define V_MC5_INT_UNKNOWN_CMD(x) ((x) << S_MC5_INT_UNKNOWN_CMD) +#define F_MC5_INT_UNKNOWN_CMD V_MC5_INT_UNKNOWN_CMD(1U) + +#define S_MC5_INT_REQUESTQ_PARITY_ERR 16 +#define V_MC5_INT_REQUESTQ_PARITY_ERR(x) ((x) << S_MC5_INT_REQUESTQ_PARITY_ERR) +#define F_MC5_INT_REQUESTQ_PARITY_ERR V_MC5_INT_REQUESTQ_PARITY_ERR(1U) + +#define S_MC5_INT_DISPATCHQ_PARITY_ERR 17 +#define V_MC5_INT_DISPATCHQ_PARITY_ERR(x) ((x) << S_MC5_INT_DISPATCHQ_PARITY_ERR) +#define F_MC5_INT_DISPATCHQ_PARITY_ERR V_MC5_INT_DISPATCHQ_PARITY_ERR(1U) + +#define S_MC5_INT_DEL_ACT_EMPTY 18 +#define V_MC5_INT_DEL_ACT_EMPTY(x) ((x) << S_MC5_INT_DEL_ACT_EMPTY) +#define F_MC5_INT_DEL_ACT_EMPTY V_MC5_INT_DEL_ACT_EMPTY(1U) + +#define A_MC5_INT_CAUSE 0xc44 +#define A_MC5_INT_TID 0xc48 +#define A_MC5_INT_PTID 0xc4c +#define A_MC5_DBGI_CONFIG 0xc74 +#define A_MC5_DBGI_REQ_CMD 0xc78 + +#define S_CMDMODE 0 +#define M_CMDMODE 0x7 +#define V_CMDMODE(x) ((x) << S_CMDMODE) +#define G_CMDMODE(x) (((x) >> S_CMDMODE) & M_CMDMODE) + +#define S_SADRSEL 4 +#define V_SADRSEL(x) ((x) << S_SADRSEL) +#define F_SADRSEL V_SADRSEL(1U) + +#define S_WRITE_BURST_SIZE 22 +#define M_WRITE_BURST_SIZE 0x3ff +#define V_WRITE_BURST_SIZE(x) ((x) << S_WRITE_BURST_SIZE) +#define G_WRITE_BURST_SIZE(x) (((x) >> S_WRITE_BURST_SIZE) & M_WRITE_BURST_SIZE) + +#define A_MC5_DBGI_REQ_ADDR0 0xc7c +#define A_MC5_DBGI_REQ_ADDR1 0xc80 +#define A_MC5_DBGI_REQ_ADDR2 0xc84 +#define A_MC5_DBGI_REQ_DATA0 0xc88 +#define A_MC5_DBGI_REQ_DATA1 0xc8c +#define A_MC5_DBGI_REQ_DATA2 0xc90 +#define A_MC5_DBGI_REQ_DATA3 0xc94 +#define A_MC5_DBGI_REQ_DATA4 0xc98 +#define A_MC5_DBGI_REQ_MASK0 0xc9c +#define A_MC5_DBGI_REQ_MASK1 0xca0 +#define A_MC5_DBGI_REQ_MASK2 0xca4 +#define A_MC5_DBGI_REQ_MASK3 0xca8 +#define A_MC5_DBGI_REQ_MASK4 0xcac +#define A_MC5_DBGI_RSP_STATUS 0xcb0 + +#define S_DBGI_RSP_VALID 0 +#define V_DBGI_RSP_VALID(x) ((x) << S_DBGI_RSP_VALID) +#define F_DBGI_RSP_VALID V_DBGI_RSP_VALID(1U) + +#define S_DBGI_RSP_HIT 1 +#define V_DBGI_RSP_HIT(x) ((x) << S_DBGI_RSP_HIT) +#define F_DBGI_RSP_HIT V_DBGI_RSP_HIT(1U) + +#define S_DBGI_RSP_ERR 2 +#define V_DBGI_RSP_ERR(x) ((x) << S_DBGI_RSP_ERR) +#define F_DBGI_RSP_ERR V_DBGI_RSP_ERR(1U) + +#define S_DBGI_RSP_ERR_REASON 8 +#define M_DBGI_RSP_ERR_REASON 0x7 +#define V_DBGI_RSP_ERR_REASON(x) ((x) << S_DBGI_RSP_ERR_REASON) +#define G_DBGI_RSP_ERR_REASON(x) (((x) >> S_DBGI_RSP_ERR_REASON) & M_DBGI_RSP_ERR_REASON) + +#define A_MC5_DBGI_RSP_DATA0 0xcb4 +#define A_MC5_DBGI_RSP_DATA1 0xcb8 +#define A_MC5_DBGI_RSP_DATA2 0xcbc +#define A_MC5_DBGI_RSP_DATA3 0xcc0 +#define A_MC5_DBGI_RSP_DATA4 0xcc4 +#define A_MC5_DBGI_RSP_LAST_CMD 0xcc8 +#define A_MC5_POPEN_DATA_WR_CMD 0xccc +#define A_MC5_POPEN_MASK_WR_CMD 0xcd0 +#define A_MC5_AOPEN_SRCH_CMD 0xcd4 +#define A_MC5_AOPEN_LRN_CMD 0xcd8 +#define A_MC5_SYN_SRCH_CMD 0xcdc +#define A_MC5_SYN_LRN_CMD 0xce0 +#define A_MC5_ACK_SRCH_CMD 0xce4 +#define A_MC5_ACK_LRN_CMD 0xce8 +#define A_MC5_ILOOKUP_CMD 0xcec +#define A_MC5_ELOOKUP_CMD 0xcf0 +#define A_MC5_DATA_WRITE_CMD 0xcf4 +#define A_MC5_DATA_READ_CMD 0xcf8 +#define A_MC5_MASK_WRITE_CMD 0xcfc + +/* PCICFG registers */ +#define A_PCICFG_PM_CSR 0x44 +#define A_PCICFG_VPD_ADDR 0x4a + +#define S_VPD_ADDR 0 +#define M_VPD_ADDR 0x7fff +#define V_VPD_ADDR(x) ((x) << S_VPD_ADDR) +#define G_VPD_ADDR(x) (((x) >> S_VPD_ADDR) & M_VPD_ADDR) + +#define S_VPD_OP_FLAG 15 +#define V_VPD_OP_FLAG(x) ((x) << S_VPD_OP_FLAG) +#define F_VPD_OP_FLAG V_VPD_OP_FLAG(1U) + +#define A_PCICFG_VPD_DATA 0x4c +#define A_PCICFG_PCIX_CMD 0x60 +#define A_PCICFG_INTR_ENABLE 0xf4 + +#define S_MASTER_PARITY_ERR 0 +#define V_MASTER_PARITY_ERR(x) ((x) << S_MASTER_PARITY_ERR) +#define F_MASTER_PARITY_ERR V_MASTER_PARITY_ERR(1U) + +#define S_SIG_TARGET_ABORT 1 +#define V_SIG_TARGET_ABORT(x) ((x) << S_SIG_TARGET_ABORT) +#define F_SIG_TARGET_ABORT V_SIG_TARGET_ABORT(1U) + +#define S_RCV_TARGET_ABORT 2 +#define V_RCV_TARGET_ABORT(x) ((x) << S_RCV_TARGET_ABORT) +#define F_RCV_TARGET_ABORT V_RCV_TARGET_ABORT(1U) + +#define S_RCV_MASTER_ABORT 3 +#define V_RCV_MASTER_ABORT(x) ((x) << S_RCV_MASTER_ABORT) +#define F_RCV_MASTER_ABORT V_RCV_MASTER_ABORT(1U) + +#define S_SIG_SYS_ERR 4 +#define V_SIG_SYS_ERR(x) ((x) << S_SIG_SYS_ERR) +#define F_SIG_SYS_ERR V_SIG_SYS_ERR(1U) + +#define S_DET_PARITY_ERR 5 +#define V_DET_PARITY_ERR(x) ((x) << S_DET_PARITY_ERR) +#define F_DET_PARITY_ERR V_DET_PARITY_ERR(1U) + +#define S_PIO_PARITY_ERR 6 +#define V_PIO_PARITY_ERR(x) ((x) << S_PIO_PARITY_ERR) +#define F_PIO_PARITY_ERR V_PIO_PARITY_ERR(1U) + +#define S_WF_PARITY_ERR 7 +#define V_WF_PARITY_ERR(x) ((x) << S_WF_PARITY_ERR) +#define F_WF_PARITY_ERR V_WF_PARITY_ERR(1U) + +#define S_RF_PARITY_ERR 8 +#define M_RF_PARITY_ERR 0x3 +#define V_RF_PARITY_ERR(x) ((x) << S_RF_PARITY_ERR) +#define G_RF_PARITY_ERR(x) (((x) >> S_RF_PARITY_ERR) & M_RF_PARITY_ERR) + +#define S_CF_PARITY_ERR 10 +#define M_CF_PARITY_ERR 0x3 +#define V_CF_PARITY_ERR(x) ((x) << S_CF_PARITY_ERR) +#define G_CF_PARITY_ERR(x) (((x) >> S_CF_PARITY_ERR) & M_CF_PARITY_ERR) + +#define A_PCICFG_INTR_CAUSE 0xf8 +#define A_PCICFG_MODE 0xfc + +#define S_PCI_MODE_64BIT 0 +#define V_PCI_MODE_64BIT(x) ((x) << S_PCI_MODE_64BIT) +#define F_PCI_MODE_64BIT V_PCI_MODE_64BIT(1U) + +#define S_PCI_MODE_66MHZ 1 +#define V_PCI_MODE_66MHZ(x) ((x) << S_PCI_MODE_66MHZ) +#define F_PCI_MODE_66MHZ V_PCI_MODE_66MHZ(1U) + +#define S_PCI_MODE_PCIX_INITPAT 2 +#define M_PCI_MODE_PCIX_INITPAT 0x7 +#define V_PCI_MODE_PCIX_INITPAT(x) ((x) << S_PCI_MODE_PCIX_INITPAT) +#define G_PCI_MODE_PCIX_INITPAT(x) (((x) >> S_PCI_MODE_PCIX_INITPAT) & M_PCI_MODE_PCIX_INITPAT) + +#define S_PCI_MODE_PCIX 5 +#define V_PCI_MODE_PCIX(x) ((x) << S_PCI_MODE_PCIX) +#define F_PCI_MODE_PCIX V_PCI_MODE_PCIX(1U) + +#define S_PCI_MODE_CLK 6 +#define M_PCI_MODE_CLK 0x3 +#define V_PCI_MODE_CLK(x) ((x) << S_PCI_MODE_CLK) +#define G_PCI_MODE_CLK(x) (((x) >> S_PCI_MODE_CLK) & M_PCI_MODE_CLK) + +#endif /* _CXGB_REGS_H_ */ diff --git a/drivers/net/ethernet/chelsio/cxgb/sge.c b/drivers/net/ethernet/chelsio/cxgb/sge.c new file mode 100644 index 000000000000..e9a03fffef15 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb/sge.c @@ -0,0 +1,2140 @@ +/***************************************************************************** + * * + * File: sge.c * + * $Revision: 1.26 $ * + * $Date: 2005/06/21 18:29:48 $ * + * Description: * + * DMA engine. * + * part of the Chelsio 10Gb Ethernet Driver. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License, version 2, as * + * published by the Free Software Foundation. * + * * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * + * * + * http://www.chelsio.com * + * * + * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * + * All rights reserved. * + * * + * Maintainers: maintainers@chelsio.com * + * * + * Authors: Dimitrios Michailidis * + * Tina Yang * + * Felix Marti * + * Scott Bardone * + * Kurt Ottaway * + * Frank DiMambro * + * * + * History: * + * * + ****************************************************************************/ + +#include "common.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpl5_cmd.h" +#include "sge.h" +#include "regs.h" +#include "espi.h" + +/* This belongs in if_ether.h */ +#define ETH_P_CPL5 0xf + +#define SGE_CMDQ_N 2 +#define SGE_FREELQ_N 2 +#define SGE_CMDQ0_E_N 1024 +#define SGE_CMDQ1_E_N 128 +#define SGE_FREEL_SIZE 4096 +#define SGE_JUMBO_FREEL_SIZE 512 +#define SGE_FREEL_REFILL_THRESH 16 +#define SGE_RESPQ_E_N 1024 +#define SGE_INTRTIMER_NRES 1000 +#define SGE_RX_SM_BUF_SIZE 1536 +#define SGE_TX_DESC_MAX_PLEN 16384 + +#define SGE_RESPQ_REPLENISH_THRES (SGE_RESPQ_E_N / 4) + +/* + * Period of the TX buffer reclaim timer. This timer does not need to run + * frequently as TX buffers are usually reclaimed by new TX packets. + */ +#define TX_RECLAIM_PERIOD (HZ / 4) + +#define M_CMD_LEN 0x7fffffff +#define V_CMD_LEN(v) (v) +#define G_CMD_LEN(v) ((v) & M_CMD_LEN) +#define V_CMD_GEN1(v) ((v) << 31) +#define V_CMD_GEN2(v) (v) +#define F_CMD_DATAVALID (1 << 1) +#define F_CMD_SOP (1 << 2) +#define V_CMD_EOP(v) ((v) << 3) + +/* + * Command queue, receive buffer list, and response queue descriptors. + */ +#if defined(__BIG_ENDIAN_BITFIELD) +struct cmdQ_e { + u32 addr_lo; + u32 len_gen; + u32 flags; + u32 addr_hi; +}; + +struct freelQ_e { + u32 addr_lo; + u32 len_gen; + u32 gen2; + u32 addr_hi; +}; + +struct respQ_e { + u32 Qsleeping : 4; + u32 Cmdq1CreditReturn : 5; + u32 Cmdq1DmaComplete : 5; + u32 Cmdq0CreditReturn : 5; + u32 Cmdq0DmaComplete : 5; + u32 FreelistQid : 2; + u32 CreditValid : 1; + u32 DataValid : 1; + u32 Offload : 1; + u32 Eop : 1; + u32 Sop : 1; + u32 GenerationBit : 1; + u32 BufferLength; +}; +#elif defined(__LITTLE_ENDIAN_BITFIELD) +struct cmdQ_e { + u32 len_gen; + u32 addr_lo; + u32 addr_hi; + u32 flags; +}; + +struct freelQ_e { + u32 len_gen; + u32 addr_lo; + u32 addr_hi; + u32 gen2; +}; + +struct respQ_e { + u32 BufferLength; + u32 GenerationBit : 1; + u32 Sop : 1; + u32 Eop : 1; + u32 Offload : 1; + u32 DataValid : 1; + u32 CreditValid : 1; + u32 FreelistQid : 2; + u32 Cmdq0DmaComplete : 5; + u32 Cmdq0CreditReturn : 5; + u32 Cmdq1DmaComplete : 5; + u32 Cmdq1CreditReturn : 5; + u32 Qsleeping : 4; +} ; +#endif + +/* + * SW Context Command and Freelist Queue Descriptors + */ +struct cmdQ_ce { + struct sk_buff *skb; + DEFINE_DMA_UNMAP_ADDR(dma_addr); + DEFINE_DMA_UNMAP_LEN(dma_len); +}; + +struct freelQ_ce { + struct sk_buff *skb; + DEFINE_DMA_UNMAP_ADDR(dma_addr); + DEFINE_DMA_UNMAP_LEN(dma_len); +}; + +/* + * SW command, freelist and response rings + */ +struct cmdQ { + unsigned long status; /* HW DMA fetch status */ + unsigned int in_use; /* # of in-use command descriptors */ + unsigned int size; /* # of descriptors */ + unsigned int processed; /* total # of descs HW has processed */ + unsigned int cleaned; /* total # of descs SW has reclaimed */ + unsigned int stop_thres; /* SW TX queue suspend threshold */ + u16 pidx; /* producer index (SW) */ + u16 cidx; /* consumer index (HW) */ + u8 genbit; /* current generation (=valid) bit */ + u8 sop; /* is next entry start of packet? */ + struct cmdQ_e *entries; /* HW command descriptor Q */ + struct cmdQ_ce *centries; /* SW command context descriptor Q */ + dma_addr_t dma_addr; /* DMA addr HW command descriptor Q */ + spinlock_t lock; /* Lock to protect cmdQ enqueuing */ +}; + +struct freelQ { + unsigned int credits; /* # of available RX buffers */ + unsigned int size; /* free list capacity */ + u16 pidx; /* producer index (SW) */ + u16 cidx; /* consumer index (HW) */ + u16 rx_buffer_size; /* Buffer size on this free list */ + u16 dma_offset; /* DMA offset to align IP headers */ + u16 recycleq_idx; /* skb recycle q to use */ + u8 genbit; /* current generation (=valid) bit */ + struct freelQ_e *entries; /* HW freelist descriptor Q */ + struct freelQ_ce *centries; /* SW freelist context descriptor Q */ + dma_addr_t dma_addr; /* DMA addr HW freelist descriptor Q */ +}; + +struct respQ { + unsigned int credits; /* credits to be returned to SGE */ + unsigned int size; /* # of response Q descriptors */ + u16 cidx; /* consumer index (SW) */ + u8 genbit; /* current generation(=valid) bit */ + struct respQ_e *entries; /* HW response descriptor Q */ + dma_addr_t dma_addr; /* DMA addr HW response descriptor Q */ +}; + +/* Bit flags for cmdQ.status */ +enum { + CMDQ_STAT_RUNNING = 1, /* fetch engine is running */ + CMDQ_STAT_LAST_PKT_DB = 2 /* last packet rung the doorbell */ +}; + +/* T204 TX SW scheduler */ + +/* Per T204 TX port */ +struct sched_port { + unsigned int avail; /* available bits - quota */ + unsigned int drain_bits_per_1024ns; /* drain rate */ + unsigned int speed; /* drain rate, mbps */ + unsigned int mtu; /* mtu size */ + struct sk_buff_head skbq; /* pending skbs */ +}; + +/* Per T204 device */ +struct sched { + ktime_t last_updated; /* last time quotas were computed */ + unsigned int max_avail; /* max bits to be sent to any port */ + unsigned int port; /* port index (round robin ports) */ + unsigned int num; /* num skbs in per port queues */ + struct sched_port p[MAX_NPORTS]; + struct tasklet_struct sched_tsk;/* tasklet used to run scheduler */ +}; +static void restart_sched(unsigned long); + + +/* + * Main SGE data structure + * + * Interrupts are handled by a single CPU and it is likely that on a MP system + * the application is migrated to another CPU. In that scenario, we try to + * separate the RX(in irq context) and TX state in order to decrease memory + * contention. + */ +struct sge { + struct adapter *adapter; /* adapter backpointer */ + struct net_device *netdev; /* netdevice backpointer */ + struct freelQ freelQ[SGE_FREELQ_N]; /* buffer free lists */ + struct respQ respQ; /* response Q */ + unsigned long stopped_tx_queues; /* bitmap of suspended Tx queues */ + unsigned int rx_pkt_pad; /* RX padding for L2 packets */ + unsigned int jumbo_fl; /* jumbo freelist Q index */ + unsigned int intrtimer_nres; /* no-resource interrupt timer */ + unsigned int fixed_intrtimer;/* non-adaptive interrupt timer */ + struct timer_list tx_reclaim_timer; /* reclaims TX buffers */ + struct timer_list espibug_timer; + unsigned long espibug_timeout; + struct sk_buff *espibug_skb[MAX_NPORTS]; + u32 sge_control; /* shadow value of sge control reg */ + struct sge_intr_counts stats; + struct sge_port_stats __percpu *port_stats[MAX_NPORTS]; + struct sched *tx_sched; + struct cmdQ cmdQ[SGE_CMDQ_N] ____cacheline_aligned_in_smp; +}; + +static const u8 ch_mac_addr[ETH_ALEN] = { + 0x0, 0x7, 0x43, 0x0, 0x0, 0x0 +}; + +/* + * stop tasklet and free all pending skb's + */ +static void tx_sched_stop(struct sge *sge) +{ + struct sched *s = sge->tx_sched; + int i; + + tasklet_kill(&s->sched_tsk); + + for (i = 0; i < MAX_NPORTS; i++) + __skb_queue_purge(&s->p[s->port].skbq); +} + +/* + * t1_sched_update_parms() is called when the MTU or link speed changes. It + * re-computes scheduler parameters to scope with the change. + */ +unsigned int t1_sched_update_parms(struct sge *sge, unsigned int port, + unsigned int mtu, unsigned int speed) +{ + struct sched *s = sge->tx_sched; + struct sched_port *p = &s->p[port]; + unsigned int max_avail_segs; + + pr_debug("t1_sched_update_params mtu=%d speed=%d\n", mtu, speed); + if (speed) + p->speed = speed; + if (mtu) + p->mtu = mtu; + + if (speed || mtu) { + unsigned long long drain = 1024ULL * p->speed * (p->mtu - 40); + do_div(drain, (p->mtu + 50) * 1000); + p->drain_bits_per_1024ns = (unsigned int) drain; + + if (p->speed < 1000) + p->drain_bits_per_1024ns = + 90 * p->drain_bits_per_1024ns / 100; + } + + if (board_info(sge->adapter)->board == CHBT_BOARD_CHT204) { + p->drain_bits_per_1024ns -= 16; + s->max_avail = max(4096U, p->mtu + 16 + 14 + 4); + max_avail_segs = max(1U, 4096 / (p->mtu - 40)); + } else { + s->max_avail = 16384; + max_avail_segs = max(1U, 9000 / (p->mtu - 40)); + } + + pr_debug("t1_sched_update_parms: mtu %u speed %u max_avail %u " + "max_avail_segs %u drain_bits_per_1024ns %u\n", p->mtu, + p->speed, s->max_avail, max_avail_segs, + p->drain_bits_per_1024ns); + + return max_avail_segs * (p->mtu - 40); +} + +#if 0 + +/* + * t1_sched_max_avail_bytes() tells the scheduler the maximum amount of + * data that can be pushed per port. + */ +void t1_sched_set_max_avail_bytes(struct sge *sge, unsigned int val) +{ + struct sched *s = sge->tx_sched; + unsigned int i; + + s->max_avail = val; + for (i = 0; i < MAX_NPORTS; i++) + t1_sched_update_parms(sge, i, 0, 0); +} + +/* + * t1_sched_set_drain_bits_per_us() tells the scheduler at which rate a port + * is draining. + */ +void t1_sched_set_drain_bits_per_us(struct sge *sge, unsigned int port, + unsigned int val) +{ + struct sched *s = sge->tx_sched; + struct sched_port *p = &s->p[port]; + p->drain_bits_per_1024ns = val * 1024 / 1000; + t1_sched_update_parms(sge, port, 0, 0); +} + +#endif /* 0 */ + + +/* + * get_clock() implements a ns clock (see ktime_get) + */ +static inline ktime_t get_clock(void) +{ + struct timespec ts; + + ktime_get_ts(&ts); + return timespec_to_ktime(ts); +} + +/* + * tx_sched_init() allocates resources and does basic initialization. + */ +static int tx_sched_init(struct sge *sge) +{ + struct sched *s; + int i; + + s = kzalloc(sizeof (struct sched), GFP_KERNEL); + if (!s) + return -ENOMEM; + + pr_debug("tx_sched_init\n"); + tasklet_init(&s->sched_tsk, restart_sched, (unsigned long) sge); + sge->tx_sched = s; + + for (i = 0; i < MAX_NPORTS; i++) { + skb_queue_head_init(&s->p[i].skbq); + t1_sched_update_parms(sge, i, 1500, 1000); + } + + return 0; +} + +/* + * sched_update_avail() computes the delta since the last time it was called + * and updates the per port quota (number of bits that can be sent to the any + * port). + */ +static inline int sched_update_avail(struct sge *sge) +{ + struct sched *s = sge->tx_sched; + ktime_t now = get_clock(); + unsigned int i; + long long delta_time_ns; + + delta_time_ns = ktime_to_ns(ktime_sub(now, s->last_updated)); + + pr_debug("sched_update_avail delta=%lld\n", delta_time_ns); + if (delta_time_ns < 15000) + return 0; + + for (i = 0; i < MAX_NPORTS; i++) { + struct sched_port *p = &s->p[i]; + unsigned int delta_avail; + + delta_avail = (p->drain_bits_per_1024ns * delta_time_ns) >> 13; + p->avail = min(p->avail + delta_avail, s->max_avail); + } + + s->last_updated = now; + + return 1; +} + +/* + * sched_skb() is called from two different places. In the tx path, any + * packet generating load on an output port will call sched_skb() + * (skb != NULL). In addition, sched_skb() is called from the irq/soft irq + * context (skb == NULL). + * The scheduler only returns a skb (which will then be sent) if the + * length of the skb is <= the current quota of the output port. + */ +static struct sk_buff *sched_skb(struct sge *sge, struct sk_buff *skb, + unsigned int credits) +{ + struct sched *s = sge->tx_sched; + struct sk_buff_head *skbq; + unsigned int i, len, update = 1; + + pr_debug("sched_skb %p\n", skb); + if (!skb) { + if (!s->num) + return NULL; + } else { + skbq = &s->p[skb->dev->if_port].skbq; + __skb_queue_tail(skbq, skb); + s->num++; + skb = NULL; + } + + if (credits < MAX_SKB_FRAGS + 1) + goto out; + +again: + for (i = 0; i < MAX_NPORTS; i++) { + s->port = (s->port + 1) & (MAX_NPORTS - 1); + skbq = &s->p[s->port].skbq; + + skb = skb_peek(skbq); + + if (!skb) + continue; + + len = skb->len; + if (len <= s->p[s->port].avail) { + s->p[s->port].avail -= len; + s->num--; + __skb_unlink(skb, skbq); + goto out; + } + skb = NULL; + } + + if (update-- && sched_update_avail(sge)) + goto again; + +out: + /* If there are more pending skbs, we use the hardware to schedule us + * again. + */ + if (s->num && !skb) { + struct cmdQ *q = &sge->cmdQ[0]; + clear_bit(CMDQ_STAT_LAST_PKT_DB, &q->status); + if (test_and_set_bit(CMDQ_STAT_RUNNING, &q->status) == 0) { + set_bit(CMDQ_STAT_LAST_PKT_DB, &q->status); + writel(F_CMDQ0_ENABLE, sge->adapter->regs + A_SG_DOORBELL); + } + } + pr_debug("sched_skb ret %p\n", skb); + + return skb; +} + +/* + * PIO to indicate that memory mapped Q contains valid descriptor(s). + */ +static inline void doorbell_pio(struct adapter *adapter, u32 val) +{ + wmb(); + writel(val, adapter->regs + A_SG_DOORBELL); +} + +/* + * Frees all RX buffers on the freelist Q. The caller must make sure that + * the SGE is turned off before calling this function. + */ +static void free_freelQ_buffers(struct pci_dev *pdev, struct freelQ *q) +{ + unsigned int cidx = q->cidx; + + while (q->credits--) { + struct freelQ_ce *ce = &q->centries[cidx]; + + pci_unmap_single(pdev, dma_unmap_addr(ce, dma_addr), + dma_unmap_len(ce, dma_len), + PCI_DMA_FROMDEVICE); + dev_kfree_skb(ce->skb); + ce->skb = NULL; + if (++cidx == q->size) + cidx = 0; + } +} + +/* + * Free RX free list and response queue resources. + */ +static void free_rx_resources(struct sge *sge) +{ + struct pci_dev *pdev = sge->adapter->pdev; + unsigned int size, i; + + if (sge->respQ.entries) { + size = sizeof(struct respQ_e) * sge->respQ.size; + pci_free_consistent(pdev, size, sge->respQ.entries, + sge->respQ.dma_addr); + } + + for (i = 0; i < SGE_FREELQ_N; i++) { + struct freelQ *q = &sge->freelQ[i]; + + if (q->centries) { + free_freelQ_buffers(pdev, q); + kfree(q->centries); + } + if (q->entries) { + size = sizeof(struct freelQ_e) * q->size; + pci_free_consistent(pdev, size, q->entries, + q->dma_addr); + } + } +} + +/* + * Allocates basic RX resources, consisting of memory mapped freelist Qs and a + * response queue. + */ +static int alloc_rx_resources(struct sge *sge, struct sge_params *p) +{ + struct pci_dev *pdev = sge->adapter->pdev; + unsigned int size, i; + + for (i = 0; i < SGE_FREELQ_N; i++) { + struct freelQ *q = &sge->freelQ[i]; + + q->genbit = 1; + q->size = p->freelQ_size[i]; + q->dma_offset = sge->rx_pkt_pad ? 0 : NET_IP_ALIGN; + size = sizeof(struct freelQ_e) * q->size; + q->entries = pci_alloc_consistent(pdev, size, &q->dma_addr); + if (!q->entries) + goto err_no_mem; + + size = sizeof(struct freelQ_ce) * q->size; + q->centries = kzalloc(size, GFP_KERNEL); + if (!q->centries) + goto err_no_mem; + } + + /* + * Calculate the buffer sizes for the two free lists. FL0 accommodates + * regular sized Ethernet frames, FL1 is sized not to exceed 16K, + * including all the sk_buff overhead. + * + * Note: For T2 FL0 and FL1 are reversed. + */ + sge->freelQ[!sge->jumbo_fl].rx_buffer_size = SGE_RX_SM_BUF_SIZE + + sizeof(struct cpl_rx_data) + + sge->freelQ[!sge->jumbo_fl].dma_offset; + + size = (16 * 1024) - + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + + sge->freelQ[sge->jumbo_fl].rx_buffer_size = size; + + /* + * Setup which skb recycle Q should be used when recycling buffers from + * each free list. + */ + sge->freelQ[!sge->jumbo_fl].recycleq_idx = 0; + sge->freelQ[sge->jumbo_fl].recycleq_idx = 1; + + sge->respQ.genbit = 1; + sge->respQ.size = SGE_RESPQ_E_N; + sge->respQ.credits = 0; + size = sizeof(struct respQ_e) * sge->respQ.size; + sge->respQ.entries = + pci_alloc_consistent(pdev, size, &sge->respQ.dma_addr); + if (!sge->respQ.entries) + goto err_no_mem; + return 0; + +err_no_mem: + free_rx_resources(sge); + return -ENOMEM; +} + +/* + * Reclaims n TX descriptors and frees the buffers associated with them. + */ +static void free_cmdQ_buffers(struct sge *sge, struct cmdQ *q, unsigned int n) +{ + struct cmdQ_ce *ce; + struct pci_dev *pdev = sge->adapter->pdev; + unsigned int cidx = q->cidx; + + q->in_use -= n; + ce = &q->centries[cidx]; + while (n--) { + if (likely(dma_unmap_len(ce, dma_len))) { + pci_unmap_single(pdev, dma_unmap_addr(ce, dma_addr), + dma_unmap_len(ce, dma_len), + PCI_DMA_TODEVICE); + if (q->sop) + q->sop = 0; + } + if (ce->skb) { + dev_kfree_skb_any(ce->skb); + q->sop = 1; + } + ce++; + if (++cidx == q->size) { + cidx = 0; + ce = q->centries; + } + } + q->cidx = cidx; +} + +/* + * Free TX resources. + * + * Assumes that SGE is stopped and all interrupts are disabled. + */ +static void free_tx_resources(struct sge *sge) +{ + struct pci_dev *pdev = sge->adapter->pdev; + unsigned int size, i; + + for (i = 0; i < SGE_CMDQ_N; i++) { + struct cmdQ *q = &sge->cmdQ[i]; + + if (q->centries) { + if (q->in_use) + free_cmdQ_buffers(sge, q, q->in_use); + kfree(q->centries); + } + if (q->entries) { + size = sizeof(struct cmdQ_e) * q->size; + pci_free_consistent(pdev, size, q->entries, + q->dma_addr); + } + } +} + +/* + * Allocates basic TX resources, consisting of memory mapped command Qs. + */ +static int alloc_tx_resources(struct sge *sge, struct sge_params *p) +{ + struct pci_dev *pdev = sge->adapter->pdev; + unsigned int size, i; + + for (i = 0; i < SGE_CMDQ_N; i++) { + struct cmdQ *q = &sge->cmdQ[i]; + + q->genbit = 1; + q->sop = 1; + q->size = p->cmdQ_size[i]; + q->in_use = 0; + q->status = 0; + q->processed = q->cleaned = 0; + q->stop_thres = 0; + spin_lock_init(&q->lock); + size = sizeof(struct cmdQ_e) * q->size; + q->entries = pci_alloc_consistent(pdev, size, &q->dma_addr); + if (!q->entries) + goto err_no_mem; + + size = sizeof(struct cmdQ_ce) * q->size; + q->centries = kzalloc(size, GFP_KERNEL); + if (!q->centries) + goto err_no_mem; + } + + /* + * CommandQ 0 handles Ethernet and TOE packets, while queue 1 is TOE + * only. For queue 0 set the stop threshold so we can handle one more + * packet from each port, plus reserve an additional 24 entries for + * Ethernet packets only. Queue 1 never suspends nor do we reserve + * space for Ethernet packets. + */ + sge->cmdQ[0].stop_thres = sge->adapter->params.nports * + (MAX_SKB_FRAGS + 1); + return 0; + +err_no_mem: + free_tx_resources(sge); + return -ENOMEM; +} + +static inline void setup_ring_params(struct adapter *adapter, u64 addr, + u32 size, int base_reg_lo, + int base_reg_hi, int size_reg) +{ + writel((u32)addr, adapter->regs + base_reg_lo); + writel(addr >> 32, adapter->regs + base_reg_hi); + writel(size, adapter->regs + size_reg); +} + +/* + * Enable/disable VLAN acceleration. + */ +void t1_vlan_mode(struct adapter *adapter, u32 features) +{ + struct sge *sge = adapter->sge; + + if (features & NETIF_F_HW_VLAN_RX) + sge->sge_control |= F_VLAN_XTRACT; + else + sge->sge_control &= ~F_VLAN_XTRACT; + if (adapter->open_device_map) { + writel(sge->sge_control, adapter->regs + A_SG_CONTROL); + readl(adapter->regs + A_SG_CONTROL); /* flush */ + } +} + +/* + * Programs the various SGE registers. However, the engine is not yet enabled, + * but sge->sge_control is setup and ready to go. + */ +static void configure_sge(struct sge *sge, struct sge_params *p) +{ + struct adapter *ap = sge->adapter; + + writel(0, ap->regs + A_SG_CONTROL); + setup_ring_params(ap, sge->cmdQ[0].dma_addr, sge->cmdQ[0].size, + A_SG_CMD0BASELWR, A_SG_CMD0BASEUPR, A_SG_CMD0SIZE); + setup_ring_params(ap, sge->cmdQ[1].dma_addr, sge->cmdQ[1].size, + A_SG_CMD1BASELWR, A_SG_CMD1BASEUPR, A_SG_CMD1SIZE); + setup_ring_params(ap, sge->freelQ[0].dma_addr, + sge->freelQ[0].size, A_SG_FL0BASELWR, + A_SG_FL0BASEUPR, A_SG_FL0SIZE); + setup_ring_params(ap, sge->freelQ[1].dma_addr, + sge->freelQ[1].size, A_SG_FL1BASELWR, + A_SG_FL1BASEUPR, A_SG_FL1SIZE); + + /* The threshold comparison uses <. */ + writel(SGE_RX_SM_BUF_SIZE + 1, ap->regs + A_SG_FLTHRESHOLD); + + setup_ring_params(ap, sge->respQ.dma_addr, sge->respQ.size, + A_SG_RSPBASELWR, A_SG_RSPBASEUPR, A_SG_RSPSIZE); + writel((u32)sge->respQ.size - 1, ap->regs + A_SG_RSPQUEUECREDIT); + + sge->sge_control = F_CMDQ0_ENABLE | F_CMDQ1_ENABLE | F_FL0_ENABLE | + F_FL1_ENABLE | F_CPL_ENABLE | F_RESPONSE_QUEUE_ENABLE | + V_CMDQ_PRIORITY(2) | F_DISABLE_CMDQ1_GTS | F_ISCSI_COALESCE | + V_RX_PKT_OFFSET(sge->rx_pkt_pad); + +#if defined(__BIG_ENDIAN_BITFIELD) + sge->sge_control |= F_ENABLE_BIG_ENDIAN; +#endif + + /* Initialize no-resource timer */ + sge->intrtimer_nres = SGE_INTRTIMER_NRES * core_ticks_per_usec(ap); + + t1_sge_set_coalesce_params(sge, p); +} + +/* + * Return the payload capacity of the jumbo free-list buffers. + */ +static inline unsigned int jumbo_payload_capacity(const struct sge *sge) +{ + return sge->freelQ[sge->jumbo_fl].rx_buffer_size - + sge->freelQ[sge->jumbo_fl].dma_offset - + sizeof(struct cpl_rx_data); +} + +/* + * Frees all SGE related resources and the sge structure itself + */ +void t1_sge_destroy(struct sge *sge) +{ + int i; + + for_each_port(sge->adapter, i) + free_percpu(sge->port_stats[i]); + + kfree(sge->tx_sched); + free_tx_resources(sge); + free_rx_resources(sge); + kfree(sge); +} + +/* + * Allocates new RX buffers on the freelist Q (and tracks them on the freelist + * context Q) until the Q is full or alloc_skb fails. + * + * It is possible that the generation bits already match, indicating that the + * buffer is already valid and nothing needs to be done. This happens when we + * copied a received buffer into a new sk_buff during the interrupt processing. + * + * If the SGE doesn't automatically align packets properly (!sge->rx_pkt_pad), + * we specify a RX_OFFSET in order to make sure that the IP header is 4B + * aligned. + */ +static void refill_free_list(struct sge *sge, struct freelQ *q) +{ + struct pci_dev *pdev = sge->adapter->pdev; + struct freelQ_ce *ce = &q->centries[q->pidx]; + struct freelQ_e *e = &q->entries[q->pidx]; + unsigned int dma_len = q->rx_buffer_size - q->dma_offset; + + while (q->credits < q->size) { + struct sk_buff *skb; + dma_addr_t mapping; + + skb = alloc_skb(q->rx_buffer_size, GFP_ATOMIC); + if (!skb) + break; + + skb_reserve(skb, q->dma_offset); + mapping = pci_map_single(pdev, skb->data, dma_len, + PCI_DMA_FROMDEVICE); + skb_reserve(skb, sge->rx_pkt_pad); + + ce->skb = skb; + dma_unmap_addr_set(ce, dma_addr, mapping); + dma_unmap_len_set(ce, dma_len, dma_len); + e->addr_lo = (u32)mapping; + e->addr_hi = (u64)mapping >> 32; + e->len_gen = V_CMD_LEN(dma_len) | V_CMD_GEN1(q->genbit); + wmb(); + e->gen2 = V_CMD_GEN2(q->genbit); + + e++; + ce++; + if (++q->pidx == q->size) { + q->pidx = 0; + q->genbit ^= 1; + ce = q->centries; + e = q->entries; + } + q->credits++; + } +} + +/* + * Calls refill_free_list for both free lists. If we cannot fill at least 1/4 + * of both rings, we go into 'few interrupt mode' in order to give the system + * time to free up resources. + */ +static void freelQs_empty(struct sge *sge) +{ + struct adapter *adapter = sge->adapter; + u32 irq_reg = readl(adapter->regs + A_SG_INT_ENABLE); + u32 irqholdoff_reg; + + refill_free_list(sge, &sge->freelQ[0]); + refill_free_list(sge, &sge->freelQ[1]); + + if (sge->freelQ[0].credits > (sge->freelQ[0].size >> 2) && + sge->freelQ[1].credits > (sge->freelQ[1].size >> 2)) { + irq_reg |= F_FL_EXHAUSTED; + irqholdoff_reg = sge->fixed_intrtimer; + } else { + /* Clear the F_FL_EXHAUSTED interrupts for now */ + irq_reg &= ~F_FL_EXHAUSTED; + irqholdoff_reg = sge->intrtimer_nres; + } + writel(irqholdoff_reg, adapter->regs + A_SG_INTRTIMER); + writel(irq_reg, adapter->regs + A_SG_INT_ENABLE); + + /* We reenable the Qs to force a freelist GTS interrupt later */ + doorbell_pio(adapter, F_FL0_ENABLE | F_FL1_ENABLE); +} + +#define SGE_PL_INTR_MASK (F_PL_INTR_SGE_ERR | F_PL_INTR_SGE_DATA) +#define SGE_INT_FATAL (F_RESPQ_OVERFLOW | F_PACKET_TOO_BIG | F_PACKET_MISMATCH) +#define SGE_INT_ENABLE (F_RESPQ_EXHAUSTED | F_RESPQ_OVERFLOW | \ + F_FL_EXHAUSTED | F_PACKET_TOO_BIG | F_PACKET_MISMATCH) + +/* + * Disable SGE Interrupts + */ +void t1_sge_intr_disable(struct sge *sge) +{ + u32 val = readl(sge->adapter->regs + A_PL_ENABLE); + + writel(val & ~SGE_PL_INTR_MASK, sge->adapter->regs + A_PL_ENABLE); + writel(0, sge->adapter->regs + A_SG_INT_ENABLE); +} + +/* + * Enable SGE interrupts. + */ +void t1_sge_intr_enable(struct sge *sge) +{ + u32 en = SGE_INT_ENABLE; + u32 val = readl(sge->adapter->regs + A_PL_ENABLE); + + if (sge->adapter->port[0].dev->hw_features & NETIF_F_TSO) + en &= ~F_PACKET_TOO_BIG; + writel(en, sge->adapter->regs + A_SG_INT_ENABLE); + writel(val | SGE_PL_INTR_MASK, sge->adapter->regs + A_PL_ENABLE); +} + +/* + * Clear SGE interrupts. + */ +void t1_sge_intr_clear(struct sge *sge) +{ + writel(SGE_PL_INTR_MASK, sge->adapter->regs + A_PL_CAUSE); + writel(0xffffffff, sge->adapter->regs + A_SG_INT_CAUSE); +} + +/* + * SGE 'Error' interrupt handler + */ +int t1_sge_intr_error_handler(struct sge *sge) +{ + struct adapter *adapter = sge->adapter; + u32 cause = readl(adapter->regs + A_SG_INT_CAUSE); + + if (adapter->port[0].dev->hw_features & NETIF_F_TSO) + cause &= ~F_PACKET_TOO_BIG; + if (cause & F_RESPQ_EXHAUSTED) + sge->stats.respQ_empty++; + if (cause & F_RESPQ_OVERFLOW) { + sge->stats.respQ_overflow++; + pr_alert("%s: SGE response queue overflow\n", + adapter->name); + } + if (cause & F_FL_EXHAUSTED) { + sge->stats.freelistQ_empty++; + freelQs_empty(sge); + } + if (cause & F_PACKET_TOO_BIG) { + sge->stats.pkt_too_big++; + pr_alert("%s: SGE max packet size exceeded\n", + adapter->name); + } + if (cause & F_PACKET_MISMATCH) { + sge->stats.pkt_mismatch++; + pr_alert("%s: SGE packet mismatch\n", adapter->name); + } + if (cause & SGE_INT_FATAL) + t1_fatal_err(adapter); + + writel(cause, adapter->regs + A_SG_INT_CAUSE); + return 0; +} + +const struct sge_intr_counts *t1_sge_get_intr_counts(const struct sge *sge) +{ + return &sge->stats; +} + +void t1_sge_get_port_stats(const struct sge *sge, int port, + struct sge_port_stats *ss) +{ + int cpu; + + memset(ss, 0, sizeof(*ss)); + for_each_possible_cpu(cpu) { + struct sge_port_stats *st = per_cpu_ptr(sge->port_stats[port], cpu); + + ss->rx_cso_good += st->rx_cso_good; + ss->tx_cso += st->tx_cso; + ss->tx_tso += st->tx_tso; + ss->tx_need_hdrroom += st->tx_need_hdrroom; + ss->vlan_xtract += st->vlan_xtract; + ss->vlan_insert += st->vlan_insert; + } +} + +/** + * recycle_fl_buf - recycle a free list buffer + * @fl: the free list + * @idx: index of buffer to recycle + * + * Recycles the specified buffer on the given free list by adding it at + * the next available slot on the list. + */ +static void recycle_fl_buf(struct freelQ *fl, int idx) +{ + struct freelQ_e *from = &fl->entries[idx]; + struct freelQ_e *to = &fl->entries[fl->pidx]; + + fl->centries[fl->pidx] = fl->centries[idx]; + to->addr_lo = from->addr_lo; + to->addr_hi = from->addr_hi; + to->len_gen = G_CMD_LEN(from->len_gen) | V_CMD_GEN1(fl->genbit); + wmb(); + to->gen2 = V_CMD_GEN2(fl->genbit); + fl->credits++; + + if (++fl->pidx == fl->size) { + fl->pidx = 0; + fl->genbit ^= 1; + } +} + +static int copybreak __read_mostly = 256; +module_param(copybreak, int, 0); +MODULE_PARM_DESC(copybreak, "Receive copy threshold"); + +/** + * get_packet - return the next ingress packet buffer + * @pdev: the PCI device that received the packet + * @fl: the SGE free list holding the packet + * @len: the actual packet length, excluding any SGE padding + * + * Get the next packet from a free list and complete setup of the + * sk_buff. If the packet is small we make a copy and recycle the + * original buffer, otherwise we use the original buffer itself. If a + * positive drop threshold is supplied packets are dropped and their + * buffers recycled if (a) the number of remaining buffers is under the + * threshold and the packet is too big to copy, or (b) the packet should + * be copied but there is no memory for the copy. + */ +static inline struct sk_buff *get_packet(struct pci_dev *pdev, + struct freelQ *fl, unsigned int len) +{ + struct sk_buff *skb; + const struct freelQ_ce *ce = &fl->centries[fl->cidx]; + + if (len < copybreak) { + skb = alloc_skb(len + 2, GFP_ATOMIC); + if (!skb) + goto use_orig_buf; + + skb_reserve(skb, 2); /* align IP header */ + skb_put(skb, len); + pci_dma_sync_single_for_cpu(pdev, + dma_unmap_addr(ce, dma_addr), + dma_unmap_len(ce, dma_len), + PCI_DMA_FROMDEVICE); + skb_copy_from_linear_data(ce->skb, skb->data, len); + pci_dma_sync_single_for_device(pdev, + dma_unmap_addr(ce, dma_addr), + dma_unmap_len(ce, dma_len), + PCI_DMA_FROMDEVICE); + recycle_fl_buf(fl, fl->cidx); + return skb; + } + +use_orig_buf: + if (fl->credits < 2) { + recycle_fl_buf(fl, fl->cidx); + return NULL; + } + + pci_unmap_single(pdev, dma_unmap_addr(ce, dma_addr), + dma_unmap_len(ce, dma_len), PCI_DMA_FROMDEVICE); + skb = ce->skb; + prefetch(skb->data); + + skb_put(skb, len); + return skb; +} + +/** + * unexpected_offload - handle an unexpected offload packet + * @adapter: the adapter + * @fl: the free list that received the packet + * + * Called when we receive an unexpected offload packet (e.g., the TOE + * function is disabled or the card is a NIC). Prints a message and + * recycles the buffer. + */ +static void unexpected_offload(struct adapter *adapter, struct freelQ *fl) +{ + struct freelQ_ce *ce = &fl->centries[fl->cidx]; + struct sk_buff *skb = ce->skb; + + pci_dma_sync_single_for_cpu(adapter->pdev, dma_unmap_addr(ce, dma_addr), + dma_unmap_len(ce, dma_len), PCI_DMA_FROMDEVICE); + pr_err("%s: unexpected offload packet, cmd %u\n", + adapter->name, *skb->data); + recycle_fl_buf(fl, fl->cidx); +} + +/* + * T1/T2 SGE limits the maximum DMA size per TX descriptor to + * SGE_TX_DESC_MAX_PLEN (16KB). If the PAGE_SIZE is larger than 16KB, the + * stack might send more than SGE_TX_DESC_MAX_PLEN in a contiguous manner. + * Note that the *_large_page_tx_descs stuff will be optimized out when + * PAGE_SIZE <= SGE_TX_DESC_MAX_PLEN. + * + * compute_large_page_descs() computes how many additional descriptors are + * required to break down the stack's request. + */ +static inline unsigned int compute_large_page_tx_descs(struct sk_buff *skb) +{ + unsigned int count = 0; + + if (PAGE_SIZE > SGE_TX_DESC_MAX_PLEN) { + unsigned int nfrags = skb_shinfo(skb)->nr_frags; + unsigned int i, len = skb_headlen(skb); + while (len > SGE_TX_DESC_MAX_PLEN) { + count++; + len -= SGE_TX_DESC_MAX_PLEN; + } + for (i = 0; nfrags--; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + len = frag->size; + while (len > SGE_TX_DESC_MAX_PLEN) { + count++; + len -= SGE_TX_DESC_MAX_PLEN; + } + } + } + return count; +} + +/* + * Write a cmdQ entry. + * + * Since this function writes the 'flags' field, it must not be used to + * write the first cmdQ entry. + */ +static inline void write_tx_desc(struct cmdQ_e *e, dma_addr_t mapping, + unsigned int len, unsigned int gen, + unsigned int eop) +{ + BUG_ON(len > SGE_TX_DESC_MAX_PLEN); + + e->addr_lo = (u32)mapping; + e->addr_hi = (u64)mapping >> 32; + e->len_gen = V_CMD_LEN(len) | V_CMD_GEN1(gen); + e->flags = F_CMD_DATAVALID | V_CMD_EOP(eop) | V_CMD_GEN2(gen); +} + +/* + * See comment for previous function. + * + * write_tx_descs_large_page() writes additional SGE tx descriptors if + * *desc_len exceeds HW's capability. + */ +static inline unsigned int write_large_page_tx_descs(unsigned int pidx, + struct cmdQ_e **e, + struct cmdQ_ce **ce, + unsigned int *gen, + dma_addr_t *desc_mapping, + unsigned int *desc_len, + unsigned int nfrags, + struct cmdQ *q) +{ + if (PAGE_SIZE > SGE_TX_DESC_MAX_PLEN) { + struct cmdQ_e *e1 = *e; + struct cmdQ_ce *ce1 = *ce; + + while (*desc_len > SGE_TX_DESC_MAX_PLEN) { + *desc_len -= SGE_TX_DESC_MAX_PLEN; + write_tx_desc(e1, *desc_mapping, SGE_TX_DESC_MAX_PLEN, + *gen, nfrags == 0 && *desc_len == 0); + ce1->skb = NULL; + dma_unmap_len_set(ce1, dma_len, 0); + *desc_mapping += SGE_TX_DESC_MAX_PLEN; + if (*desc_len) { + ce1++; + e1++; + if (++pidx == q->size) { + pidx = 0; + *gen ^= 1; + ce1 = q->centries; + e1 = q->entries; + } + } + } + *e = e1; + *ce = ce1; + } + return pidx; +} + +/* + * Write the command descriptors to transmit the given skb starting at + * descriptor pidx with the given generation. + */ +static inline void write_tx_descs(struct adapter *adapter, struct sk_buff *skb, + unsigned int pidx, unsigned int gen, + struct cmdQ *q) +{ + dma_addr_t mapping, desc_mapping; + struct cmdQ_e *e, *e1; + struct cmdQ_ce *ce; + unsigned int i, flags, first_desc_len, desc_len, + nfrags = skb_shinfo(skb)->nr_frags; + + e = e1 = &q->entries[pidx]; + ce = &q->centries[pidx]; + + mapping = pci_map_single(adapter->pdev, skb->data, + skb_headlen(skb), PCI_DMA_TODEVICE); + + desc_mapping = mapping; + desc_len = skb_headlen(skb); + + flags = F_CMD_DATAVALID | F_CMD_SOP | + V_CMD_EOP(nfrags == 0 && desc_len <= SGE_TX_DESC_MAX_PLEN) | + V_CMD_GEN2(gen); + first_desc_len = (desc_len <= SGE_TX_DESC_MAX_PLEN) ? + desc_len : SGE_TX_DESC_MAX_PLEN; + e->addr_lo = (u32)desc_mapping; + e->addr_hi = (u64)desc_mapping >> 32; + e->len_gen = V_CMD_LEN(first_desc_len) | V_CMD_GEN1(gen); + ce->skb = NULL; + dma_unmap_len_set(ce, dma_len, 0); + + if (PAGE_SIZE > SGE_TX_DESC_MAX_PLEN && + desc_len > SGE_TX_DESC_MAX_PLEN) { + desc_mapping += first_desc_len; + desc_len -= first_desc_len; + e1++; + ce++; + if (++pidx == q->size) { + pidx = 0; + gen ^= 1; + e1 = q->entries; + ce = q->centries; + } + pidx = write_large_page_tx_descs(pidx, &e1, &ce, &gen, + &desc_mapping, &desc_len, + nfrags, q); + + if (likely(desc_len)) + write_tx_desc(e1, desc_mapping, desc_len, gen, + nfrags == 0); + } + + ce->skb = NULL; + dma_unmap_addr_set(ce, dma_addr, mapping); + dma_unmap_len_set(ce, dma_len, skb_headlen(skb)); + + for (i = 0; nfrags--; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + e1++; + ce++; + if (++pidx == q->size) { + pidx = 0; + gen ^= 1; + e1 = q->entries; + ce = q->centries; + } + + mapping = pci_map_page(adapter->pdev, frag->page, + frag->page_offset, frag->size, + PCI_DMA_TODEVICE); + desc_mapping = mapping; + desc_len = frag->size; + + pidx = write_large_page_tx_descs(pidx, &e1, &ce, &gen, + &desc_mapping, &desc_len, + nfrags, q); + if (likely(desc_len)) + write_tx_desc(e1, desc_mapping, desc_len, gen, + nfrags == 0); + ce->skb = NULL; + dma_unmap_addr_set(ce, dma_addr, mapping); + dma_unmap_len_set(ce, dma_len, frag->size); + } + ce->skb = skb; + wmb(); + e->flags = flags; +} + +/* + * Clean up completed Tx buffers. + */ +static inline void reclaim_completed_tx(struct sge *sge, struct cmdQ *q) +{ + unsigned int reclaim = q->processed - q->cleaned; + + if (reclaim) { + pr_debug("reclaim_completed_tx processed:%d cleaned:%d\n", + q->processed, q->cleaned); + free_cmdQ_buffers(sge, q, reclaim); + q->cleaned += reclaim; + } +} + +/* + * Called from tasklet. Checks the scheduler for any + * pending skbs that can be sent. + */ +static void restart_sched(unsigned long arg) +{ + struct sge *sge = (struct sge *) arg; + struct adapter *adapter = sge->adapter; + struct cmdQ *q = &sge->cmdQ[0]; + struct sk_buff *skb; + unsigned int credits, queued_skb = 0; + + spin_lock(&q->lock); + reclaim_completed_tx(sge, q); + + credits = q->size - q->in_use; + pr_debug("restart_sched credits=%d\n", credits); + while ((skb = sched_skb(sge, NULL, credits)) != NULL) { + unsigned int genbit, pidx, count; + count = 1 + skb_shinfo(skb)->nr_frags; + count += compute_large_page_tx_descs(skb); + q->in_use += count; + genbit = q->genbit; + pidx = q->pidx; + q->pidx += count; + if (q->pidx >= q->size) { + q->pidx -= q->size; + q->genbit ^= 1; + } + write_tx_descs(adapter, skb, pidx, genbit, q); + credits = q->size - q->in_use; + queued_skb = 1; + } + + if (queued_skb) { + clear_bit(CMDQ_STAT_LAST_PKT_DB, &q->status); + if (test_and_set_bit(CMDQ_STAT_RUNNING, &q->status) == 0) { + set_bit(CMDQ_STAT_LAST_PKT_DB, &q->status); + writel(F_CMDQ0_ENABLE, adapter->regs + A_SG_DOORBELL); + } + } + spin_unlock(&q->lock); +} + +/** + * sge_rx - process an ingress ethernet packet + * @sge: the sge structure + * @fl: the free list that contains the packet buffer + * @len: the packet length + * + * Process an ingress ethernet pakcet and deliver it to the stack. + */ +static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len) +{ + struct sk_buff *skb; + const struct cpl_rx_pkt *p; + struct adapter *adapter = sge->adapter; + struct sge_port_stats *st; + struct net_device *dev; + + skb = get_packet(adapter->pdev, fl, len - sge->rx_pkt_pad); + if (unlikely(!skb)) { + sge->stats.rx_drops++; + return; + } + + p = (const struct cpl_rx_pkt *) skb->data; + if (p->iff >= adapter->params.nports) { + kfree_skb(skb); + return; + } + __skb_pull(skb, sizeof(*p)); + + st = this_cpu_ptr(sge->port_stats[p->iff]); + dev = adapter->port[p->iff].dev; + + skb->protocol = eth_type_trans(skb, dev); + if ((dev->features & NETIF_F_RXCSUM) && p->csum == 0xffff && + skb->protocol == htons(ETH_P_IP) && + (skb->data[9] == IPPROTO_TCP || skb->data[9] == IPPROTO_UDP)) { + ++st->rx_cso_good; + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else + skb_checksum_none_assert(skb); + + if (p->vlan_valid) { + st->vlan_xtract++; + __vlan_hwaccel_put_tag(skb, ntohs(p->vlan)); + } + netif_receive_skb(skb); +} + +/* + * Returns true if a command queue has enough available descriptors that + * we can resume Tx operation after temporarily disabling its packet queue. + */ +static inline int enough_free_Tx_descs(const struct cmdQ *q) +{ + unsigned int r = q->processed - q->cleaned; + + return q->in_use - r < (q->size >> 1); +} + +/* + * Called when sufficient space has become available in the SGE command queues + * after the Tx packet schedulers have been suspended to restart the Tx path. + */ +static void restart_tx_queues(struct sge *sge) +{ + struct adapter *adap = sge->adapter; + int i; + + if (!enough_free_Tx_descs(&sge->cmdQ[0])) + return; + + for_each_port(adap, i) { + struct net_device *nd = adap->port[i].dev; + + if (test_and_clear_bit(nd->if_port, &sge->stopped_tx_queues) && + netif_running(nd)) { + sge->stats.cmdQ_restarted[2]++; + netif_wake_queue(nd); + } + } +} + +/* + * update_tx_info is called from the interrupt handler/NAPI to return cmdQ0 + * information. + */ +static unsigned int update_tx_info(struct adapter *adapter, + unsigned int flags, + unsigned int pr0) +{ + struct sge *sge = adapter->sge; + struct cmdQ *cmdq = &sge->cmdQ[0]; + + cmdq->processed += pr0; + if (flags & (F_FL0_ENABLE | F_FL1_ENABLE)) { + freelQs_empty(sge); + flags &= ~(F_FL0_ENABLE | F_FL1_ENABLE); + } + if (flags & F_CMDQ0_ENABLE) { + clear_bit(CMDQ_STAT_RUNNING, &cmdq->status); + + if (cmdq->cleaned + cmdq->in_use != cmdq->processed && + !test_and_set_bit(CMDQ_STAT_LAST_PKT_DB, &cmdq->status)) { + set_bit(CMDQ_STAT_RUNNING, &cmdq->status); + writel(F_CMDQ0_ENABLE, adapter->regs + A_SG_DOORBELL); + } + if (sge->tx_sched) + tasklet_hi_schedule(&sge->tx_sched->sched_tsk); + + flags &= ~F_CMDQ0_ENABLE; + } + + if (unlikely(sge->stopped_tx_queues != 0)) + restart_tx_queues(sge); + + return flags; +} + +/* + * Process SGE responses, up to the supplied budget. Returns the number of + * responses processed. A negative budget is effectively unlimited. + */ +static int process_responses(struct adapter *adapter, int budget) +{ + struct sge *sge = adapter->sge; + struct respQ *q = &sge->respQ; + struct respQ_e *e = &q->entries[q->cidx]; + int done = 0; + unsigned int flags = 0; + unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0}; + + while (done < budget && e->GenerationBit == q->genbit) { + flags |= e->Qsleeping; + + cmdq_processed[0] += e->Cmdq0CreditReturn; + cmdq_processed[1] += e->Cmdq1CreditReturn; + + /* We batch updates to the TX side to avoid cacheline + * ping-pong of TX state information on MP where the sender + * might run on a different CPU than this function... + */ + if (unlikely((flags & F_CMDQ0_ENABLE) || cmdq_processed[0] > 64)) { + flags = update_tx_info(adapter, flags, cmdq_processed[0]); + cmdq_processed[0] = 0; + } + + if (unlikely(cmdq_processed[1] > 16)) { + sge->cmdQ[1].processed += cmdq_processed[1]; + cmdq_processed[1] = 0; + } + + if (likely(e->DataValid)) { + struct freelQ *fl = &sge->freelQ[e->FreelistQid]; + + BUG_ON(!e->Sop || !e->Eop); + if (unlikely(e->Offload)) + unexpected_offload(adapter, fl); + else + sge_rx(sge, fl, e->BufferLength); + + ++done; + + /* + * Note: this depends on each packet consuming a + * single free-list buffer; cf. the BUG above. + */ + if (++fl->cidx == fl->size) + fl->cidx = 0; + prefetch(fl->centries[fl->cidx].skb); + + if (unlikely(--fl->credits < + fl->size - SGE_FREEL_REFILL_THRESH)) + refill_free_list(sge, fl); + } else + sge->stats.pure_rsps++; + + e++; + if (unlikely(++q->cidx == q->size)) { + q->cidx = 0; + q->genbit ^= 1; + e = q->entries; + } + prefetch(e); + + if (++q->credits > SGE_RESPQ_REPLENISH_THRES) { + writel(q->credits, adapter->regs + A_SG_RSPQUEUECREDIT); + q->credits = 0; + } + } + + flags = update_tx_info(adapter, flags, cmdq_processed[0]); + sge->cmdQ[1].processed += cmdq_processed[1]; + + return done; +} + +static inline int responses_pending(const struct adapter *adapter) +{ + const struct respQ *Q = &adapter->sge->respQ; + const struct respQ_e *e = &Q->entries[Q->cidx]; + + return e->GenerationBit == Q->genbit; +} + +/* + * A simpler version of process_responses() that handles only pure (i.e., + * non data-carrying) responses. Such respones are too light-weight to justify + * calling a softirq when using NAPI, so we handle them specially in hard + * interrupt context. The function is called with a pointer to a response, + * which the caller must ensure is a valid pure response. Returns 1 if it + * encounters a valid data-carrying response, 0 otherwise. + */ +static int process_pure_responses(struct adapter *adapter) +{ + struct sge *sge = adapter->sge; + struct respQ *q = &sge->respQ; + struct respQ_e *e = &q->entries[q->cidx]; + const struct freelQ *fl = &sge->freelQ[e->FreelistQid]; + unsigned int flags = 0; + unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0}; + + prefetch(fl->centries[fl->cidx].skb); + if (e->DataValid) + return 1; + + do { + flags |= e->Qsleeping; + + cmdq_processed[0] += e->Cmdq0CreditReturn; + cmdq_processed[1] += e->Cmdq1CreditReturn; + + e++; + if (unlikely(++q->cidx == q->size)) { + q->cidx = 0; + q->genbit ^= 1; + e = q->entries; + } + prefetch(e); + + if (++q->credits > SGE_RESPQ_REPLENISH_THRES) { + writel(q->credits, adapter->regs + A_SG_RSPQUEUECREDIT); + q->credits = 0; + } + sge->stats.pure_rsps++; + } while (e->GenerationBit == q->genbit && !e->DataValid); + + flags = update_tx_info(adapter, flags, cmdq_processed[0]); + sge->cmdQ[1].processed += cmdq_processed[1]; + + return e->GenerationBit == q->genbit; +} + +/* + * Handler for new data events when using NAPI. This does not need any locking + * or protection from interrupts as data interrupts are off at this point and + * other adapter interrupts do not interfere. + */ +int t1_poll(struct napi_struct *napi, int budget) +{ + struct adapter *adapter = container_of(napi, struct adapter, napi); + int work_done = process_responses(adapter, budget); + + if (likely(work_done < budget)) { + napi_complete(napi); + writel(adapter->sge->respQ.cidx, + adapter->regs + A_SG_SLEEPING); + } + return work_done; +} + +irqreturn_t t1_interrupt(int irq, void *data) +{ + struct adapter *adapter = data; + struct sge *sge = adapter->sge; + int handled; + + if (likely(responses_pending(adapter))) { + writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE); + + if (napi_schedule_prep(&adapter->napi)) { + if (process_pure_responses(adapter)) + __napi_schedule(&adapter->napi); + else { + /* no data, no NAPI needed */ + writel(sge->respQ.cidx, adapter->regs + A_SG_SLEEPING); + /* undo schedule_prep */ + napi_enable(&adapter->napi); + } + } + return IRQ_HANDLED; + } + + spin_lock(&adapter->async_lock); + handled = t1_slow_intr_handler(adapter); + spin_unlock(&adapter->async_lock); + + if (!handled) + sge->stats.unhandled_irqs++; + + return IRQ_RETVAL(handled != 0); +} + +/* + * Enqueues the sk_buff onto the cmdQ[qid] and has hardware fetch it. + * + * The code figures out how many entries the sk_buff will require in the + * cmdQ and updates the cmdQ data structure with the state once the enqueue + * has complete. Then, it doesn't access the global structure anymore, but + * uses the corresponding fields on the stack. In conjunction with a spinlock + * around that code, we can make the function reentrant without holding the + * lock when we actually enqueue (which might be expensive, especially on + * architectures with IO MMUs). + * + * This runs with softirqs disabled. + */ +static int t1_sge_tx(struct sk_buff *skb, struct adapter *adapter, + unsigned int qid, struct net_device *dev) +{ + struct sge *sge = adapter->sge; + struct cmdQ *q = &sge->cmdQ[qid]; + unsigned int credits, pidx, genbit, count, use_sched_skb = 0; + + if (!spin_trylock(&q->lock)) + return NETDEV_TX_LOCKED; + + reclaim_completed_tx(sge, q); + + pidx = q->pidx; + credits = q->size - q->in_use; + count = 1 + skb_shinfo(skb)->nr_frags; + count += compute_large_page_tx_descs(skb); + + /* Ethernet packet */ + if (unlikely(credits < count)) { + if (!netif_queue_stopped(dev)) { + netif_stop_queue(dev); + set_bit(dev->if_port, &sge->stopped_tx_queues); + sge->stats.cmdQ_full[2]++; + pr_err("%s: Tx ring full while queue awake!\n", + adapter->name); + } + spin_unlock(&q->lock); + return NETDEV_TX_BUSY; + } + + if (unlikely(credits - count < q->stop_thres)) { + netif_stop_queue(dev); + set_bit(dev->if_port, &sge->stopped_tx_queues); + sge->stats.cmdQ_full[2]++; + } + + /* T204 cmdQ0 skbs that are destined for a certain port have to go + * through the scheduler. + */ + if (sge->tx_sched && !qid && skb->dev) { +use_sched: + use_sched_skb = 1; + /* Note that the scheduler might return a different skb than + * the one passed in. + */ + skb = sched_skb(sge, skb, credits); + if (!skb) { + spin_unlock(&q->lock); + return NETDEV_TX_OK; + } + pidx = q->pidx; + count = 1 + skb_shinfo(skb)->nr_frags; + count += compute_large_page_tx_descs(skb); + } + + q->in_use += count; + genbit = q->genbit; + pidx = q->pidx; + q->pidx += count; + if (q->pidx >= q->size) { + q->pidx -= q->size; + q->genbit ^= 1; + } + spin_unlock(&q->lock); + + write_tx_descs(adapter, skb, pidx, genbit, q); + + /* + * We always ring the doorbell for cmdQ1. For cmdQ0, we only ring + * the doorbell if the Q is asleep. There is a natural race, where + * the hardware is going to sleep just after we checked, however, + * then the interrupt handler will detect the outstanding TX packet + * and ring the doorbell for us. + */ + if (qid) + doorbell_pio(adapter, F_CMDQ1_ENABLE); + else { + clear_bit(CMDQ_STAT_LAST_PKT_DB, &q->status); + if (test_and_set_bit(CMDQ_STAT_RUNNING, &q->status) == 0) { + set_bit(CMDQ_STAT_LAST_PKT_DB, &q->status); + writel(F_CMDQ0_ENABLE, adapter->regs + A_SG_DOORBELL); + } + } + + if (use_sched_skb) { + if (spin_trylock(&q->lock)) { + credits = q->size - q->in_use; + skb = NULL; + goto use_sched; + } + } + return NETDEV_TX_OK; +} + +#define MK_ETH_TYPE_MSS(type, mss) (((mss) & 0x3FFF) | ((type) << 14)) + +/* + * eth_hdr_len - return the length of an Ethernet header + * @data: pointer to the start of the Ethernet header + * + * Returns the length of an Ethernet header, including optional VLAN tag. + */ +static inline int eth_hdr_len(const void *data) +{ + const struct ethhdr *e = data; + + return e->h_proto == htons(ETH_P_8021Q) ? VLAN_ETH_HLEN : ETH_HLEN; +} + +/* + * Adds the CPL header to the sk_buff and passes it to t1_sge_tx. + */ +netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct adapter *adapter = dev->ml_priv; + struct sge *sge = adapter->sge; + struct sge_port_stats *st = this_cpu_ptr(sge->port_stats[dev->if_port]); + struct cpl_tx_pkt *cpl; + struct sk_buff *orig_skb = skb; + int ret; + + if (skb->protocol == htons(ETH_P_CPL5)) + goto send; + + /* + * We are using a non-standard hard_header_len. + * Allocate more header room in the rare cases it is not big enough. + */ + if (unlikely(skb_headroom(skb) < dev->hard_header_len - ETH_HLEN)) { + skb = skb_realloc_headroom(skb, sizeof(struct cpl_tx_pkt_lso)); + ++st->tx_need_hdrroom; + dev_kfree_skb_any(orig_skb); + if (!skb) + return NETDEV_TX_OK; + } + + if (skb_shinfo(skb)->gso_size) { + int eth_type; + struct cpl_tx_pkt_lso *hdr; + + ++st->tx_tso; + + eth_type = skb_network_offset(skb) == ETH_HLEN ? + CPL_ETH_II : CPL_ETH_II_VLAN; + + hdr = (struct cpl_tx_pkt_lso *)skb_push(skb, sizeof(*hdr)); + hdr->opcode = CPL_TX_PKT_LSO; + hdr->ip_csum_dis = hdr->l4_csum_dis = 0; + hdr->ip_hdr_words = ip_hdr(skb)->ihl; + hdr->tcp_hdr_words = tcp_hdr(skb)->doff; + hdr->eth_type_mss = htons(MK_ETH_TYPE_MSS(eth_type, + skb_shinfo(skb)->gso_size)); + hdr->len = htonl(skb->len - sizeof(*hdr)); + cpl = (struct cpl_tx_pkt *)hdr; + } else { + /* + * Packets shorter than ETH_HLEN can break the MAC, drop them + * early. Also, we may get oversized packets because some + * parts of the kernel don't handle our unusual hard_header_len + * right, drop those too. + */ + if (unlikely(skb->len < ETH_HLEN || + skb->len > dev->mtu + eth_hdr_len(skb->data))) { + pr_debug("%s: packet size %d hdr %d mtu%d\n", dev->name, + skb->len, eth_hdr_len(skb->data), dev->mtu); + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + if (skb->ip_summed == CHECKSUM_PARTIAL && + ip_hdr(skb)->protocol == IPPROTO_UDP) { + if (unlikely(skb_checksum_help(skb))) { + pr_debug("%s: unable to do udp checksum\n", dev->name); + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + } + + /* Hmmm, assuming to catch the gratious arp... and we'll use + * it to flush out stuck espi packets... + */ + if ((unlikely(!adapter->sge->espibug_skb[dev->if_port]))) { + if (skb->protocol == htons(ETH_P_ARP) && + arp_hdr(skb)->ar_op == htons(ARPOP_REQUEST)) { + adapter->sge->espibug_skb[dev->if_port] = skb; + /* We want to re-use this skb later. We + * simply bump the reference count and it + * will not be freed... + */ + skb = skb_get(skb); + } + } + + cpl = (struct cpl_tx_pkt *)__skb_push(skb, sizeof(*cpl)); + cpl->opcode = CPL_TX_PKT; + cpl->ip_csum_dis = 1; /* SW calculates IP csum */ + cpl->l4_csum_dis = skb->ip_summed == CHECKSUM_PARTIAL ? 0 : 1; + /* the length field isn't used so don't bother setting it */ + + st->tx_cso += (skb->ip_summed == CHECKSUM_PARTIAL); + } + cpl->iff = dev->if_port; + + if (vlan_tx_tag_present(skb)) { + cpl->vlan_valid = 1; + cpl->vlan = htons(vlan_tx_tag_get(skb)); + st->vlan_insert++; + } else + cpl->vlan_valid = 0; + +send: + ret = t1_sge_tx(skb, adapter, 0, dev); + + /* If transmit busy, and we reallocated skb's due to headroom limit, + * then silently discard to avoid leak. + */ + if (unlikely(ret != NETDEV_TX_OK && skb != orig_skb)) { + dev_kfree_skb_any(skb); + ret = NETDEV_TX_OK; + } + return ret; +} + +/* + * Callback for the Tx buffer reclaim timer. Runs with softirqs disabled. + */ +static void sge_tx_reclaim_cb(unsigned long data) +{ + int i; + struct sge *sge = (struct sge *)data; + + for (i = 0; i < SGE_CMDQ_N; ++i) { + struct cmdQ *q = &sge->cmdQ[i]; + + if (!spin_trylock(&q->lock)) + continue; + + reclaim_completed_tx(sge, q); + if (i == 0 && q->in_use) { /* flush pending credits */ + writel(F_CMDQ0_ENABLE, sge->adapter->regs + A_SG_DOORBELL); + } + spin_unlock(&q->lock); + } + mod_timer(&sge->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD); +} + +/* + * Propagate changes of the SGE coalescing parameters to the HW. + */ +int t1_sge_set_coalesce_params(struct sge *sge, struct sge_params *p) +{ + sge->fixed_intrtimer = p->rx_coalesce_usecs * + core_ticks_per_usec(sge->adapter); + writel(sge->fixed_intrtimer, sge->adapter->regs + A_SG_INTRTIMER); + return 0; +} + +/* + * Allocates both RX and TX resources and configures the SGE. However, + * the hardware is not enabled yet. + */ +int t1_sge_configure(struct sge *sge, struct sge_params *p) +{ + if (alloc_rx_resources(sge, p)) + return -ENOMEM; + if (alloc_tx_resources(sge, p)) { + free_rx_resources(sge); + return -ENOMEM; + } + configure_sge(sge, p); + + /* + * Now that we have sized the free lists calculate the payload + * capacity of the large buffers. Other parts of the driver use + * this to set the max offload coalescing size so that RX packets + * do not overflow our large buffers. + */ + p->large_buf_capacity = jumbo_payload_capacity(sge); + return 0; +} + +/* + * Disables the DMA engine. + */ +void t1_sge_stop(struct sge *sge) +{ + int i; + writel(0, sge->adapter->regs + A_SG_CONTROL); + readl(sge->adapter->regs + A_SG_CONTROL); /* flush */ + + if (is_T2(sge->adapter)) + del_timer_sync(&sge->espibug_timer); + + del_timer_sync(&sge->tx_reclaim_timer); + if (sge->tx_sched) + tx_sched_stop(sge); + + for (i = 0; i < MAX_NPORTS; i++) + kfree_skb(sge->espibug_skb[i]); +} + +/* + * Enables the DMA engine. + */ +void t1_sge_start(struct sge *sge) +{ + refill_free_list(sge, &sge->freelQ[0]); + refill_free_list(sge, &sge->freelQ[1]); + + writel(sge->sge_control, sge->adapter->regs + A_SG_CONTROL); + doorbell_pio(sge->adapter, F_FL0_ENABLE | F_FL1_ENABLE); + readl(sge->adapter->regs + A_SG_CONTROL); /* flush */ + + mod_timer(&sge->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD); + + if (is_T2(sge->adapter)) + mod_timer(&sge->espibug_timer, jiffies + sge->espibug_timeout); +} + +/* + * Callback for the T2 ESPI 'stuck packet feature' workaorund + */ +static void espibug_workaround_t204(unsigned long data) +{ + struct adapter *adapter = (struct adapter *)data; + struct sge *sge = adapter->sge; + unsigned int nports = adapter->params.nports; + u32 seop[MAX_NPORTS]; + + if (adapter->open_device_map & PORT_MASK) { + int i; + + if (t1_espi_get_mon_t204(adapter, &(seop[0]), 0) < 0) + return; + + for (i = 0; i < nports; i++) { + struct sk_buff *skb = sge->espibug_skb[i]; + + if (!netif_running(adapter->port[i].dev) || + netif_queue_stopped(adapter->port[i].dev) || + !seop[i] || ((seop[i] & 0xfff) != 0) || !skb) + continue; + + if (!skb->cb[0]) { + skb_copy_to_linear_data_offset(skb, + sizeof(struct cpl_tx_pkt), + ch_mac_addr, + ETH_ALEN); + skb_copy_to_linear_data_offset(skb, + skb->len - 10, + ch_mac_addr, + ETH_ALEN); + skb->cb[0] = 0xff; + } + + /* bump the reference count to avoid freeing of + * the skb once the DMA has completed. + */ + skb = skb_get(skb); + t1_sge_tx(skb, adapter, 0, adapter->port[i].dev); + } + } + mod_timer(&sge->espibug_timer, jiffies + sge->espibug_timeout); +} + +static void espibug_workaround(unsigned long data) +{ + struct adapter *adapter = (struct adapter *)data; + struct sge *sge = adapter->sge; + + if (netif_running(adapter->port[0].dev)) { + struct sk_buff *skb = sge->espibug_skb[0]; + u32 seop = t1_espi_get_mon(adapter, 0x930, 0); + + if ((seop & 0xfff0fff) == 0xfff && skb) { + if (!skb->cb[0]) { + skb_copy_to_linear_data_offset(skb, + sizeof(struct cpl_tx_pkt), + ch_mac_addr, + ETH_ALEN); + skb_copy_to_linear_data_offset(skb, + skb->len - 10, + ch_mac_addr, + ETH_ALEN); + skb->cb[0] = 0xff; + } + + /* bump the reference count to avoid freeing of the + * skb once the DMA has completed. + */ + skb = skb_get(skb); + t1_sge_tx(skb, adapter, 0, adapter->port[0].dev); + } + } + mod_timer(&sge->espibug_timer, jiffies + sge->espibug_timeout); +} + +/* + * Creates a t1_sge structure and returns suggested resource parameters. + */ +struct sge * __devinit t1_sge_create(struct adapter *adapter, + struct sge_params *p) +{ + struct sge *sge = kzalloc(sizeof(*sge), GFP_KERNEL); + int i; + + if (!sge) + return NULL; + + sge->adapter = adapter; + sge->netdev = adapter->port[0].dev; + sge->rx_pkt_pad = t1_is_T1B(adapter) ? 0 : 2; + sge->jumbo_fl = t1_is_T1B(adapter) ? 1 : 0; + + for_each_port(adapter, i) { + sge->port_stats[i] = alloc_percpu(struct sge_port_stats); + if (!sge->port_stats[i]) + goto nomem_port; + } + + init_timer(&sge->tx_reclaim_timer); + sge->tx_reclaim_timer.data = (unsigned long)sge; + sge->tx_reclaim_timer.function = sge_tx_reclaim_cb; + + if (is_T2(sge->adapter)) { + init_timer(&sge->espibug_timer); + + if (adapter->params.nports > 1) { + tx_sched_init(sge); + sge->espibug_timer.function = espibug_workaround_t204; + } else + sge->espibug_timer.function = espibug_workaround; + sge->espibug_timer.data = (unsigned long)sge->adapter; + + sge->espibug_timeout = 1; + /* for T204, every 10ms */ + if (adapter->params.nports > 1) + sge->espibug_timeout = HZ/100; + } + + + p->cmdQ_size[0] = SGE_CMDQ0_E_N; + p->cmdQ_size[1] = SGE_CMDQ1_E_N; + p->freelQ_size[!sge->jumbo_fl] = SGE_FREEL_SIZE; + p->freelQ_size[sge->jumbo_fl] = SGE_JUMBO_FREEL_SIZE; + if (sge->tx_sched) { + if (board_info(sge->adapter)->board == CHBT_BOARD_CHT204) + p->rx_coalesce_usecs = 15; + else + p->rx_coalesce_usecs = 50; + } else + p->rx_coalesce_usecs = 50; + + p->coalesce_enable = 0; + p->sample_interval_usecs = 0; + + return sge; +nomem_port: + while (i >= 0) { + free_percpu(sge->port_stats[i]); + --i; + } + kfree(sge); + return NULL; + +} diff --git a/drivers/net/ethernet/chelsio/cxgb/sge.h b/drivers/net/ethernet/chelsio/cxgb/sge.h new file mode 100644 index 000000000000..e03980bcdd65 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb/sge.h @@ -0,0 +1,94 @@ +/***************************************************************************** + * * + * File: sge.h * + * $Revision: 1.11 $ * + * $Date: 2005/06/21 22:10:55 $ * + * Description: * + * part of the Chelsio 10Gb Ethernet Driver. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License, version 2, as * + * published by the Free Software Foundation. * + * * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * + * * + * http://www.chelsio.com * + * * + * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * + * All rights reserved. * + * * + * Maintainers: maintainers@chelsio.com * + * * + * Authors: Dimitrios Michailidis * + * Tina Yang * + * Felix Marti * + * Scott Bardone * + * Kurt Ottaway * + * Frank DiMambro * + * * + * History: * + * * + ****************************************************************************/ + +#ifndef _CXGB_SGE_H_ +#define _CXGB_SGE_H_ + +#include +#include +#include + +struct sge_intr_counts { + unsigned int rx_drops; /* # of packets dropped due to no mem */ + unsigned int pure_rsps; /* # of non-payload responses */ + unsigned int unhandled_irqs; /* # of unhandled interrupts */ + unsigned int respQ_empty; /* # times respQ empty */ + unsigned int respQ_overflow; /* # respQ overflow (fatal) */ + unsigned int freelistQ_empty; /* # times freelist empty */ + unsigned int pkt_too_big; /* packet too large (fatal) */ + unsigned int pkt_mismatch; + unsigned int cmdQ_full[3]; /* not HW IRQ, host cmdQ[] full */ + unsigned int cmdQ_restarted[3];/* # of times cmdQ X was restarted */ +}; + +struct sge_port_stats { + u64 rx_cso_good; /* # of successful RX csum offloads */ + u64 tx_cso; /* # of TX checksum offloads */ + u64 tx_tso; /* # of TSO requests */ + u64 vlan_xtract; /* # of VLAN tag extractions */ + u64 vlan_insert; /* # of VLAN tag insertions */ + u64 tx_need_hdrroom; /* # of TX skbs in need of more header room */ +}; + +struct sk_buff; +struct net_device; +struct adapter; +struct sge_params; +struct sge; + +struct sge *t1_sge_create(struct adapter *, struct sge_params *); +int t1_sge_configure(struct sge *, struct sge_params *); +int t1_sge_set_coalesce_params(struct sge *, struct sge_params *); +void t1_sge_destroy(struct sge *); +irqreturn_t t1_interrupt(int irq, void *cookie); +int t1_poll(struct napi_struct *, int); + +netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev); +void t1_vlan_mode(struct adapter *adapter, u32 features); +void t1_sge_start(struct sge *); +void t1_sge_stop(struct sge *); +int t1_sge_intr_error_handler(struct sge *); +void t1_sge_intr_enable(struct sge *); +void t1_sge_intr_disable(struct sge *); +void t1_sge_intr_clear(struct sge *); +const struct sge_intr_counts *t1_sge_get_intr_counts(const struct sge *sge); +void t1_sge_get_port_stats(const struct sge *sge, int port, struct sge_port_stats *); +unsigned int t1_sched_update_parms(struct sge *, unsigned int, unsigned int, + unsigned int); + +#endif /* _CXGB_SGE_H_ */ diff --git a/drivers/net/ethernet/chelsio/cxgb/subr.c b/drivers/net/ethernet/chelsio/cxgb/subr.c new file mode 100644 index 000000000000..8a43c7e19701 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb/subr.c @@ -0,0 +1,1130 @@ +/***************************************************************************** + * * + * File: subr.c * + * $Revision: 1.27 $ * + * $Date: 2005/06/22 01:08:36 $ * + * Description: * + * Various subroutines (intr,pio,etc.) used by Chelsio 10G Ethernet driver. * + * part of the Chelsio 10Gb Ethernet Driver. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License, version 2, as * + * published by the Free Software Foundation. * + * * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * + * * + * http://www.chelsio.com * + * * + * Copyright (c) 2003 - 2005 Chelsio Communications, Inc. * + * All rights reserved. * + * * + * Maintainers: maintainers@chelsio.com * + * * + * Authors: Dimitrios Michailidis * + * Tina Yang * + * Felix Marti * + * Scott Bardone * + * Kurt Ottaway * + * Frank DiMambro * + * * + * History: * + * * + ****************************************************************************/ + +#include "common.h" +#include "elmer0.h" +#include "regs.h" +#include "gmac.h" +#include "cphy.h" +#include "sge.h" +#include "tp.h" +#include "espi.h" + +/** + * t1_wait_op_done - wait until an operation is completed + * @adapter: the adapter performing the operation + * @reg: the register to check for completion + * @mask: a single-bit field within @reg that indicates completion + * @polarity: the value of the field when the operation is completed + * @attempts: number of check iterations + * @delay: delay in usecs between iterations + * + * Wait until an operation is completed by checking a bit in a register + * up to @attempts times. Returns %0 if the operation completes and %1 + * otherwise. + */ +static int t1_wait_op_done(adapter_t *adapter, int reg, u32 mask, int polarity, + int attempts, int delay) +{ + while (1) { + u32 val = readl(adapter->regs + reg) & mask; + + if (!!val == polarity) + return 0; + if (--attempts == 0) + return 1; + if (delay) + udelay(delay); + } +} + +#define TPI_ATTEMPTS 50 + +/* + * Write a register over the TPI interface (unlocked and locked versions). + */ +int __t1_tpi_write(adapter_t *adapter, u32 addr, u32 value) +{ + int tpi_busy; + + writel(addr, adapter->regs + A_TPI_ADDR); + writel(value, adapter->regs + A_TPI_WR_DATA); + writel(F_TPIWR, adapter->regs + A_TPI_CSR); + + tpi_busy = t1_wait_op_done(adapter, A_TPI_CSR, F_TPIRDY, 1, + TPI_ATTEMPTS, 3); + if (tpi_busy) + pr_alert("%s: TPI write to 0x%x failed\n", + adapter->name, addr); + return tpi_busy; +} + +int t1_tpi_write(adapter_t *adapter, u32 addr, u32 value) +{ + int ret; + + spin_lock(&adapter->tpi_lock); + ret = __t1_tpi_write(adapter, addr, value); + spin_unlock(&adapter->tpi_lock); + return ret; +} + +/* + * Read a register over the TPI interface (unlocked and locked versions). + */ +int __t1_tpi_read(adapter_t *adapter, u32 addr, u32 *valp) +{ + int tpi_busy; + + writel(addr, adapter->regs + A_TPI_ADDR); + writel(0, adapter->regs + A_TPI_CSR); + + tpi_busy = t1_wait_op_done(adapter, A_TPI_CSR, F_TPIRDY, 1, + TPI_ATTEMPTS, 3); + if (tpi_busy) + pr_alert("%s: TPI read from 0x%x failed\n", + adapter->name, addr); + else + *valp = readl(adapter->regs + A_TPI_RD_DATA); + return tpi_busy; +} + +int t1_tpi_read(adapter_t *adapter, u32 addr, u32 *valp) +{ + int ret; + + spin_lock(&adapter->tpi_lock); + ret = __t1_tpi_read(adapter, addr, valp); + spin_unlock(&adapter->tpi_lock); + return ret; +} + +/* + * Set a TPI parameter. + */ +static void t1_tpi_par(adapter_t *adapter, u32 value) +{ + writel(V_TPIPAR(value), adapter->regs + A_TPI_PAR); +} + +/* + * Called when a port's link settings change to propagate the new values to the + * associated PHY and MAC. After performing the common tasks it invokes an + * OS-specific handler. + */ +void t1_link_changed(adapter_t *adapter, int port_id) +{ + int link_ok, speed, duplex, fc; + struct cphy *phy = adapter->port[port_id].phy; + struct link_config *lc = &adapter->port[port_id].link_config; + + phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc); + + lc->speed = speed < 0 ? SPEED_INVALID : speed; + lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex; + if (!(lc->requested_fc & PAUSE_AUTONEG)) + fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); + + if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE) { + /* Set MAC speed, duplex, and flow control to match PHY. */ + struct cmac *mac = adapter->port[port_id].mac; + + mac->ops->set_speed_duplex_fc(mac, speed, duplex, fc); + lc->fc = (unsigned char)fc; + } + t1_link_negotiated(adapter, port_id, link_ok, speed, duplex, fc); +} + +static int t1_pci_intr_handler(adapter_t *adapter) +{ + u32 pcix_cause; + + pci_read_config_dword(adapter->pdev, A_PCICFG_INTR_CAUSE, &pcix_cause); + + if (pcix_cause) { + pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_CAUSE, + pcix_cause); + t1_fatal_err(adapter); /* PCI errors are fatal */ + } + return 0; +} + +#ifdef CONFIG_CHELSIO_T1_1G +#include "fpga_defs.h" + +/* + * PHY interrupt handler for FPGA boards. + */ +static int fpga_phy_intr_handler(adapter_t *adapter) +{ + int p; + u32 cause = readl(adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_CAUSE); + + for_each_port(adapter, p) + if (cause & (1 << p)) { + struct cphy *phy = adapter->port[p].phy; + int phy_cause = phy->ops->interrupt_handler(phy); + + if (phy_cause & cphy_cause_link_change) + t1_link_changed(adapter, p); + } + writel(cause, adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_CAUSE); + return 0; +} + +/* + * Slow path interrupt handler for FPGAs. + */ +static int fpga_slow_intr(adapter_t *adapter) +{ + u32 cause = readl(adapter->regs + A_PL_CAUSE); + + cause &= ~F_PL_INTR_SGE_DATA; + if (cause & F_PL_INTR_SGE_ERR) + t1_sge_intr_error_handler(adapter->sge); + + if (cause & FPGA_PCIX_INTERRUPT_GMAC) + fpga_phy_intr_handler(adapter); + + if (cause & FPGA_PCIX_INTERRUPT_TP) { + /* + * FPGA doesn't support MC4 interrupts and it requires + * this odd layer of indirection for MC5. + */ + u32 tp_cause = readl(adapter->regs + FPGA_TP_ADDR_INTERRUPT_CAUSE); + + /* Clear TP interrupt */ + writel(tp_cause, adapter->regs + FPGA_TP_ADDR_INTERRUPT_CAUSE); + } + if (cause & FPGA_PCIX_INTERRUPT_PCIX) + t1_pci_intr_handler(adapter); + + /* Clear the interrupts just processed. */ + if (cause) + writel(cause, adapter->regs + A_PL_CAUSE); + + return cause != 0; +} +#endif + +/* + * Wait until Elmer's MI1 interface is ready for new operations. + */ +static int mi1_wait_until_ready(adapter_t *adapter, int mi1_reg) +{ + int attempts = 100, busy; + + do { + u32 val; + + __t1_tpi_read(adapter, mi1_reg, &val); + busy = val & F_MI1_OP_BUSY; + if (busy) + udelay(10); + } while (busy && --attempts); + if (busy) + pr_alert("%s: MDIO operation timed out\n", adapter->name); + return busy; +} + +/* + * MI1 MDIO initialization. + */ +static void mi1_mdio_init(adapter_t *adapter, const struct board_info *bi) +{ + u32 clkdiv = bi->clock_elmer0 / (2 * bi->mdio_mdc) - 1; + u32 val = F_MI1_PREAMBLE_ENABLE | V_MI1_MDI_INVERT(bi->mdio_mdiinv) | + V_MI1_MDI_ENABLE(bi->mdio_mdien) | V_MI1_CLK_DIV(clkdiv); + + if (!(bi->caps & SUPPORTED_10000baseT_Full)) + val |= V_MI1_SOF(1); + t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_CFG, val); +} + +#if defined(CONFIG_CHELSIO_T1_1G) +/* + * Elmer MI1 MDIO read/write operations. + */ +static int mi1_mdio_read(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr) +{ + struct adapter *adapter = dev->ml_priv; + u32 addr = V_MI1_REG_ADDR(reg_addr) | V_MI1_PHY_ADDR(phy_addr); + unsigned int val; + + spin_lock(&adapter->tpi_lock); + __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr); + __t1_tpi_write(adapter, + A_ELMER0_PORT0_MI1_OP, MI1_OP_DIRECT_READ); + mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP); + __t1_tpi_read(adapter, A_ELMER0_PORT0_MI1_DATA, &val); + spin_unlock(&adapter->tpi_lock); + return val; +} + +static int mi1_mdio_write(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr, u16 val) +{ + struct adapter *adapter = dev->ml_priv; + u32 addr = V_MI1_REG_ADDR(reg_addr) | V_MI1_PHY_ADDR(phy_addr); + + spin_lock(&adapter->tpi_lock); + __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr); + __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_DATA, val); + __t1_tpi_write(adapter, + A_ELMER0_PORT0_MI1_OP, MI1_OP_DIRECT_WRITE); + mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP); + spin_unlock(&adapter->tpi_lock); + return 0; +} + +static const struct mdio_ops mi1_mdio_ops = { + .init = mi1_mdio_init, + .read = mi1_mdio_read, + .write = mi1_mdio_write, + .mode_support = MDIO_SUPPORTS_C22 +}; + +#endif + +static int mi1_mdio_ext_read(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr) +{ + struct adapter *adapter = dev->ml_priv; + u32 addr = V_MI1_REG_ADDR(mmd_addr) | V_MI1_PHY_ADDR(phy_addr); + unsigned int val; + + spin_lock(&adapter->tpi_lock); + + /* Write the address we want. */ + __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr); + __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_DATA, reg_addr); + __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_OP, + MI1_OP_INDIRECT_ADDRESS); + mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP); + + /* Write the operation we want. */ + __t1_tpi_write(adapter, + A_ELMER0_PORT0_MI1_OP, MI1_OP_INDIRECT_READ); + mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP); + + /* Read the data. */ + __t1_tpi_read(adapter, A_ELMER0_PORT0_MI1_DATA, &val); + spin_unlock(&adapter->tpi_lock); + return val; +} + +static int mi1_mdio_ext_write(struct net_device *dev, int phy_addr, + int mmd_addr, u16 reg_addr, u16 val) +{ + struct adapter *adapter = dev->ml_priv; + u32 addr = V_MI1_REG_ADDR(mmd_addr) | V_MI1_PHY_ADDR(phy_addr); + + spin_lock(&adapter->tpi_lock); + + /* Write the address we want. */ + __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_ADDR, addr); + __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_DATA, reg_addr); + __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_OP, + MI1_OP_INDIRECT_ADDRESS); + mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP); + + /* Write the data. */ + __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_DATA, val); + __t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_OP, MI1_OP_INDIRECT_WRITE); + mi1_wait_until_ready(adapter, A_ELMER0_PORT0_MI1_OP); + spin_unlock(&adapter->tpi_lock); + return 0; +} + +static const struct mdio_ops mi1_mdio_ext_ops = { + .init = mi1_mdio_init, + .read = mi1_mdio_ext_read, + .write = mi1_mdio_ext_write, + .mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22 +}; + +enum { + CH_BRD_T110_1CU, + CH_BRD_N110_1F, + CH_BRD_N210_1F, + CH_BRD_T210_1F, + CH_BRD_T210_1CU, + CH_BRD_N204_4CU, +}; + +static const struct board_info t1_board[] = { + { + .board = CHBT_BOARD_CHT110, + .port_number = 1, + .caps = SUPPORTED_10000baseT_Full, + .chip_term = CHBT_TERM_T1, + .chip_mac = CHBT_MAC_PM3393, + .chip_phy = CHBT_PHY_MY3126, + .clock_core = 125000000, + .clock_mc3 = 150000000, + .clock_mc4 = 125000000, + .espi_nports = 1, + .clock_elmer0 = 44, + .mdio_mdien = 1, + .mdio_mdiinv = 1, + .mdio_mdc = 1, + .mdio_phybaseaddr = 1, + .gmac = &t1_pm3393_ops, + .gphy = &t1_my3126_ops, + .mdio_ops = &mi1_mdio_ext_ops, + .desc = "Chelsio T110 1x10GBase-CX4 TOE", + }, + + { + .board = CHBT_BOARD_N110, + .port_number = 1, + .caps = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE, + .chip_term = CHBT_TERM_T1, + .chip_mac = CHBT_MAC_PM3393, + .chip_phy = CHBT_PHY_88X2010, + .clock_core = 125000000, + .espi_nports = 1, + .clock_elmer0 = 44, + .mdio_mdien = 0, + .mdio_mdiinv = 0, + .mdio_mdc = 1, + .mdio_phybaseaddr = 0, + .gmac = &t1_pm3393_ops, + .gphy = &t1_mv88x201x_ops, + .mdio_ops = &mi1_mdio_ext_ops, + .desc = "Chelsio N110 1x10GBaseX NIC", + }, + + { + .board = CHBT_BOARD_N210, + .port_number = 1, + .caps = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE, + .chip_term = CHBT_TERM_T2, + .chip_mac = CHBT_MAC_PM3393, + .chip_phy = CHBT_PHY_88X2010, + .clock_core = 125000000, + .espi_nports = 1, + .clock_elmer0 = 44, + .mdio_mdien = 0, + .mdio_mdiinv = 0, + .mdio_mdc = 1, + .mdio_phybaseaddr = 0, + .gmac = &t1_pm3393_ops, + .gphy = &t1_mv88x201x_ops, + .mdio_ops = &mi1_mdio_ext_ops, + .desc = "Chelsio N210 1x10GBaseX NIC", + }, + + { + .board = CHBT_BOARD_CHT210, + .port_number = 1, + .caps = SUPPORTED_10000baseT_Full, + .chip_term = CHBT_TERM_T2, + .chip_mac = CHBT_MAC_PM3393, + .chip_phy = CHBT_PHY_88X2010, + .clock_core = 125000000, + .clock_mc3 = 133000000, + .clock_mc4 = 125000000, + .espi_nports = 1, + .clock_elmer0 = 44, + .mdio_mdien = 0, + .mdio_mdiinv = 0, + .mdio_mdc = 1, + .mdio_phybaseaddr = 0, + .gmac = &t1_pm3393_ops, + .gphy = &t1_mv88x201x_ops, + .mdio_ops = &mi1_mdio_ext_ops, + .desc = "Chelsio T210 1x10GBaseX TOE", + }, + + { + .board = CHBT_BOARD_CHT210, + .port_number = 1, + .caps = SUPPORTED_10000baseT_Full, + .chip_term = CHBT_TERM_T2, + .chip_mac = CHBT_MAC_PM3393, + .chip_phy = CHBT_PHY_MY3126, + .clock_core = 125000000, + .clock_mc3 = 133000000, + .clock_mc4 = 125000000, + .espi_nports = 1, + .clock_elmer0 = 44, + .mdio_mdien = 1, + .mdio_mdiinv = 1, + .mdio_mdc = 1, + .mdio_phybaseaddr = 1, + .gmac = &t1_pm3393_ops, + .gphy = &t1_my3126_ops, + .mdio_ops = &mi1_mdio_ext_ops, + .desc = "Chelsio T210 1x10GBase-CX4 TOE", + }, + +#ifdef CONFIG_CHELSIO_T1_1G + { + .board = CHBT_BOARD_CHN204, + .port_number = 4, + .caps = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full + | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full + | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | + SUPPORTED_PAUSE | SUPPORTED_TP, + .chip_term = CHBT_TERM_T2, + .chip_mac = CHBT_MAC_VSC7321, + .chip_phy = CHBT_PHY_88E1111, + .clock_core = 100000000, + .espi_nports = 4, + .clock_elmer0 = 44, + .mdio_mdien = 0, + .mdio_mdiinv = 0, + .mdio_mdc = 0, + .mdio_phybaseaddr = 4, + .gmac = &t1_vsc7326_ops, + .gphy = &t1_mv88e1xxx_ops, + .mdio_ops = &mi1_mdio_ops, + .desc = "Chelsio N204 4x100/1000BaseT NIC", + }, +#endif + +}; + +DEFINE_PCI_DEVICE_TABLE(t1_pci_tbl) = { + CH_DEVICE(8, 0, CH_BRD_T110_1CU), + CH_DEVICE(8, 1, CH_BRD_T110_1CU), + CH_DEVICE(7, 0, CH_BRD_N110_1F), + CH_DEVICE(10, 1, CH_BRD_N210_1F), + CH_DEVICE(11, 1, CH_BRD_T210_1F), + CH_DEVICE(14, 1, CH_BRD_T210_1CU), + CH_DEVICE(16, 1, CH_BRD_N204_4CU), + { 0 } +}; + +MODULE_DEVICE_TABLE(pci, t1_pci_tbl); + +/* + * Return the board_info structure with a given index. Out-of-range indices + * return NULL. + */ +const struct board_info *t1_get_board_info(unsigned int board_id) +{ + return board_id < ARRAY_SIZE(t1_board) ? &t1_board[board_id] : NULL; +} + +struct chelsio_vpd_t { + u32 format_version; + u8 serial_number[16]; + u8 mac_base_address[6]; + u8 pad[2]; /* make multiple-of-4 size requirement explicit */ +}; + +#define EEPROMSIZE (8 * 1024) +#define EEPROM_MAX_POLL 4 + +/* + * Read SEEPROM. A zero is written to the flag register when the address is + * written to the Control register. The hardware device will set the flag to a + * one when 4B have been transferred to the Data register. + */ +int t1_seeprom_read(adapter_t *adapter, u32 addr, __le32 *data) +{ + int i = EEPROM_MAX_POLL; + u16 val; + u32 v; + + if (addr >= EEPROMSIZE || (addr & 3)) + return -EINVAL; + + pci_write_config_word(adapter->pdev, A_PCICFG_VPD_ADDR, (u16)addr); + do { + udelay(50); + pci_read_config_word(adapter->pdev, A_PCICFG_VPD_ADDR, &val); + } while (!(val & F_VPD_OP_FLAG) && --i); + + if (!(val & F_VPD_OP_FLAG)) { + pr_err("%s: reading EEPROM address 0x%x failed\n", + adapter->name, addr); + return -EIO; + } + pci_read_config_dword(adapter->pdev, A_PCICFG_VPD_DATA, &v); + *data = cpu_to_le32(v); + return 0; +} + +static int t1_eeprom_vpd_get(adapter_t *adapter, struct chelsio_vpd_t *vpd) +{ + int addr, ret = 0; + + for (addr = 0; !ret && addr < sizeof(*vpd); addr += sizeof(u32)) + ret = t1_seeprom_read(adapter, addr, + (__le32 *)((u8 *)vpd + addr)); + + return ret; +} + +/* + * Read a port's MAC address from the VPD ROM. + */ +static int vpd_macaddress_get(adapter_t *adapter, int index, u8 mac_addr[]) +{ + struct chelsio_vpd_t vpd; + + if (t1_eeprom_vpd_get(adapter, &vpd)) + return 1; + memcpy(mac_addr, vpd.mac_base_address, 5); + mac_addr[5] = vpd.mac_base_address[5] + index; + return 0; +} + +/* + * Set up the MAC/PHY according to the requested link settings. + * + * If the PHY can auto-negotiate first decide what to advertise, then + * enable/disable auto-negotiation as desired and reset. + * + * If the PHY does not auto-negotiate we just reset it. + * + * If auto-negotiation is off set the MAC to the proper speed/duplex/FC, + * otherwise do it later based on the outcome of auto-negotiation. + */ +int t1_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc) +{ + unsigned int fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); + + if (lc->supported & SUPPORTED_Autoneg) { + lc->advertising &= ~(ADVERTISED_ASYM_PAUSE | ADVERTISED_PAUSE); + if (fc) { + if (fc == ((PAUSE_RX | PAUSE_TX) & + (mac->adapter->params.nports < 2))) + lc->advertising |= ADVERTISED_PAUSE; + else { + lc->advertising |= ADVERTISED_ASYM_PAUSE; + if (fc == PAUSE_RX) + lc->advertising |= ADVERTISED_PAUSE; + } + } + phy->ops->advertise(phy, lc->advertising); + + if (lc->autoneg == AUTONEG_DISABLE) { + lc->speed = lc->requested_speed; + lc->duplex = lc->requested_duplex; + lc->fc = (unsigned char)fc; + mac->ops->set_speed_duplex_fc(mac, lc->speed, + lc->duplex, fc); + /* Also disables autoneg */ + phy->state = PHY_AUTONEG_RDY; + phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex); + phy->ops->reset(phy, 0); + } else { + phy->state = PHY_AUTONEG_EN; + phy->ops->autoneg_enable(phy); /* also resets PHY */ + } + } else { + phy->state = PHY_AUTONEG_RDY; + mac->ops->set_speed_duplex_fc(mac, -1, -1, fc); + lc->fc = (unsigned char)fc; + phy->ops->reset(phy, 0); + } + return 0; +} + +/* + * External interrupt handler for boards using elmer0. + */ +int t1_elmer0_ext_intr_handler(adapter_t *adapter) +{ + struct cphy *phy; + int phy_cause; + u32 cause; + + t1_tpi_read(adapter, A_ELMER0_INT_CAUSE, &cause); + + switch (board_info(adapter)->board) { +#ifdef CONFIG_CHELSIO_T1_1G + case CHBT_BOARD_CHT204: + case CHBT_BOARD_CHT204E: + case CHBT_BOARD_CHN204: + case CHBT_BOARD_CHT204V: { + int i, port_bit; + for_each_port(adapter, i) { + port_bit = i + 1; + if (!(cause & (1 << port_bit))) + continue; + + phy = adapter->port[i].phy; + phy_cause = phy->ops->interrupt_handler(phy); + if (phy_cause & cphy_cause_link_change) + t1_link_changed(adapter, i); + } + break; + } + case CHBT_BOARD_CHT101: + if (cause & ELMER0_GP_BIT1) { /* Marvell 88E1111 interrupt */ + phy = adapter->port[0].phy; + phy_cause = phy->ops->interrupt_handler(phy); + if (phy_cause & cphy_cause_link_change) + t1_link_changed(adapter, 0); + } + break; + case CHBT_BOARD_7500: { + int p; + /* + * Elmer0's interrupt cause isn't useful here because there is + * only one bit that can be set for all 4 ports. This means + * we are forced to check every PHY's interrupt status + * register to see who initiated the interrupt. + */ + for_each_port(adapter, p) { + phy = adapter->port[p].phy; + phy_cause = phy->ops->interrupt_handler(phy); + if (phy_cause & cphy_cause_link_change) + t1_link_changed(adapter, p); + } + break; + } +#endif + case CHBT_BOARD_CHT210: + case CHBT_BOARD_N210: + case CHBT_BOARD_N110: + if (cause & ELMER0_GP_BIT6) { /* Marvell 88x2010 interrupt */ + phy = adapter->port[0].phy; + phy_cause = phy->ops->interrupt_handler(phy); + if (phy_cause & cphy_cause_link_change) + t1_link_changed(adapter, 0); + } + break; + case CHBT_BOARD_8000: + case CHBT_BOARD_CHT110: + if (netif_msg_intr(adapter)) + dev_dbg(&adapter->pdev->dev, + "External interrupt cause 0x%x\n", cause); + if (cause & ELMER0_GP_BIT1) { /* PMC3393 INTB */ + struct cmac *mac = adapter->port[0].mac; + + mac->ops->interrupt_handler(mac); + } + if (cause & ELMER0_GP_BIT5) { /* XPAK MOD_DETECT */ + u32 mod_detect; + + t1_tpi_read(adapter, + A_ELMER0_GPI_STAT, &mod_detect); + if (netif_msg_link(adapter)) + dev_info(&adapter->pdev->dev, "XPAK %s\n", + mod_detect ? "removed" : "inserted"); + } + break; + } + t1_tpi_write(adapter, A_ELMER0_INT_CAUSE, cause); + return 0; +} + +/* Enables all interrupts. */ +void t1_interrupts_enable(adapter_t *adapter) +{ + unsigned int i; + + adapter->slow_intr_mask = F_PL_INTR_SGE_ERR | F_PL_INTR_TP; + + t1_sge_intr_enable(adapter->sge); + t1_tp_intr_enable(adapter->tp); + if (adapter->espi) { + adapter->slow_intr_mask |= F_PL_INTR_ESPI; + t1_espi_intr_enable(adapter->espi); + } + + /* Enable MAC/PHY interrupts for each port. */ + for_each_port(adapter, i) { + adapter->port[i].mac->ops->interrupt_enable(adapter->port[i].mac); + adapter->port[i].phy->ops->interrupt_enable(adapter->port[i].phy); + } + + /* Enable PCIX & external chip interrupts on ASIC boards. */ + if (t1_is_asic(adapter)) { + u32 pl_intr = readl(adapter->regs + A_PL_ENABLE); + + /* PCI-X interrupts */ + pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_ENABLE, + 0xffffffff); + + adapter->slow_intr_mask |= F_PL_INTR_EXT | F_PL_INTR_PCIX; + pl_intr |= F_PL_INTR_EXT | F_PL_INTR_PCIX; + writel(pl_intr, adapter->regs + A_PL_ENABLE); + } +} + +/* Disables all interrupts. */ +void t1_interrupts_disable(adapter_t* adapter) +{ + unsigned int i; + + t1_sge_intr_disable(adapter->sge); + t1_tp_intr_disable(adapter->tp); + if (adapter->espi) + t1_espi_intr_disable(adapter->espi); + + /* Disable MAC/PHY interrupts for each port. */ + for_each_port(adapter, i) { + adapter->port[i].mac->ops->interrupt_disable(adapter->port[i].mac); + adapter->port[i].phy->ops->interrupt_disable(adapter->port[i].phy); + } + + /* Disable PCIX & external chip interrupts. */ + if (t1_is_asic(adapter)) + writel(0, adapter->regs + A_PL_ENABLE); + + /* PCI-X interrupts */ + pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_ENABLE, 0); + + adapter->slow_intr_mask = 0; +} + +/* Clears all interrupts */ +void t1_interrupts_clear(adapter_t* adapter) +{ + unsigned int i; + + t1_sge_intr_clear(adapter->sge); + t1_tp_intr_clear(adapter->tp); + if (adapter->espi) + t1_espi_intr_clear(adapter->espi); + + /* Clear MAC/PHY interrupts for each port. */ + for_each_port(adapter, i) { + adapter->port[i].mac->ops->interrupt_clear(adapter->port[i].mac); + adapter->port[i].phy->ops->interrupt_clear(adapter->port[i].phy); + } + + /* Enable interrupts for external devices. */ + if (t1_is_asic(adapter)) { + u32 pl_intr = readl(adapter->regs + A_PL_CAUSE); + + writel(pl_intr | F_PL_INTR_EXT | F_PL_INTR_PCIX, + adapter->regs + A_PL_CAUSE); + } + + /* PCI-X interrupts */ + pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_CAUSE, 0xffffffff); +} + +/* + * Slow path interrupt handler for ASICs. + */ +static int asic_slow_intr(adapter_t *adapter) +{ + u32 cause = readl(adapter->regs + A_PL_CAUSE); + + cause &= adapter->slow_intr_mask; + if (!cause) + return 0; + if (cause & F_PL_INTR_SGE_ERR) + t1_sge_intr_error_handler(adapter->sge); + if (cause & F_PL_INTR_TP) + t1_tp_intr_handler(adapter->tp); + if (cause & F_PL_INTR_ESPI) + t1_espi_intr_handler(adapter->espi); + if (cause & F_PL_INTR_PCIX) + t1_pci_intr_handler(adapter); + if (cause & F_PL_INTR_EXT) + t1_elmer0_ext_intr(adapter); + + /* Clear the interrupts just processed. */ + writel(cause, adapter->regs + A_PL_CAUSE); + readl(adapter->regs + A_PL_CAUSE); /* flush writes */ + return 1; +} + +int t1_slow_intr_handler(adapter_t *adapter) +{ +#ifdef CONFIG_CHELSIO_T1_1G + if (!t1_is_asic(adapter)) + return fpga_slow_intr(adapter); +#endif + return asic_slow_intr(adapter); +} + +/* Power sequencing is a work-around for Intel's XPAKs. */ +static void power_sequence_xpak(adapter_t* adapter) +{ + u32 mod_detect; + u32 gpo; + + /* Check for XPAK */ + t1_tpi_read(adapter, A_ELMER0_GPI_STAT, &mod_detect); + if (!(ELMER0_GP_BIT5 & mod_detect)) { + /* XPAK is present */ + t1_tpi_read(adapter, A_ELMER0_GPO, &gpo); + gpo |= ELMER0_GP_BIT18; + t1_tpi_write(adapter, A_ELMER0_GPO, gpo); + } +} + +int __devinit t1_get_board_rev(adapter_t *adapter, const struct board_info *bi, + struct adapter_params *p) +{ + p->chip_version = bi->chip_term; + p->is_asic = (p->chip_version != CHBT_TERM_FPGA); + if (p->chip_version == CHBT_TERM_T1 || + p->chip_version == CHBT_TERM_T2 || + p->chip_version == CHBT_TERM_FPGA) { + u32 val = readl(adapter->regs + A_TP_PC_CONFIG); + + val = G_TP_PC_REV(val); + if (val == 2) + p->chip_revision = TERM_T1B; + else if (val == 3) + p->chip_revision = TERM_T2; + else + return -1; + } else + return -1; + return 0; +} + +/* + * Enable board components other than the Chelsio chip, such as external MAC + * and PHY. + */ +static int board_init(adapter_t *adapter, const struct board_info *bi) +{ + switch (bi->board) { + case CHBT_BOARD_8000: + case CHBT_BOARD_N110: + case CHBT_BOARD_N210: + case CHBT_BOARD_CHT210: + t1_tpi_par(adapter, 0xf); + t1_tpi_write(adapter, A_ELMER0_GPO, 0x800); + break; + case CHBT_BOARD_CHT110: + t1_tpi_par(adapter, 0xf); + t1_tpi_write(adapter, A_ELMER0_GPO, 0x1800); + + /* TBD XXX Might not need. This fixes a problem + * described in the Intel SR XPAK errata. + */ + power_sequence_xpak(adapter); + break; +#ifdef CONFIG_CHELSIO_T1_1G + case CHBT_BOARD_CHT204E: + /* add config space write here */ + case CHBT_BOARD_CHT204: + case CHBT_BOARD_CHT204V: + case CHBT_BOARD_CHN204: + t1_tpi_par(adapter, 0xf); + t1_tpi_write(adapter, A_ELMER0_GPO, 0x804); + break; + case CHBT_BOARD_CHT101: + case CHBT_BOARD_7500: + t1_tpi_par(adapter, 0xf); + t1_tpi_write(adapter, A_ELMER0_GPO, 0x1804); + break; +#endif + } + return 0; +} + +/* + * Initialize and configure the Terminator HW modules. Note that external + * MAC and PHYs are initialized separately. + */ +int t1_init_hw_modules(adapter_t *adapter) +{ + int err = -EIO; + const struct board_info *bi = board_info(adapter); + + if (!bi->clock_mc4) { + u32 val = readl(adapter->regs + A_MC4_CFG); + + writel(val | F_READY | F_MC4_SLOW, adapter->regs + A_MC4_CFG); + writel(F_M_BUS_ENABLE | F_TCAM_RESET, + adapter->regs + A_MC5_CONFIG); + } + + if (adapter->espi && t1_espi_init(adapter->espi, bi->chip_mac, + bi->espi_nports)) + goto out_err; + + if (t1_tp_reset(adapter->tp, &adapter->params.tp, bi->clock_core)) + goto out_err; + + err = t1_sge_configure(adapter->sge, &adapter->params.sge); + if (err) + goto out_err; + + err = 0; +out_err: + return err; +} + +/* + * Determine a card's PCI mode. + */ +static void __devinit get_pci_mode(adapter_t *adapter, struct chelsio_pci_params *p) +{ + static const unsigned short speed_map[] = { 33, 66, 100, 133 }; + u32 pci_mode; + + pci_read_config_dword(adapter->pdev, A_PCICFG_MODE, &pci_mode); + p->speed = speed_map[G_PCI_MODE_CLK(pci_mode)]; + p->width = (pci_mode & F_PCI_MODE_64BIT) ? 64 : 32; + p->is_pcix = (pci_mode & F_PCI_MODE_PCIX) != 0; +} + +/* + * Release the structures holding the SW per-Terminator-HW-module state. + */ +void t1_free_sw_modules(adapter_t *adapter) +{ + unsigned int i; + + for_each_port(adapter, i) { + struct cmac *mac = adapter->port[i].mac; + struct cphy *phy = adapter->port[i].phy; + + if (mac) + mac->ops->destroy(mac); + if (phy) + phy->ops->destroy(phy); + } + + if (adapter->sge) + t1_sge_destroy(adapter->sge); + if (adapter->tp) + t1_tp_destroy(adapter->tp); + if (adapter->espi) + t1_espi_destroy(adapter->espi); +} + +static void __devinit init_link_config(struct link_config *lc, + const struct board_info *bi) +{ + lc->supported = bi->caps; + lc->requested_speed = lc->speed = SPEED_INVALID; + lc->requested_duplex = lc->duplex = DUPLEX_INVALID; + lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX; + if (lc->supported & SUPPORTED_Autoneg) { + lc->advertising = lc->supported; + lc->autoneg = AUTONEG_ENABLE; + lc->requested_fc |= PAUSE_AUTONEG; + } else { + lc->advertising = 0; + lc->autoneg = AUTONEG_DISABLE; + } +} + +/* + * Allocate and initialize the data structures that hold the SW state of + * the Terminator HW modules. + */ +int __devinit t1_init_sw_modules(adapter_t *adapter, + const struct board_info *bi) +{ + unsigned int i; + + adapter->params.brd_info = bi; + adapter->params.nports = bi->port_number; + adapter->params.stats_update_period = bi->gmac->stats_update_period; + + adapter->sge = t1_sge_create(adapter, &adapter->params.sge); + if (!adapter->sge) { + pr_err("%s: SGE initialization failed\n", + adapter->name); + goto error; + } + + if (bi->espi_nports && !(adapter->espi = t1_espi_create(adapter))) { + pr_err("%s: ESPI initialization failed\n", + adapter->name); + goto error; + } + + adapter->tp = t1_tp_create(adapter, &adapter->params.tp); + if (!adapter->tp) { + pr_err("%s: TP initialization failed\n", + adapter->name); + goto error; + } + + board_init(adapter, bi); + bi->mdio_ops->init(adapter, bi); + if (bi->gphy->reset) + bi->gphy->reset(adapter); + if (bi->gmac->reset) + bi->gmac->reset(adapter); + + for_each_port(adapter, i) { + u8 hw_addr[6]; + struct cmac *mac; + int phy_addr = bi->mdio_phybaseaddr + i; + + adapter->port[i].phy = bi->gphy->create(adapter->port[i].dev, + phy_addr, bi->mdio_ops); + if (!adapter->port[i].phy) { + pr_err("%s: PHY %d initialization failed\n", + adapter->name, i); + goto error; + } + + adapter->port[i].mac = mac = bi->gmac->create(adapter, i); + if (!mac) { + pr_err("%s: MAC %d initialization failed\n", + adapter->name, i); + goto error; + } + + /* + * Get the port's MAC addresses either from the EEPROM if one + * exists or the one hardcoded in the MAC. + */ + if (!t1_is_asic(adapter) || bi->chip_mac == CHBT_MAC_DUMMY) + mac->ops->macaddress_get(mac, hw_addr); + else if (vpd_macaddress_get(adapter, i, hw_addr)) { + pr_err("%s: could not read MAC address from VPD ROM\n", + adapter->port[i].dev->name); + goto error; + } + memcpy(adapter->port[i].dev->dev_addr, hw_addr, ETH_ALEN); + init_link_config(&adapter->port[i].link_config, bi); + } + + get_pci_mode(adapter, &adapter->params.pci); + t1_interrupts_clear(adapter); + return 0; + +error: + t1_free_sw_modules(adapter); + return -1; +} diff --git a/drivers/net/ethernet/chelsio/cxgb/suni1x10gexp_regs.h b/drivers/net/ethernet/chelsio/cxgb/suni1x10gexp_regs.h new file mode 100644 index 000000000000..d0f87d82566a --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb/suni1x10gexp_regs.h @@ -0,0 +1,1643 @@ +/***************************************************************************** + * * + * File: suni1x10gexp_regs.h * + * $Revision: 1.9 $ * + * $Date: 2005/06/22 00:17:04 $ * + * Description: * + * PMC/SIERRA (pm3393) MAC-PHY functionality. * + * part of the Chelsio 10Gb Ethernet Driver. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License, version 2, as * + * published by the Free Software Foundation. * + * * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * + * * + * http://www.chelsio.com * + * * + * Maintainers: maintainers@chelsio.com * + * * + * Authors: PMC/SIERRA * + * * + * History: * + * * + ****************************************************************************/ + +#ifndef _CXGB_SUNI1x10GEXP_REGS_H_ +#define _CXGB_SUNI1x10GEXP_REGS_H_ + +/* +** Space allocated for each Exact Match Filter +** There are 8 filter configurations +*/ +#define SUNI1x10GEXP_REG_SIZEOF_MAC_FILTER 0x0003 + +#define mSUNI1x10GEXP_MAC_FILTER_OFFSET(filterId) ( (filterId) * SUNI1x10GEXP_REG_SIZEOF_MAC_FILTER ) + +/* +** Space allocated for VLAN-Id Filter +** There are 8 filter configurations +*/ +#define SUNI1x10GEXP_REG_SIZEOF_MAC_VID_FILTER 0x0001 + +#define mSUNI1x10GEXP_MAC_VID_FILTER_OFFSET(filterId) ( (filterId) * SUNI1x10GEXP_REG_SIZEOF_MAC_VID_FILTER ) + +/* +** Space allocated for each MSTAT Counter +*/ +#define SUNI1x10GEXP_REG_SIZEOF_MSTAT_COUNT 0x0004 + +#define mSUNI1x10GEXP_MSTAT_COUNT_OFFSET(countId) ( (countId) * SUNI1x10GEXP_REG_SIZEOF_MSTAT_COUNT ) + + +/******************************************************************************/ +/** S/UNI-1x10GE-XP REGISTER ADDRESS MAP **/ +/******************************************************************************/ +/* Refer to the Register Bit Masks bellow for the naming of each register and */ +/* to the S/UNI-1x10GE-XP Data Sheet for the signification of each bit */ +/******************************************************************************/ + + +#define SUNI1x10GEXP_REG_IDENTIFICATION 0x0000 +#define SUNI1x10GEXP_REG_PRODUCT_REVISION 0x0001 +#define SUNI1x10GEXP_REG_CONFIG_AND_RESET_CONTROL 0x0002 +#define SUNI1x10GEXP_REG_LOOPBACK_MISC_CTRL 0x0003 +#define SUNI1x10GEXP_REG_DEVICE_STATUS 0x0004 +#define SUNI1x10GEXP_REG_GLOBAL_PERFORMANCE_MONITOR_UPDATE 0x0005 + +#define SUNI1x10GEXP_REG_MDIO_COMMAND 0x0006 +#define SUNI1x10GEXP_REG_MDIO_INTERRUPT_ENABLE 0x0007 +#define SUNI1x10GEXP_REG_MDIO_INTERRUPT_STATUS 0x0008 +#define SUNI1x10GEXP_REG_MMD_PHY_ADDRESS 0x0009 +#define SUNI1x10GEXP_REG_MMD_CONTROL_ADDRESS_DATA 0x000A +#define SUNI1x10GEXP_REG_MDIO_READ_STATUS_DATA 0x000B + +#define SUNI1x10GEXP_REG_OAM_INTF_CTRL 0x000C +#define SUNI1x10GEXP_REG_MASTER_INTERRUPT_STATUS 0x000D +#define SUNI1x10GEXP_REG_GLOBAL_INTERRUPT_ENABLE 0x000E +#define SUNI1x10GEXP_REG_FREE 0x000F + +#define SUNI1x10GEXP_REG_XTEF_MISC_CTRL 0x0010 +#define SUNI1x10GEXP_REG_XRF_MISC_CTRL 0x0011 + +#define SUNI1x10GEXP_REG_SERDES_3125_CONFIG_1 0x0100 +#define SUNI1x10GEXP_REG_SERDES_3125_CONFIG_2 0x0101 +#define SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_ENABLE 0x0102 +#define SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_VISIBLE 0x0103 +#define SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_STATUS 0x0104 +#define SUNI1x10GEXP_REG_SERDES_3125_TEST_CONFIG 0x0107 + +#define SUNI1x10GEXP_REG_RXXG_CONFIG_1 0x2040 +#define SUNI1x10GEXP_REG_RXXG_CONFIG_2 0x2041 +#define SUNI1x10GEXP_REG_RXXG_CONFIG_3 0x2042 +#define SUNI1x10GEXP_REG_RXXG_INTERRUPT 0x2043 +#define SUNI1x10GEXP_REG_RXXG_MAX_FRAME_LENGTH 0x2045 +#define SUNI1x10GEXP_REG_RXXG_SA_15_0 0x2046 +#define SUNI1x10GEXP_REG_RXXG_SA_31_16 0x2047 +#define SUNI1x10GEXP_REG_RXXG_SA_47_32 0x2048 +#define SUNI1x10GEXP_REG_RXXG_RECEIVE_FIFO_THRESHOLD 0x2049 +#define mSUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_LOW(filterId) (0x204A + mSUNI1x10GEXP_MAC_FILTER_OFFSET(filterId)) +#define mSUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_MID(filterId) (0x204B + mSUNI1x10GEXP_MAC_FILTER_OFFSET(filterId)) +#define mSUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_HIGH(filterId)(0x204C + mSUNI1x10GEXP_MAC_FILTER_OFFSET(filterId)) +#define mSUNI1x10GEXP_REG_RXXG_EXACT_MATCH_VID(filterId) (0x2062 + mSUNI1x10GEXP_MAC_VID_FILTER_OFFSET(filterId)) +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_0_LOW 0x204A +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_0_MID 0x204B +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_0_HIGH 0x204C +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_LOW 0x204D +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_MID 0x204E +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_1_HIGH 0x204F +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_2_LOW 0x2050 +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_2_MID 0x2051 +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_2_HIGH 0x2052 +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_3_LOW 0x2053 +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_3_MID 0x2054 +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_3_HIGH 0x2055 +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_4_LOW 0x2056 +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_4_MID 0x2057 +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_4_HIGH 0x2058 +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_5_LOW 0x2059 +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_5_MID 0x205A +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_5_HIGH 0x205B +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_6_LOW 0x205C +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_6_MID 0x205D +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_6_HIGH 0x205E +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_7_LOW 0x205F +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_7_MID 0x2060 +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_ADDR_7_HIGH 0x2061 +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_VID_0 0x2062 +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_VID_1 0x2063 +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_VID_2 0x2064 +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_VID_3 0x2065 +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_VID_4 0x2066 +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_VID_5 0x2067 +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_VID_6 0x2068 +#define SUNI1x10GEXP_REG_RXXG_EXACT_MATCH_VID_7 0x2069 +#define SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_LOW 0x206A +#define SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDLOW 0x206B +#define SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDHIGH 0x206C +#define SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_HIGH 0x206D +#define SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_0 0x206E +#define SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_1 0x206F +#define SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_2 0x2070 + +#define SUNI1x10GEXP_REG_XRF_PATTERN_GEN_CTRL 0x2081 +#define SUNI1x10GEXP_REG_XRF_8BTB_ERR_COUNT_LANE_0 0x2084 +#define SUNI1x10GEXP_REG_XRF_8BTB_ERR_COUNT_LANE_1 0x2085 +#define SUNI1x10GEXP_REG_XRF_8BTB_ERR_COUNT_LANE_2 0x2086 +#define SUNI1x10GEXP_REG_XRF_8BTB_ERR_COUNT_LANE_3 0x2087 +#define SUNI1x10GEXP_REG_XRF_INTERRUPT_ENABLE 0x2088 +#define SUNI1x10GEXP_REG_XRF_INTERRUPT_STATUS 0x2089 +#define SUNI1x10GEXP_REG_XRF_ERR_STATUS 0x208A +#define SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_ENABLE 0x208B +#define SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_STATUS 0x208C +#define SUNI1x10GEXP_REG_XRF_CODE_ERR_THRES 0x2092 + +#define SUNI1x10GEXP_REG_RXOAM_CONFIG 0x20C0 +#define SUNI1x10GEXP_REG_RXOAM_FILTER_1_CONFIG 0x20C1 +#define SUNI1x10GEXP_REG_RXOAM_FILTER_2_CONFIG 0x20C2 +#define SUNI1x10GEXP_REG_RXOAM_CONFIG_2 0x20C3 +#define SUNI1x10GEXP_REG_RXOAM_HEC_CONFIG 0x20C4 +#define SUNI1x10GEXP_REG_RXOAM_HEC_ERR_THRES 0x20C5 +#define SUNI1x10GEXP_REG_RXOAM_INTERRUPT_ENABLE 0x20C7 +#define SUNI1x10GEXP_REG_RXOAM_INTERRUPT_STATUS 0x20C8 +#define SUNI1x10GEXP_REG_RXOAM_STATUS 0x20C9 +#define SUNI1x10GEXP_REG_RXOAM_HEC_ERR_COUNT 0x20CA +#define SUNI1x10GEXP_REG_RXOAM_FIFO_OVERFLOW_COUNT 0x20CB +#define SUNI1x10GEXP_REG_RXOAM_FILTER_MISMATCH_COUNT_LSB 0x20CC +#define SUNI1x10GEXP_REG_RXOAM_FILTER_MISMATCH_COUNT_MSB 0x20CD +#define SUNI1x10GEXP_REG_RXOAM_FILTER_1_MISMATCH_COUNT_LSB 0x20CE +#define SUNI1x10GEXP_REG_RXOAM_FILTER_1_MISMATCH_COUNT_MSB 0x20CF +#define SUNI1x10GEXP_REG_RXOAM_FILTER_2_MISMATCH_COUNT_LSB 0x20D0 +#define SUNI1x10GEXP_REG_RXOAM_FILTER_2_MISMATCH_COUNT_MSB 0x20D1 +#define SUNI1x10GEXP_REG_RXOAM_OAM_EXTRACT_COUNT_LSB 0x20D2 +#define SUNI1x10GEXP_REG_RXOAM_OAM_EXTRACT_COUNT_MSB 0x20D3 +#define SUNI1x10GEXP_REG_RXOAM_MINI_PACKET_COUNT_LSB 0x20D4 +#define SUNI1x10GEXP_REG_RXOAM_MINI_PACKET_COUNT_MSB 0x20D5 +#define SUNI1x10GEXP_REG_RXOAM_FILTER_MISMATCH_THRES_LSB 0x20D6 +#define SUNI1x10GEXP_REG_RXOAM_FILTER_MISMATCH_THRES_MSB 0x20D7 + +#define SUNI1x10GEXP_REG_MSTAT_CONTROL 0x2100 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_0 0x2101 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_1 0x2102 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_2 0x2103 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_ROLLOVER_3 0x2104 +#define SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_0 0x2105 +#define SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_1 0x2106 +#define SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_2 0x2107 +#define SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_3 0x2108 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_WRITE_ADDRESS 0x2109 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_WRITE_DATA_LOW 0x210A +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_WRITE_DATA_MIDDLE 0x210B +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_WRITE_DATA_HIGH 0x210C +#define mSUNI1x10GEXP_REG_MSTAT_COUNTER_LOW(countId) (0x2110 + mSUNI1x10GEXP_MSTAT_COUNT_OFFSET(countId)) +#define mSUNI1x10GEXP_REG_MSTAT_COUNTER_MID(countId) (0x2111 + mSUNI1x10GEXP_MSTAT_COUNT_OFFSET(countId)) +#define mSUNI1x10GEXP_REG_MSTAT_COUNTER_HIGH(countId) (0x2112 + mSUNI1x10GEXP_MSTAT_COUNT_OFFSET(countId)) +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_0_LOW 0x2110 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_0_MID 0x2111 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_0_HIGH 0x2112 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_0_RESVD 0x2113 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_1_LOW 0x2114 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_1_MID 0x2115 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_1_HIGH 0x2116 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_1_RESVD 0x2117 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_2_LOW 0x2118 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_2_MID 0x2119 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_2_HIGH 0x211A +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_2_RESVD 0x211B +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_3_LOW 0x211C +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_3_MID 0x211D +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_3_HIGH 0x211E +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_3_RESVD 0x211F +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_4_LOW 0x2120 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_4_MID 0x2121 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_4_HIGH 0x2122 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_4_RESVD 0x2123 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_5_LOW 0x2124 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_5_MID 0x2125 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_5_HIGH 0x2126 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_5_RESVD 0x2127 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_6_LOW 0x2128 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_6_MID 0x2129 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_6_HIGH 0x212A +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_6_RESVD 0x212B +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_7_LOW 0x212C +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_7_MID 0x212D +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_7_HIGH 0x212E +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_7_RESVD 0x212F +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_8_LOW 0x2130 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_8_MID 0x2131 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_8_HIGH 0x2132 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_8_RESVD 0x2133 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_9_LOW 0x2134 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_9_MID 0x2135 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_9_HIGH 0x2136 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_9_RESVD 0x2137 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_10_LOW 0x2138 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_10_MID 0x2139 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_10_HIGH 0x213A +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_10_RESVD 0x213B +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_11_LOW 0x213C +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_11_MID 0x213D +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_11_HIGH 0x213E +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_11_RESVD 0x213F +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_12_LOW 0x2140 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_12_MID 0x2141 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_12_HIGH 0x2142 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_12_RESVD 0x2143 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_13_LOW 0x2144 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_13_MID 0x2145 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_13_HIGH 0x2146 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_13_RESVD 0x2147 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_14_LOW 0x2148 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_14_MID 0x2149 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_14_HIGH 0x214A +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_14_RESVD 0x214B +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_15_LOW 0x214C +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_15_MID 0x214D +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_15_HIGH 0x214E +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_15_RESVD 0x214F +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_16_LOW 0x2150 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_16_MID 0x2151 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_16_HIGH 0x2152 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_16_RESVD 0x2153 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_17_LOW 0x2154 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_17_MID 0x2155 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_17_HIGH 0x2156 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_17_RESVD 0x2157 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_18_LOW 0x2158 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_18_MID 0x2159 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_18_HIGH 0x215A +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_18_RESVD 0x215B +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_19_LOW 0x215C +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_19_MID 0x215D +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_19_HIGH 0x215E +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_19_RESVD 0x215F +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_20_LOW 0x2160 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_20_MID 0x2161 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_20_HIGH 0x2162 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_20_RESVD 0x2163 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_21_LOW 0x2164 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_21_MID 0x2165 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_21_HIGH 0x2166 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_21_RESVD 0x2167 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_22_LOW 0x2168 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_22_MID 0x2169 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_22_HIGH 0x216A +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_22_RESVD 0x216B +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_23_LOW 0x216C +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_23_MID 0x216D +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_23_HIGH 0x216E +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_23_RESVD 0x216F +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_24_LOW 0x2170 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_24_MID 0x2171 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_24_HIGH 0x2172 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_24_RESVD 0x2173 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_25_LOW 0x2174 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_25_MID 0x2175 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_25_HIGH 0x2176 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_25_RESVD 0x2177 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_26_LOW 0x2178 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_26_MID 0x2179 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_26_HIGH 0x217a +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_26_RESVD 0x217b +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_27_LOW 0x217c +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_27_MID 0x217d +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_27_HIGH 0x217e +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_27_RESVD 0x217f +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_28_LOW 0x2180 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_28_MID 0x2181 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_28_HIGH 0x2182 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_28_RESVD 0x2183 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_29_LOW 0x2184 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_29_MID 0x2185 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_29_HIGH 0x2186 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_29_RESVD 0x2187 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_30_LOW 0x2188 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_30_MID 0x2189 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_30_HIGH 0x218A +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_30_RESVD 0x218B +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_31_LOW 0x218C +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_31_MID 0x218D +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_31_HIGH 0x218E +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_31_RESVD 0x218F +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_32_LOW 0x2190 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_32_MID 0x2191 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_32_HIGH 0x2192 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_32_RESVD 0x2193 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_33_LOW 0x2194 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_33_MID 0x2195 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_33_HIGH 0x2196 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_33_RESVD 0x2197 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_34_LOW 0x2198 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_34_MID 0x2199 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_34_HIGH 0x219A +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_34_RESVD 0x219B +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_35_LOW 0x219C +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_35_MID 0x219D +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_35_HIGH 0x219E +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_35_RESVD 0x219F +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_36_LOW 0x21A0 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_36_MID 0x21A1 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_36_HIGH 0x21A2 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_36_RESVD 0x21A3 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_37_LOW 0x21A4 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_37_MID 0x21A5 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_37_HIGH 0x21A6 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_37_RESVD 0x21A7 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_38_LOW 0x21A8 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_38_MID 0x21A9 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_38_HIGH 0x21AA +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_38_RESVD 0x21AB +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_39_LOW 0x21AC +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_39_MID 0x21AD +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_39_HIGH 0x21AE +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_39_RESVD 0x21AF +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_40_LOW 0x21B0 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_40_MID 0x21B1 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_40_HIGH 0x21B2 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_40_RESVD 0x21B3 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_41_LOW 0x21B4 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_41_MID 0x21B5 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_41_HIGH 0x21B6 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_41_RESVD 0x21B7 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_42_LOW 0x21B8 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_42_MID 0x21B9 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_42_HIGH 0x21BA +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_42_RESVD 0x21BB +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_43_LOW 0x21BC +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_43_MID 0x21BD +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_43_HIGH 0x21BE +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_43_RESVD 0x21BF +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_44_LOW 0x21C0 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_44_MID 0x21C1 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_44_HIGH 0x21C2 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_44_RESVD 0x21C3 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_45_LOW 0x21C4 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_45_MID 0x21C5 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_45_HIGH 0x21C6 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_45_RESVD 0x21C7 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_46_LOW 0x21C8 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_46_MID 0x21C9 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_46_HIGH 0x21CA +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_46_RESVD 0x21CB +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_47_LOW 0x21CC +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_47_MID 0x21CD +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_47_HIGH 0x21CE +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_47_RESVD 0x21CF +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_48_LOW 0x21D0 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_48_MID 0x21D1 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_48_HIGH 0x21D2 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_48_RESVD 0x21D3 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_49_LOW 0x21D4 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_49_MID 0x21D5 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_49_HIGH 0x21D6 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_49_RESVD 0x21D7 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_50_LOW 0x21D8 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_50_MID 0x21D9 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_50_HIGH 0x21DA +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_50_RESVD 0x21DB +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_51_LOW 0x21DC +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_51_MID 0x21DD +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_51_HIGH 0x21DE +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_51_RESVD 0x21DF +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_52_LOW 0x21E0 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_52_MID 0x21E1 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_52_HIGH 0x21E2 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_52_RESVD 0x21E3 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_53_LOW 0x21E4 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_53_MID 0x21E5 +#define SUNI1x10GEXP_REG_MSTAT_COUNTER_53_HIGH 0x21E6 +#define SUNI1x10GEXP_CNTR_MAC_ETHERNET_NUM 51 + +#define SUNI1x10GEXP_REG_IFLX_GLOBAL_CONFIG 0x2200 +#define SUNI1x10GEXP_REG_IFLX_CHANNEL_PROVISION 0x2201 +#define SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_ENABLE 0x2209 +#define SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_INTERRUPT 0x220A +#define SUNI1x10GEXP_REG_IFLX_INDIR_CHANNEL_ADDRESS 0x220D +#define SUNI1x10GEXP_REG_IFLX_INDIR_LOGICAL_FIFO_LOW_LIMIT_PROVISION 0x220E +#define SUNI1x10GEXP_REG_IFLX_INDIR_LOGICAL_FIFO_HIGH_LIMIT 0x220F +#define SUNI1x10GEXP_REG_IFLX_INDIR_FULL_ALMOST_FULL_STATUS_LIMIT 0x2210 +#define SUNI1x10GEXP_REG_IFLX_INDIR_EMPTY_ALMOST_EMPTY_STATUS_LIMIT 0x2211 + +#define SUNI1x10GEXP_REG_PL4MOS_CONFIG 0x2240 +#define SUNI1x10GEXP_REG_PL4MOS_MASK 0x2241 +#define SUNI1x10GEXP_REG_PL4MOS_FAIRNESS_MASKING 0x2242 +#define SUNI1x10GEXP_REG_PL4MOS_MAXBURST1 0x2243 +#define SUNI1x10GEXP_REG_PL4MOS_MAXBURST2 0x2244 +#define SUNI1x10GEXP_REG_PL4MOS_TRANSFER_SIZE 0x2245 + +#define SUNI1x10GEXP_REG_PL4ODP_CONFIG 0x2280 +#define SUNI1x10GEXP_REG_PL4ODP_INTERRUPT_MASK 0x2282 +#define SUNI1x10GEXP_REG_PL4ODP_INTERRUPT 0x2283 +#define SUNI1x10GEXP_REG_PL4ODP_CONFIG_MAX_T 0x2284 + +#define SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_STATUS 0x2300 +#define SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_CHANGE 0x2301 +#define SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_MASK 0x2302 +#define SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_LIMITS 0x2303 +#define SUNI1x10GEXP_REG_PL4IO_CALENDAR_REPETITIONS 0x2304 +#define SUNI1x10GEXP_REG_PL4IO_CONFIG 0x2305 + +#define SUNI1x10GEXP_REG_TXXG_CONFIG_1 0x3040 +#define SUNI1x10GEXP_REG_TXXG_CONFIG_2 0x3041 +#define SUNI1x10GEXP_REG_TXXG_CONFIG_3 0x3042 +#define SUNI1x10GEXP_REG_TXXG_INTERRUPT 0x3043 +#define SUNI1x10GEXP_REG_TXXG_STATUS 0x3044 +#define SUNI1x10GEXP_REG_TXXG_MAX_FRAME_SIZE 0x3045 +#define SUNI1x10GEXP_REG_TXXG_MIN_FRAME_SIZE 0x3046 +#define SUNI1x10GEXP_REG_TXXG_SA_15_0 0x3047 +#define SUNI1x10GEXP_REG_TXXG_SA_31_16 0x3048 +#define SUNI1x10GEXP_REG_TXXG_SA_47_32 0x3049 +#define SUNI1x10GEXP_REG_TXXG_PAUSE_TIMER 0x304D +#define SUNI1x10GEXP_REG_TXXG_PAUSE_TIMER_INTERVAL 0x304E +#define SUNI1x10GEXP_REG_TXXG_FILTER_ERROR_COUNTER 0x3051 +#define SUNI1x10GEXP_REG_TXXG_PAUSE_QUANTUM_CONFIG 0x3052 + +#define SUNI1x10GEXP_REG_XTEF_CTRL 0x3080 +#define SUNI1x10GEXP_REG_XTEF_INTERRUPT_STATUS 0x3084 +#define SUNI1x10GEXP_REG_XTEF_INTERRUPT_ENABLE 0x3085 +#define SUNI1x10GEXP_REG_XTEF_VISIBILITY 0x3086 + +#define SUNI1x10GEXP_REG_TXOAM_OAM_CONFIG 0x30C0 +#define SUNI1x10GEXP_REG_TXOAM_MINI_RATE_CONFIG 0x30C1 +#define SUNI1x10GEXP_REG_TXOAM_MINI_GAP_FIFO_CONFIG 0x30C2 +#define SUNI1x10GEXP_REG_TXOAM_P1P2_STATIC_VALUES 0x30C3 +#define SUNI1x10GEXP_REG_TXOAM_P3P4_STATIC_VALUES 0x30C4 +#define SUNI1x10GEXP_REG_TXOAM_P5P6_STATIC_VALUES 0x30C5 +#define SUNI1x10GEXP_REG_TXOAM_INTERRUPT_ENABLE 0x30C6 +#define SUNI1x10GEXP_REG_TXOAM_INTERRUPT_STATUS 0x30C7 +#define SUNI1x10GEXP_REG_TXOAM_INSERT_COUNT_LSB 0x30C8 +#define SUNI1x10GEXP_REG_TXOAM_INSERT_COUNT_MSB 0x30C9 +#define SUNI1x10GEXP_REG_TXOAM_OAM_MINI_COUNT_LSB 0x30CA +#define SUNI1x10GEXP_REG_TXOAM_OAM_MINI_COUNT_MSB 0x30CB +#define SUNI1x10GEXP_REG_TXOAM_P1P2_MINI_MASK 0x30CC +#define SUNI1x10GEXP_REG_TXOAM_P3P4_MINI_MASK 0x30CD +#define SUNI1x10GEXP_REG_TXOAM_P5P6_MINI_MASK 0x30CE +#define SUNI1x10GEXP_REG_TXOAM_COSET 0x30CF +#define SUNI1x10GEXP_REG_TXOAM_EMPTY_FIFO_INS_OP_CNT_LSB 0x30D0 +#define SUNI1x10GEXP_REG_TXOAM_EMPTY_FIFO_INS_OP_CNT_MSB 0x30D1 +#define SUNI1x10GEXP_REG_TXOAM_STATIC_VALUE_MINI_COUNT_LSB 0x30D2 +#define SUNI1x10GEXP_REG_TXOAM_STATIC_VALUE_MINI_COUNT_MSB 0x30D3 + + +#define SUNI1x10GEXP_REG_EFLX_GLOBAL_CONFIG 0x3200 +#define SUNI1x10GEXP_REG_EFLX_ERCU_GLOBAL_STATUS 0x3201 +#define SUNI1x10GEXP_REG_EFLX_INDIR_CHANNEL_ADDRESS 0x3202 +#define SUNI1x10GEXP_REG_EFLX_INDIR_FIFO_LOW_LIMIT 0x3203 +#define SUNI1x10GEXP_REG_EFLX_INDIR_FIFO_HIGH_LIMIT 0x3204 +#define SUNI1x10GEXP_REG_EFLX_INDIR_FULL_ALMOST_FULL_STATUS_AND_LIMIT 0x3205 +#define SUNI1x10GEXP_REG_EFLX_INDIR_EMPTY_ALMOST_EMPTY_STATUS_AND_LIMIT 0x3206 +#define SUNI1x10GEXP_REG_EFLX_INDIR_FIFO_CUT_THROUGH_THRESHOLD 0x3207 +#define SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_ENABLE 0x320C +#define SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_INDICATION 0x320D +#define SUNI1x10GEXP_REG_EFLX_CHANNEL_PROVISION 0x3210 + +#define SUNI1x10GEXP_REG_PL4IDU_CONFIG 0x3280 +#define SUNI1x10GEXP_REG_PL4IDU_INTERRUPT_MASK 0x3282 +#define SUNI1x10GEXP_REG_PL4IDU_INTERRUPT 0x3283 + + +/*----------------------------------------*/ +#define SUNI1x10GEXP_REG_MAX_OFFSET 0x3480 + +/******************************************************************************/ +/* -- End register offset definitions -- */ +/******************************************************************************/ + +/******************************************************************************/ +/** SUNI-1x10GE-XP REGISTER BIT MASKS **/ +/******************************************************************************/ + +#define SUNI1x10GEXP_BITMSK_BITS_1 0x00001 +#define SUNI1x10GEXP_BITMSK_BITS_2 0x00003 +#define SUNI1x10GEXP_BITMSK_BITS_3 0x00007 +#define SUNI1x10GEXP_BITMSK_BITS_4 0x0000f +#define SUNI1x10GEXP_BITMSK_BITS_5 0x0001f +#define SUNI1x10GEXP_BITMSK_BITS_6 0x0003f +#define SUNI1x10GEXP_BITMSK_BITS_7 0x0007f +#define SUNI1x10GEXP_BITMSK_BITS_8 0x000ff +#define SUNI1x10GEXP_BITMSK_BITS_9 0x001ff +#define SUNI1x10GEXP_BITMSK_BITS_10 0x003ff +#define SUNI1x10GEXP_BITMSK_BITS_11 0x007ff +#define SUNI1x10GEXP_BITMSK_BITS_12 0x00fff +#define SUNI1x10GEXP_BITMSK_BITS_13 0x01fff +#define SUNI1x10GEXP_BITMSK_BITS_14 0x03fff +#define SUNI1x10GEXP_BITMSK_BITS_15 0x07fff +#define SUNI1x10GEXP_BITMSK_BITS_16 0x0ffff + +#define mSUNI1x10GEXP_CLR_MSBITS_1(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_15) +#define mSUNI1x10GEXP_CLR_MSBITS_2(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_14) +#define mSUNI1x10GEXP_CLR_MSBITS_3(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_13) +#define mSUNI1x10GEXP_CLR_MSBITS_4(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_12) +#define mSUNI1x10GEXP_CLR_MSBITS_5(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_11) +#define mSUNI1x10GEXP_CLR_MSBITS_6(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_10) +#define mSUNI1x10GEXP_CLR_MSBITS_7(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_9) +#define mSUNI1x10GEXP_CLR_MSBITS_8(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_8) +#define mSUNI1x10GEXP_CLR_MSBITS_9(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_7) +#define mSUNI1x10GEXP_CLR_MSBITS_10(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_6) +#define mSUNI1x10GEXP_CLR_MSBITS_11(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_5) +#define mSUNI1x10GEXP_CLR_MSBITS_12(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_4) +#define mSUNI1x10GEXP_CLR_MSBITS_13(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_3) +#define mSUNI1x10GEXP_CLR_MSBITS_14(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_2) +#define mSUNI1x10GEXP_CLR_MSBITS_15(v) ((v) & SUNI1x10GEXP_BITMSK_BITS_1) + +#define mSUNI1x10GEXP_GET_BIT(val, bitMsk) (((val)&(bitMsk)) ? 1:0) + + + +/*---------------------------------------------------------------------------- + * Register 0x0001: S/UNI-1x10GE-XP Product Revision + * Bit 3-0 REVISION + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_REVISION 0x000F + +/*---------------------------------------------------------------------------- + * Register 0x0002: S/UNI-1x10GE-XP Configuration and Reset Control + * Bit 2 XAUI_ARESETB + * Bit 1 PL4_ARESETB + * Bit 0 DRESETB + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_XAUI_ARESET 0x0004 +#define SUNI1x10GEXP_BITMSK_PL4_ARESET 0x0002 +#define SUNI1x10GEXP_BITMSK_DRESETB 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x0003: S/UNI-1x10GE-XP Loop Back and Miscellaneous Control + * Bit 11 PL4IO_OUTCLKSEL + * Bit 9 SYSPCSLB + * Bit 8 LINEPCSLB + * Bit 7 MSTAT_BYPASS + * Bit 6 RXXG_BYPASS + * Bit 5 TXXG_BYPASS + * Bit 4 SOP_PAD_EN + * Bit 1 LOS_INV + * Bit 0 OVERRIDE_LOS + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_PL4IO_OUTCLKSEL 0x0800 +#define SUNI1x10GEXP_BITMSK_SYSPCSLB 0x0200 +#define SUNI1x10GEXP_BITMSK_LINEPCSLB 0x0100 +#define SUNI1x10GEXP_BITMSK_MSTAT_BYPASS 0x0080 +#define SUNI1x10GEXP_BITMSK_RXXG_BYPASS 0x0040 +#define SUNI1x10GEXP_BITMSK_TXXG_BYPASS 0x0020 +#define SUNI1x10GEXP_BITMSK_SOP_PAD_EN 0x0010 +#define SUNI1x10GEXP_BITMSK_LOS_INV 0x0002 +#define SUNI1x10GEXP_BITMSK_OVERRIDE_LOS 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x0004: S/UNI-1x10GE-XP Device Status + * Bit 9 TOP_SXRA_EXPIRED + * Bit 8 TOP_MDIO_BUSY + * Bit 7 TOP_DTRB + * Bit 6 TOP_EXPIRED + * Bit 5 TOP_PAUSED + * Bit 4 TOP_PL4_ID_DOOL + * Bit 3 TOP_PL4_IS_DOOL + * Bit 2 TOP_PL4_ID_ROOL + * Bit 1 TOP_PL4_IS_ROOL + * Bit 0 TOP_PL4_OUT_ROOL + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_TOP_SXRA_EXPIRED 0x0200 +#define SUNI1x10GEXP_BITMSK_TOP_MDIO_BUSY 0x0100 +#define SUNI1x10GEXP_BITMSK_TOP_DTRB 0x0080 +#define SUNI1x10GEXP_BITMSK_TOP_EXPIRED 0x0040 +#define SUNI1x10GEXP_BITMSK_TOP_PAUSED 0x0020 +#define SUNI1x10GEXP_BITMSK_TOP_PL4_ID_DOOL 0x0010 +#define SUNI1x10GEXP_BITMSK_TOP_PL4_IS_DOOL 0x0008 +#define SUNI1x10GEXP_BITMSK_TOP_PL4_ID_ROOL 0x0004 +#define SUNI1x10GEXP_BITMSK_TOP_PL4_IS_ROOL 0x0002 +#define SUNI1x10GEXP_BITMSK_TOP_PL4_OUT_ROOL 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x0005: Global Performance Update and Clock Monitors + * Bit 15 TIP + * Bit 8 XAUI_REF_CLKA + * Bit 7 RXLANE3CLKA + * Bit 6 RXLANE2CLKA + * Bit 5 RXLANE1CLKA + * Bit 4 RXLANE0CLKA + * Bit 3 CSUCLKA + * Bit 2 TDCLKA + * Bit 1 RSCLKA + * Bit 0 RDCLKA + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_TIP 0x8000 +#define SUNI1x10GEXP_BITMSK_XAUI_REF_CLKA 0x0100 +#define SUNI1x10GEXP_BITMSK_RXLANE3CLKA 0x0080 +#define SUNI1x10GEXP_BITMSK_RXLANE2CLKA 0x0040 +#define SUNI1x10GEXP_BITMSK_RXLANE1CLKA 0x0020 +#define SUNI1x10GEXP_BITMSK_RXLANE0CLKA 0x0010 +#define SUNI1x10GEXP_BITMSK_CSUCLKA 0x0008 +#define SUNI1x10GEXP_BITMSK_TDCLKA 0x0004 +#define SUNI1x10GEXP_BITMSK_RSCLKA 0x0002 +#define SUNI1x10GEXP_BITMSK_RDCLKA 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x0006: MDIO Command + * Bit 4 MDIO_RDINC + * Bit 3 MDIO_RSTAT + * Bit 2 MDIO_LCTLD + * Bit 1 MDIO_LCTLA + * Bit 0 MDIO_SPRE + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_MDIO_RDINC 0x0010 +#define SUNI1x10GEXP_BITMSK_MDIO_RSTAT 0x0008 +#define SUNI1x10GEXP_BITMSK_MDIO_LCTLD 0x0004 +#define SUNI1x10GEXP_BITMSK_MDIO_LCTLA 0x0002 +#define SUNI1x10GEXP_BITMSK_MDIO_SPRE 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x0007: MDIO Interrupt Enable + * Bit 0 MDIO_BUSY_EN + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_MDIO_BUSY_EN 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x0008: MDIO Interrupt Status + * Bit 0 MDIO_BUSYI + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_MDIO_BUSYI 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x0009: MMD PHY Address + * Bit 12-8 MDIO_DEVADR + * Bit 4-0 MDIO_PRTADR + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_MDIO_DEVADR 0x1F00 +#define SUNI1x10GEXP_BITOFF_MDIO_DEVADR 8 +#define SUNI1x10GEXP_BITMSK_MDIO_PRTADR 0x001F +#define SUNI1x10GEXP_BITOFF_MDIO_PRTADR 0 + +/*---------------------------------------------------------------------------- + * Register 0x000C: OAM Interface Control + * Bit 6 MDO_OD_ENB + * Bit 5 MDI_INV + * Bit 4 MDI_SEL + * Bit 3 RXOAMEN + * Bit 2 RXOAMCLKEN + * Bit 1 TXOAMEN + * Bit 0 TXOAMCLKEN + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_MDO_OD_ENB 0x0040 +#define SUNI1x10GEXP_BITMSK_MDI_INV 0x0020 +#define SUNI1x10GEXP_BITMSK_MDI_SEL 0x0010 +#define SUNI1x10GEXP_BITMSK_RXOAMEN 0x0008 +#define SUNI1x10GEXP_BITMSK_RXOAMCLKEN 0x0004 +#define SUNI1x10GEXP_BITMSK_TXOAMEN 0x0002 +#define SUNI1x10GEXP_BITMSK_TXOAMCLKEN 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x000D: S/UNI-1x10GE-XP Master Interrupt Status + * Bit 15 TOP_PL4IO_INT + * Bit 14 TOP_IRAM_INT + * Bit 13 TOP_ERAM_INT + * Bit 12 TOP_XAUI_INT + * Bit 11 TOP_MSTAT_INT + * Bit 10 TOP_RXXG_INT + * Bit 9 TOP_TXXG_INT + * Bit 8 TOP_XRF_INT + * Bit 7 TOP_XTEF_INT + * Bit 6 TOP_MDIO_BUSY_INT + * Bit 5 TOP_RXOAM_INT + * Bit 4 TOP_TXOAM_INT + * Bit 3 TOP_IFLX_INT + * Bit 2 TOP_EFLX_INT + * Bit 1 TOP_PL4ODP_INT + * Bit 0 TOP_PL4IDU_INT + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_TOP_PL4IO_INT 0x8000 +#define SUNI1x10GEXP_BITMSK_TOP_IRAM_INT 0x4000 +#define SUNI1x10GEXP_BITMSK_TOP_ERAM_INT 0x2000 +#define SUNI1x10GEXP_BITMSK_TOP_XAUI_INT 0x1000 +#define SUNI1x10GEXP_BITMSK_TOP_MSTAT_INT 0x0800 +#define SUNI1x10GEXP_BITMSK_TOP_RXXG_INT 0x0400 +#define SUNI1x10GEXP_BITMSK_TOP_TXXG_INT 0x0200 +#define SUNI1x10GEXP_BITMSK_TOP_XRF_INT 0x0100 +#define SUNI1x10GEXP_BITMSK_TOP_XTEF_INT 0x0080 +#define SUNI1x10GEXP_BITMSK_TOP_MDIO_BUSY_INT 0x0040 +#define SUNI1x10GEXP_BITMSK_TOP_RXOAM_INT 0x0020 +#define SUNI1x10GEXP_BITMSK_TOP_TXOAM_INT 0x0010 +#define SUNI1x10GEXP_BITMSK_TOP_IFLX_INT 0x0008 +#define SUNI1x10GEXP_BITMSK_TOP_EFLX_INT 0x0004 +#define SUNI1x10GEXP_BITMSK_TOP_PL4ODP_INT 0x0002 +#define SUNI1x10GEXP_BITMSK_TOP_PL4IDU_INT 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x000E:PM3393 Global interrupt enable + * Bit 15 TOP_INTE + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_TOP_INTE 0x8000 + +/*---------------------------------------------------------------------------- + * Register 0x0010: XTEF Miscellaneous Control + * Bit 7 RF_VAL + * Bit 6 RF_OVERRIDE + * Bit 5 LF_VAL + * Bit 4 LF_OVERRIDE + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_RF_VAL 0x0080 +#define SUNI1x10GEXP_BITMSK_RF_OVERRIDE 0x0040 +#define SUNI1x10GEXP_BITMSK_LF_VAL 0x0020 +#define SUNI1x10GEXP_BITMSK_LF_OVERRIDE 0x0010 +#define SUNI1x10GEXP_BITMSK_LFRF_OVERRIDE_VAL 0x00F0 + +/*---------------------------------------------------------------------------- + * Register 0x0011: XRF Miscellaneous Control + * Bit 6-4 EN_IDLE_REP + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_EN_IDLE_REP 0x0070 + +/*---------------------------------------------------------------------------- + * Register 0x0100: SERDES 3125 Configuration Register 1 + * Bit 10 RXEQB_3 + * Bit 8 RXEQB_2 + * Bit 6 RXEQB_1 + * Bit 4 RXEQB_0 + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_RXEQB 0x0FF0 +#define SUNI1x10GEXP_BITOFF_RXEQB_3 10 +#define SUNI1x10GEXP_BITOFF_RXEQB_2 8 +#define SUNI1x10GEXP_BITOFF_RXEQB_1 6 +#define SUNI1x10GEXP_BITOFF_RXEQB_0 4 + +/*---------------------------------------------------------------------------- + * Register 0x0101: SERDES 3125 Configuration Register 2 + * Bit 12 YSEL + * Bit 7 PRE_EMPH_3 + * Bit 6 PRE_EMPH_2 + * Bit 5 PRE_EMPH_1 + * Bit 4 PRE_EMPH_0 + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_YSEL 0x1000 +#define SUNI1x10GEXP_BITMSK_PRE_EMPH 0x00F0 +#define SUNI1x10GEXP_BITMSK_PRE_EMPH_3 0x0080 +#define SUNI1x10GEXP_BITMSK_PRE_EMPH_2 0x0040 +#define SUNI1x10GEXP_BITMSK_PRE_EMPH_1 0x0020 +#define SUNI1x10GEXP_BITMSK_PRE_EMPH_0 0x0010 + +/*---------------------------------------------------------------------------- + * Register 0x0102: SERDES 3125 Interrupt Enable Register + * Bit 3 LASIE + * Bit 2 SPLL_RAE + * Bit 1 MPLL_RAE + * Bit 0 PLL_LOCKE + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_LASIE 0x0008 +#define SUNI1x10GEXP_BITMSK_SPLL_RAE 0x0004 +#define SUNI1x10GEXP_BITMSK_MPLL_RAE 0x0002 +#define SUNI1x10GEXP_BITMSK_PLL_LOCKE 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x0103: SERDES 3125 Interrupt Visibility Register + * Bit 3 LASIV + * Bit 2 SPLL_RAV + * Bit 1 MPLL_RAV + * Bit 0 PLL_LOCKV + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_LASIV 0x0008 +#define SUNI1x10GEXP_BITMSK_SPLL_RAV 0x0004 +#define SUNI1x10GEXP_BITMSK_MPLL_RAV 0x0002 +#define SUNI1x10GEXP_BITMSK_PLL_LOCKV 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x0104: SERDES 3125 Interrupt Status Register + * Bit 3 LASII + * Bit 2 SPLL_RAI + * Bit 1 MPLL_RAI + * Bit 0 PLL_LOCKI + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_LASII 0x0008 +#define SUNI1x10GEXP_BITMSK_SPLL_RAI 0x0004 +#define SUNI1x10GEXP_BITMSK_MPLL_RAI 0x0002 +#define SUNI1x10GEXP_BITMSK_PLL_LOCKI 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x0107: SERDES 3125 Test Configuration + * Bit 12 DUALTX + * Bit 10 HC_1 + * Bit 9 HC_0 + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_DUALTX 0x1000 +#define SUNI1x10GEXP_BITMSK_HC 0x0600 +#define SUNI1x10GEXP_BITOFF_HC_0 9 + +/*---------------------------------------------------------------------------- + * Register 0x2040: RXXG Configuration 1 + * Bit 15 RXXG_RXEN + * Bit 14 RXXG_ROCF + * Bit 13 RXXG_PAD_STRIP + * Bit 10 RXXG_PUREP + * Bit 9 RXXG_LONGP + * Bit 8 RXXG_PARF + * Bit 7 RXXG_FLCHK + * Bit 5 RXXG_PASS_CTRL + * Bit 3 RXXG_CRC_STRIP + * Bit 2-0 RXXG_MIFG + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_RXXG_RXEN 0x8000 +#define SUNI1x10GEXP_BITMSK_RXXG_ROCF 0x4000 +#define SUNI1x10GEXP_BITMSK_RXXG_PAD_STRIP 0x2000 +#define SUNI1x10GEXP_BITMSK_RXXG_PUREP 0x0400 +#define SUNI1x10GEXP_BITMSK_RXXG_LONGP 0x0200 +#define SUNI1x10GEXP_BITMSK_RXXG_PARF 0x0100 +#define SUNI1x10GEXP_BITMSK_RXXG_FLCHK 0x0080 +#define SUNI1x10GEXP_BITMSK_RXXG_PASS_CTRL 0x0020 +#define SUNI1x10GEXP_BITMSK_RXXG_CRC_STRIP 0x0008 + +/*---------------------------------------------------------------------------- + * Register 0x02041: RXXG Configuration 2 + * Bit 7-0 RXXG_HDRSIZE + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_RXXG_HDRSIZE 0x00FF + +/*---------------------------------------------------------------------------- + * Register 0x2042: RXXG Configuration 3 + * Bit 15 RXXG_MIN_LERRE + * Bit 14 RXXG_MAX_LERRE + * Bit 12 RXXG_LINE_ERRE + * Bit 10 RXXG_RX_OVRE + * Bit 9 RXXG_ADR_FILTERE + * Bit 8 RXXG_ERR_FILTERE + * Bit 5 RXXG_PRMB_ERRE + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_RXXG_MIN_LERRE 0x8000 +#define SUNI1x10GEXP_BITMSK_RXXG_MAX_LERRE 0x4000 +#define SUNI1x10GEXP_BITMSK_RXXG_LINE_ERRE 0x1000 +#define SUNI1x10GEXP_BITMSK_RXXG_RX_OVRE 0x0400 +#define SUNI1x10GEXP_BITMSK_RXXG_ADR_FILTERE 0x0200 +#define SUNI1x10GEXP_BITMSK_RXXG_ERR_FILTERRE 0x0100 +#define SUNI1x10GEXP_BITMSK_RXXG_PRMB_ERRE 0x0020 + +/*---------------------------------------------------------------------------- + * Register 0x2043: RXXG Interrupt + * Bit 15 RXXG_MIN_LERRI + * Bit 14 RXXG_MAX_LERRI + * Bit 12 RXXG_LINE_ERRI + * Bit 10 RXXG_RX_OVRI + * Bit 9 RXXG_ADR_FILTERI + * Bit 8 RXXG_ERR_FILTERI + * Bit 5 RXXG_PRMB_ERRE + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_RXXG_MIN_LERRI 0x8000 +#define SUNI1x10GEXP_BITMSK_RXXG_MAX_LERRI 0x4000 +#define SUNI1x10GEXP_BITMSK_RXXG_LINE_ERRI 0x1000 +#define SUNI1x10GEXP_BITMSK_RXXG_RX_OVRI 0x0400 +#define SUNI1x10GEXP_BITMSK_RXXG_ADR_FILTERI 0x0200 +#define SUNI1x10GEXP_BITMSK_RXXG_ERR_FILTERI 0x0100 +#define SUNI1x10GEXP_BITMSK_RXXG_PRMB_ERRE 0x0020 + +/*---------------------------------------------------------------------------- + * Register 0x2049: RXXG Receive FIFO Threshold + * Bit 2-0 RXXG_CUT_THRU + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_RXXG_CUT_THRU 0x0007 +#define SUNI1x10GEXP_BITOFF_RXXG_CUT_THRU 0 + +/*---------------------------------------------------------------------------- + * Register 0x2062H - 0x2069: RXXG Exact Match VID + * Bit 11-0 RXXG_VID_MATCH + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_RXXG_VID_MATCH 0x0FFF +#define SUNI1x10GEXP_BITOFF_RXXG_VID_MATCH 0 + +/*---------------------------------------------------------------------------- + * Register 0x206EH - 0x206F: RXXG Address Filter Control + * Bit 3 RXXG_FORWARD_ENABLE + * Bit 2 RXXG_VLAN_ENABLE + * Bit 1 RXXG_SRC_ADDR + * Bit 0 RXXG_MATCH_ENABLE + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_RXXG_FORWARD_ENABLE 0x0008 +#define SUNI1x10GEXP_BITMSK_RXXG_VLAN_ENABLE 0x0004 +#define SUNI1x10GEXP_BITMSK_RXXG_SRC_ADDR 0x0002 +#define SUNI1x10GEXP_BITMSK_RXXG_MATCH_ENABLE 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x2070: RXXG Address Filter Control 2 + * Bit 1 RXXG_PMODE + * Bit 0 RXXG_MHASH_EN + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_RXXG_PMODE 0x0002 +#define SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x2081: XRF Control Register 2 + * Bit 6 EN_PKT_GEN + * Bit 4-2 PATT + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_EN_PKT_GEN 0x0040 +#define SUNI1x10GEXP_BITMSK_PATT 0x001C +#define SUNI1x10GEXP_BITOFF_PATT 2 + +/*---------------------------------------------------------------------------- + * Register 0x2088: XRF Interrupt Enable + * Bit 12-9 LANE_HICERE + * Bit 8-5 HS_SD_LANEE + * Bit 4 ALIGN_STATUS_ERRE + * Bit 3-0 LANE_SYNC_STAT_ERRE + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_LANE_HICERE 0x1E00 +#define SUNI1x10GEXP_BITOFF_LANE_HICERE 9 +#define SUNI1x10GEXP_BITMSK_HS_SD_LANEE 0x01E0 +#define SUNI1x10GEXP_BITOFF_HS_SD_LANEE 5 +#define SUNI1x10GEXP_BITMSK_ALIGN_STATUS_ERRE 0x0010 +#define SUNI1x10GEXP_BITMSK_LANE_SYNC_STAT_ERRE 0x000F +#define SUNI1x10GEXP_BITOFF_LANE_SYNC_STAT_ERRE 0 + +/*---------------------------------------------------------------------------- + * Register 0x2089: XRF Interrupt Status + * Bit 12-9 LANE_HICERI + * Bit 8-5 HS_SD_LANEI + * Bit 4 ALIGN_STATUS_ERRI + * Bit 3-0 LANE_SYNC_STAT_ERRI + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_LANE_HICERI 0x1E00 +#define SUNI1x10GEXP_BITOFF_LANE_HICERI 9 +#define SUNI1x10GEXP_BITMSK_HS_SD_LANEI 0x01E0 +#define SUNI1x10GEXP_BITOFF_HS_SD_LANEI 5 +#define SUNI1x10GEXP_BITMSK_ALIGN_STATUS_ERRI 0x0010 +#define SUNI1x10GEXP_BITMSK_LANE_SYNC_STAT_ERRI 0x000F +#define SUNI1x10GEXP_BITOFF_LANE_SYNC_STAT_ERRI 0 + +/*---------------------------------------------------------------------------- + * Register 0x208A: XRF Error Status + * Bit 8-5 HS_SD_LANE + * Bit 4 ALIGN_STATUS_ERR + * Bit 3-0 LANE_SYNC_STAT_ERR + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_HS_SD_LANE3 0x0100 +#define SUNI1x10GEXP_BITMSK_HS_SD_LANE2 0x0080 +#define SUNI1x10GEXP_BITMSK_HS_SD_LANE1 0x0040 +#define SUNI1x10GEXP_BITMSK_HS_SD_LANE0 0x0020 +#define SUNI1x10GEXP_BITMSK_ALIGN_STATUS_ERR 0x0010 +#define SUNI1x10GEXP_BITMSK_LANE3_SYNC_STAT_ERR 0x0008 +#define SUNI1x10GEXP_BITMSK_LANE2_SYNC_STAT_ERR 0x0004 +#define SUNI1x10GEXP_BITMSK_LANE1_SYNC_STAT_ERR 0x0002 +#define SUNI1x10GEXP_BITMSK_LANE0_SYNC_STAT_ERR 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x208B: XRF Diagnostic Interrupt Enable + * Bit 7-4 LANE_OVERRUNE + * Bit 3-0 LANE_UNDERRUNE + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_LANE_OVERRUNE 0x00F0 +#define SUNI1x10GEXP_BITOFF_LANE_OVERRUNE 4 +#define SUNI1x10GEXP_BITMSK_LANE_UNDERRUNE 0x000F +#define SUNI1x10GEXP_BITOFF_LANE_UNDERRUNE 0 + +/*---------------------------------------------------------------------------- + * Register 0x208C: XRF Diagnostic Interrupt Status + * Bit 7-4 LANE_OVERRUNI + * Bit 3-0 LANE_UNDERRUNI + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_LANE_OVERRUNI 0x00F0 +#define SUNI1x10GEXP_BITOFF_LANE_OVERRUNI 4 +#define SUNI1x10GEXP_BITMSK_LANE_UNDERRUNI 0x000F +#define SUNI1x10GEXP_BITOFF_LANE_UNDERRUNI 0 + +/*---------------------------------------------------------------------------- + * Register 0x20C0: RXOAM Configuration + * Bit 15 RXOAM_BUSY + * Bit 14-12 RXOAM_F2_SEL + * Bit 10-8 RXOAM_F1_SEL + * Bit 7-6 RXOAM_FILTER_CTRL + * Bit 5-0 RXOAM_PX_EN + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_RXOAM_BUSY 0x8000 +#define SUNI1x10GEXP_BITMSK_RXOAM_F2_SEL 0x7000 +#define SUNI1x10GEXP_BITOFF_RXOAM_F2_SEL 12 +#define SUNI1x10GEXP_BITMSK_RXOAM_F1_SEL 0x0700 +#define SUNI1x10GEXP_BITOFF_RXOAM_F1_SEL 8 +#define SUNI1x10GEXP_BITMSK_RXOAM_FILTER_CTRL 0x00C0 +#define SUNI1x10GEXP_BITOFF_RXOAM_FILTER_CTRL 6 +#define SUNI1x10GEXP_BITMSK_RXOAM_PX_EN 0x003F +#define SUNI1x10GEXP_BITOFF_RXOAM_PX_EN 0 + +/*---------------------------------------------------------------------------- + * Register 0x20C1,0x20C2: RXOAM Filter Configuration + * Bit 15-8 RXOAM_FX_MASK + * Bit 7-0 RXOAM_FX_VAL + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_RXOAM_FX_MASK 0xFF00 +#define SUNI1x10GEXP_BITOFF_RXOAM_FX_MASK 8 +#define SUNI1x10GEXP_BITMSK_RXOAM_FX_VAL 0x00FF +#define SUNI1x10GEXP_BITOFF_RXOAM_FX_VAl 0 + +/*---------------------------------------------------------------------------- + * Register 0x20C3: RXOAM Configuration Register 2 + * Bit 13 RXOAM_REC_BYTE_VAL + * Bit 11-10 RXOAM_BYPASS_MODE + * Bit 5-0 RXOAM_PX_CLEAR + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_RXOAM_REC_BYTE_VAL 0x2000 +#define SUNI1x10GEXP_BITMSK_RXOAM_BYPASS_MODE 0x0C00 +#define SUNI1x10GEXP_BITOFF_RXOAM_BYPASS_MODE 10 +#define SUNI1x10GEXP_BITMSK_RXOAM_PX_CLEAR 0x003F +#define SUNI1x10GEXP_BITOFF_RXOAM_PX_CLEAR 0 + +/*---------------------------------------------------------------------------- + * Register 0x20C4: RXOAM HEC Configuration + * Bit 15-8 RXOAM_COSET + * Bit 2 RXOAM_HEC_ERR_PKT + * Bit 0 RXOAM_HEC_EN + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_RXOAM_COSET 0xFF00 +#define SUNI1x10GEXP_BITOFF_RXOAM_COSET 8 +#define SUNI1x10GEXP_BITMSK_RXOAM_HEC_ERR_PKT 0x0004 +#define SUNI1x10GEXP_BITMSK_RXOAM_HEC_EN 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x20C7: RXOAM Interrupt Enable + * Bit 10 RXOAM_FILTER_THRSHE + * Bit 9 RXOAM_OAM_ERRE + * Bit 8 RXOAM_HECE_THRSHE + * Bit 7 RXOAM_SOPE + * Bit 6 RXOAM_RFE + * Bit 5 RXOAM_LFE + * Bit 4 RXOAM_DV_ERRE + * Bit 3 RXOAM_DATA_INVALIDE + * Bit 2 RXOAM_FILTER_DROPE + * Bit 1 RXOAM_HECE + * Bit 0 RXOAM_OFLE + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_RXOAM_FILTER_THRSHE 0x0400 +#define SUNI1x10GEXP_BITMSK_RXOAM_OAM_ERRE 0x0200 +#define SUNI1x10GEXP_BITMSK_RXOAM_HECE_THRSHE 0x0100 +#define SUNI1x10GEXP_BITMSK_RXOAM_SOPE 0x0080 +#define SUNI1x10GEXP_BITMSK_RXOAM_RFE 0x0040 +#define SUNI1x10GEXP_BITMSK_RXOAM_LFE 0x0020 +#define SUNI1x10GEXP_BITMSK_RXOAM_DV_ERRE 0x0010 +#define SUNI1x10GEXP_BITMSK_RXOAM_DATA_INVALIDE 0x0008 +#define SUNI1x10GEXP_BITMSK_RXOAM_FILTER_DROPE 0x0004 +#define SUNI1x10GEXP_BITMSK_RXOAM_HECE 0x0002 +#define SUNI1x10GEXP_BITMSK_RXOAM_OFLE 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x20C8: RXOAM Interrupt Status + * Bit 10 RXOAM_FILTER_THRSHI + * Bit 9 RXOAM_OAM_ERRI + * Bit 8 RXOAM_HECE_THRSHI + * Bit 7 RXOAM_SOPI + * Bit 6 RXOAM_RFI + * Bit 5 RXOAM_LFI + * Bit 4 RXOAM_DV_ERRI + * Bit 3 RXOAM_DATA_INVALIDI + * Bit 2 RXOAM_FILTER_DROPI + * Bit 1 RXOAM_HECI + * Bit 0 RXOAM_OFLI + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_RXOAM_FILTER_THRSHI 0x0400 +#define SUNI1x10GEXP_BITMSK_RXOAM_OAM_ERRI 0x0200 +#define SUNI1x10GEXP_BITMSK_RXOAM_HECE_THRSHI 0x0100 +#define SUNI1x10GEXP_BITMSK_RXOAM_SOPI 0x0080 +#define SUNI1x10GEXP_BITMSK_RXOAM_RFI 0x0040 +#define SUNI1x10GEXP_BITMSK_RXOAM_LFI 0x0020 +#define SUNI1x10GEXP_BITMSK_RXOAM_DV_ERRI 0x0010 +#define SUNI1x10GEXP_BITMSK_RXOAM_DATA_INVALIDI 0x0008 +#define SUNI1x10GEXP_BITMSK_RXOAM_FILTER_DROPI 0x0004 +#define SUNI1x10GEXP_BITMSK_RXOAM_HECI 0x0002 +#define SUNI1x10GEXP_BITMSK_RXOAM_OFLI 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x20C9: RXOAM Status + * Bit 10 RXOAM_FILTER_THRSHV + * Bit 8 RXOAM_HECE_THRSHV + * Bit 6 RXOAM_RFV + * Bit 5 RXOAM_LFV + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_RXOAM_FILTER_THRSHV 0x0400 +#define SUNI1x10GEXP_BITMSK_RXOAM_HECE_THRSHV 0x0100 +#define SUNI1x10GEXP_BITMSK_RXOAM_RFV 0x0040 +#define SUNI1x10GEXP_BITMSK_RXOAM_LFV 0x0020 + +/*---------------------------------------------------------------------------- + * Register 0x2100: MSTAT Control + * Bit 2 MSTAT_WRITE + * Bit 1 MSTAT_CLEAR + * Bit 0 MSTAT_SNAP + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_MSTAT_WRITE 0x0004 +#define SUNI1x10GEXP_BITMSK_MSTAT_CLEAR 0x0002 +#define SUNI1x10GEXP_BITMSK_MSTAT_SNAP 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x2109: MSTAT Counter Write Address + * Bit 5-0 MSTAT_WRITE_ADDRESS + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_MSTAT_WRITE_ADDRESS 0x003F +#define SUNI1x10GEXP_BITOFF_MSTAT_WRITE_ADDRESS 0 + +/*---------------------------------------------------------------------------- + * Register 0x2200: IFLX Global Configuration Register + * Bit 15 IFLX_IRCU_ENABLE + * Bit 14 IFLX_IDSWT_ENABLE + * Bit 13-0 IFLX_IFD_CNT + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_IFLX_IRCU_ENABLE 0x8000 +#define SUNI1x10GEXP_BITMSK_IFLX_IDSWT_ENABLE 0x4000 +#define SUNI1x10GEXP_BITMSK_IFLX_IFD_CNT 0x3FFF +#define SUNI1x10GEXP_BITOFF_IFLX_IFD_CNT 0 + +/*---------------------------------------------------------------------------- + * Register 0x2209: IFLX FIFO Overflow Enable + * Bit 0 IFLX_OVFE + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_IFLX_OVFE 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x220A: IFLX FIFO Overflow Interrupt + * Bit 0 IFLX_OVFI + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_IFLX_OVFI 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x220D: IFLX Indirect Channel Address + * Bit 15 IFLX_BUSY + * Bit 14 IFLX_RWB + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_IFLX_BUSY 0x8000 +#define SUNI1x10GEXP_BITMSK_IFLX_RWB 0x4000 + +/*---------------------------------------------------------------------------- + * Register 0x220E: IFLX Indirect Logical FIFO Low Limit & Provision + * Bit 9-0 IFLX_LOLIM + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_IFLX_LOLIM 0x03FF +#define SUNI1x10GEXP_BITOFF_IFLX_LOLIM 0 + +/*---------------------------------------------------------------------------- + * Register 0x220F: IFLX Indirect Logical FIFO High Limit + * Bit 9-0 IFLX_HILIM + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_IFLX_HILIM 0x03FF +#define SUNI1x10GEXP_BITOFF_IFLX_HILIM 0 + +/*---------------------------------------------------------------------------- + * Register 0x2210: IFLX Indirect Full/Almost Full Status & Limit + * Bit 15 IFLX_FULL + * Bit 14 IFLX_AFULL + * Bit 13-0 IFLX_AFTH + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_IFLX_FULL 0x8000 +#define SUNI1x10GEXP_BITMSK_IFLX_AFULL 0x4000 +#define SUNI1x10GEXP_BITMSK_IFLX_AFTH 0x3FFF +#define SUNI1x10GEXP_BITOFF_IFLX_AFTH 0 + +/*---------------------------------------------------------------------------- + * Register 0x2211: IFLX Indirect Empty/Almost Empty Status & Limit + * Bit 15 IFLX_EMPTY + * Bit 14 IFLX_AEMPTY + * Bit 13-0 IFLX_AETH + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_IFLX_EMPTY 0x8000 +#define SUNI1x10GEXP_BITMSK_IFLX_AEMPTY 0x4000 +#define SUNI1x10GEXP_BITMSK_IFLX_AETH 0x3FFF +#define SUNI1x10GEXP_BITOFF_IFLX_AETH 0 + +/*---------------------------------------------------------------------------- + * Register 0x2240: PL4MOS Configuration Register + * Bit 3 PL4MOS_RE_INIT + * Bit 2 PL4MOS_EN + * Bit 1 PL4MOS_NO_STATUS + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_PL4MOS_RE_INIT 0x0008 +#define SUNI1x10GEXP_BITMSK_PL4MOS_EN 0x0004 +#define SUNI1x10GEXP_BITMSK_PL4MOS_NO_STATUS 0x0002 + +/*---------------------------------------------------------------------------- + * Register 0x2243: PL4MOS MaxBurst1 Register + * Bit 11-0 PL4MOS_MAX_BURST1 + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_PL4MOS_MAX_BURST1 0x0FFF +#define SUNI1x10GEXP_BITOFF_PL4MOS_MAX_BURST1 0 + +/*---------------------------------------------------------------------------- + * Register 0x2244: PL4MOS MaxBurst2 Register + * Bit 11-0 PL4MOS_MAX_BURST2 + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_PL4MOS_MAX_BURST2 0x0FFF +#define SUNI1x10GEXP_BITOFF_PL4MOS_MAX_BURST2 0 + +/*---------------------------------------------------------------------------- + * Register 0x2245: PL4MOS Transfer Size Register + * Bit 7-0 PL4MOS_MAX_TRANSFER + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_PL4MOS_MAX_TRANSFER 0x00FF +#define SUNI1x10GEXP_BITOFF_PL4MOS_MAX_TRANSFER 0 + +/*---------------------------------------------------------------------------- + * Register 0x2280: PL4ODP Configuration + * Bit 15-12 PL4ODP_REPEAT_T + * Bit 8 PL4ODP_SOP_RULE + * Bit 1 PL4ODP_EN_PORTS + * Bit 0 PL4ODP_EN_DFWD + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_PL4ODP_REPEAT_T 0xF000 +#define SUNI1x10GEXP_BITOFF_PL4ODP_REPEAT_T 12 +#define SUNI1x10GEXP_BITMSK_PL4ODP_SOP_RULE 0x0100 +#define SUNI1x10GEXP_BITMSK_PL4ODP_EN_PORTS 0x0002 +#define SUNI1x10GEXP_BITMSK_PL4ODP_EN_DFWD 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x2282: PL4ODP Interrupt Mask + * Bit 0 PL4ODP_OUT_DISE + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_PL4ODP_OUT_DISE 0x0001 + + + +#define SUNI1x10GEXP_BITMSK_PL4ODP_PPE_EOPEOBE 0x0080 +#define SUNI1x10GEXP_BITMSK_PL4ODP_PPE_ERREOPE 0x0040 +#define SUNI1x10GEXP_BITMSK_PL4ODP_PPE_MEOPE 0x0008 +#define SUNI1x10GEXP_BITMSK_PL4ODP_PPE_MSOPE 0x0004 +#define SUNI1x10GEXP_BITMSK_PL4ODP_ES_OVRE 0x0002 + + +/*---------------------------------------------------------------------------- + * Register 0x2283: PL4ODP Interrupt + * Bit 0 PL4ODP_OUT_DISI + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_PL4ODP_OUT_DISI 0x0001 + + + +#define SUNI1x10GEXP_BITMSK_PL4ODP_PPE_EOPEOBI 0x0080 +#define SUNI1x10GEXP_BITMSK_PL4ODP_PPE_ERREOPI 0x0040 +#define SUNI1x10GEXP_BITMSK_PL4ODP_PPE_MEOPI 0x0008 +#define SUNI1x10GEXP_BITMSK_PL4ODP_PPE_MSOPI 0x0004 +#define SUNI1x10GEXP_BITMSK_PL4ODP_ES_OVRI 0x0002 + +/*---------------------------------------------------------------------------- + * Register 0x2300: PL4IO Lock Detect Status + * Bit 15 PL4IO_OUT_ROOLV + * Bit 12 PL4IO_IS_ROOLV + * Bit 11 PL4IO_DIP2_ERRV + * Bit 8 PL4IO_ID_ROOLV + * Bit 4 PL4IO_IS_DOOLV + * Bit 0 PL4IO_ID_DOOLV + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_PL4IO_OUT_ROOLV 0x8000 +#define SUNI1x10GEXP_BITMSK_PL4IO_IS_ROOLV 0x1000 +#define SUNI1x10GEXP_BITMSK_PL4IO_DIP2_ERRV 0x0800 +#define SUNI1x10GEXP_BITMSK_PL4IO_ID_ROOLV 0x0100 +#define SUNI1x10GEXP_BITMSK_PL4IO_IS_DOOLV 0x0010 +#define SUNI1x10GEXP_BITMSK_PL4IO_ID_DOOLV 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x2301: PL4IO Lock Detect Change + * Bit 15 PL4IO_OUT_ROOLI + * Bit 12 PL4IO_IS_ROOLI + * Bit 11 PL4IO_DIP2_ERRI + * Bit 8 PL4IO_ID_ROOLI + * Bit 4 PL4IO_IS_DOOLI + * Bit 0 PL4IO_ID_DOOLI + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_PL4IO_OUT_ROOLI 0x8000 +#define SUNI1x10GEXP_BITMSK_PL4IO_IS_ROOLI 0x1000 +#define SUNI1x10GEXP_BITMSK_PL4IO_DIP2_ERRI 0x0800 +#define SUNI1x10GEXP_BITMSK_PL4IO_ID_ROOLI 0x0100 +#define SUNI1x10GEXP_BITMSK_PL4IO_IS_DOOLI 0x0010 +#define SUNI1x10GEXP_BITMSK_PL4IO_ID_DOOLI 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x2302: PL4IO Lock Detect Mask + * Bit 15 PL4IO_OUT_ROOLE + * Bit 12 PL4IO_IS_ROOLE + * Bit 11 PL4IO_DIP2_ERRE + * Bit 8 PL4IO_ID_ROOLE + * Bit 4 PL4IO_IS_DOOLE + * Bit 0 PL4IO_ID_DOOLE + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_PL4IO_OUT_ROOLE 0x8000 +#define SUNI1x10GEXP_BITMSK_PL4IO_IS_ROOLE 0x1000 +#define SUNI1x10GEXP_BITMSK_PL4IO_DIP2_ERRE 0x0800 +#define SUNI1x10GEXP_BITMSK_PL4IO_ID_ROOLE 0x0100 +#define SUNI1x10GEXP_BITMSK_PL4IO_IS_DOOLE 0x0010 +#define SUNI1x10GEXP_BITMSK_PL4IO_ID_DOOLE 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x2303: PL4IO Lock Detect Limits + * Bit 15-8 PL4IO_REF_LIMIT + * Bit 7-0 PL4IO_TRAN_LIMIT + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_PL4IO_REF_LIMIT 0xFF00 +#define SUNI1x10GEXP_BITOFF_PL4IO_REF_LIMIT 8 +#define SUNI1x10GEXP_BITMSK_PL4IO_TRAN_LIMIT 0x00FF +#define SUNI1x10GEXP_BITOFF_PL4IO_TRAN_LIMIT 0 + +/*---------------------------------------------------------------------------- + * Register 0x2304: PL4IO Calendar Repetitions + * Bit 15-8 PL4IO_IN_MUL + * Bit 7-0 PL4IO_OUT_MUL + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_PL4IO_IN_MUL 0xFF00 +#define SUNI1x10GEXP_BITOFF_PL4IO_IN_MUL 8 +#define SUNI1x10GEXP_BITMSK_PL4IO_OUT_MUL 0x00FF +#define SUNI1x10GEXP_BITOFF_PL4IO_OUT_MUL 0 + +/*---------------------------------------------------------------------------- + * Register 0x2305: PL4IO Configuration + * Bit 15 PL4IO_DIP2_ERR_CHK + * Bit 11 PL4IO_ODAT_DIS + * Bit 10 PL4IO_TRAIN_DIS + * Bit 9 PL4IO_OSTAT_DIS + * Bit 8 PL4IO_ISTAT_DIS + * Bit 7 PL4IO_NO_ISTAT + * Bit 6 PL4IO_STAT_OUTSEL + * Bit 5 PL4IO_INSEL + * Bit 4 PL4IO_DLSEL + * Bit 1-0 PL4IO_OUTSEL + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_PL4IO_DIP2_ERR_CHK 0x8000 +#define SUNI1x10GEXP_BITMSK_PL4IO_ODAT_DIS 0x0800 +#define SUNI1x10GEXP_BITMSK_PL4IO_TRAIN_DIS 0x0400 +#define SUNI1x10GEXP_BITMSK_PL4IO_OSTAT_DIS 0x0200 +#define SUNI1x10GEXP_BITMSK_PL4IO_ISTAT_DIS 0x0100 +#define SUNI1x10GEXP_BITMSK_PL4IO_NO_ISTAT 0x0080 +#define SUNI1x10GEXP_BITMSK_PL4IO_STAT_OUTSEL 0x0040 +#define SUNI1x10GEXP_BITMSK_PL4IO_INSEL 0x0020 +#define SUNI1x10GEXP_BITMSK_PL4IO_DLSEL 0x0010 +#define SUNI1x10GEXP_BITMSK_PL4IO_OUTSEL 0x0003 +#define SUNI1x10GEXP_BITOFF_PL4IO_OUTSEL 0 + +/*---------------------------------------------------------------------------- + * Register 0x3040: TXXG Configuration Register 1 + * Bit 15 TXXG_TXEN0 + * Bit 13 TXXG_HOSTPAUSE + * Bit 12-7 TXXG_IPGT + * Bit 5 TXXG_32BIT_ALIGN + * Bit 4 TXXG_CRCEN + * Bit 3 TXXG_FCTX + * Bit 2 TXXG_FCRX + * Bit 1 TXXG_PADEN + * Bit 0 TXXG_SPRE + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_TXXG_TXEN0 0x8000 +#define SUNI1x10GEXP_BITMSK_TXXG_HOSTPAUSE 0x2000 +#define SUNI1x10GEXP_BITMSK_TXXG_IPGT 0x1F80 +#define SUNI1x10GEXP_BITOFF_TXXG_IPGT 7 +#define SUNI1x10GEXP_BITMSK_TXXG_32BIT_ALIGN 0x0020 +#define SUNI1x10GEXP_BITMSK_TXXG_CRCEN 0x0010 +#define SUNI1x10GEXP_BITMSK_TXXG_FCTX 0x0008 +#define SUNI1x10GEXP_BITMSK_TXXG_FCRX 0x0004 +#define SUNI1x10GEXP_BITMSK_TXXG_PADEN 0x0002 +#define SUNI1x10GEXP_BITMSK_TXXG_SPRE 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x3041: TXXG Configuration Register 2 + * Bit 7-0 TXXG_HDRSIZE + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_TXXG_HDRSIZE 0x00FF + +/*---------------------------------------------------------------------------- + * Register 0x3042: TXXG Configuration Register 3 + * Bit 15 TXXG_FIFO_ERRE + * Bit 14 TXXG_FIFO_UDRE + * Bit 13 TXXG_MAX_LERRE + * Bit 12 TXXG_MIN_LERRE + * Bit 11 TXXG_XFERE + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_TXXG_FIFO_ERRE 0x8000 +#define SUNI1x10GEXP_BITMSK_TXXG_FIFO_UDRE 0x4000 +#define SUNI1x10GEXP_BITMSK_TXXG_MAX_LERRE 0x2000 +#define SUNI1x10GEXP_BITMSK_TXXG_MIN_LERRE 0x1000 +#define SUNI1x10GEXP_BITMSK_TXXG_XFERE 0x0800 + +/*---------------------------------------------------------------------------- + * Register 0x3043: TXXG Interrupt + * Bit 15 TXXG_FIFO_ERRI + * Bit 14 TXXG_FIFO_UDRI + * Bit 13 TXXG_MAX_LERRI + * Bit 12 TXXG_MIN_LERRI + * Bit 11 TXXG_XFERI + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_TXXG_FIFO_ERRI 0x8000 +#define SUNI1x10GEXP_BITMSK_TXXG_FIFO_UDRI 0x4000 +#define SUNI1x10GEXP_BITMSK_TXXG_MAX_LERRI 0x2000 +#define SUNI1x10GEXP_BITMSK_TXXG_MIN_LERRI 0x1000 +#define SUNI1x10GEXP_BITMSK_TXXG_XFERI 0x0800 + +/*---------------------------------------------------------------------------- + * Register 0x3044: TXXG Status Register + * Bit 1 TXXG_TXACTIVE + * Bit 0 TXXG_PAUSED + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_TXXG_TXACTIVE 0x0002 +#define SUNI1x10GEXP_BITMSK_TXXG_PAUSED 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x3046: TXXG TX_MINFR - Transmit Min Frame Size Register + * Bit 7-0 TXXG_TX_MINFR + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_TXXG_TX_MINFR 0x00FF +#define SUNI1x10GEXP_BITOFF_TXXG_TX_MINFR 0 + +/*---------------------------------------------------------------------------- + * Register 0x3052: TXXG Pause Quantum Value Configuration Register + * Bit 7-0 TXXG_FC_PAUSE_QNTM + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_TXXG_FC_PAUSE_QNTM 0x00FF +#define SUNI1x10GEXP_BITOFF_TXXG_FC_PAUSE_QNTM 0 + +/*---------------------------------------------------------------------------- + * Register 0x3080: XTEF Control + * Bit 3-0 XTEF_FORCE_PARITY_ERR + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_XTEF_FORCE_PARITY_ERR 0x000F +#define SUNI1x10GEXP_BITOFF_XTEF_FORCE_PARITY_ERR 0 + +/*---------------------------------------------------------------------------- + * Register 0x3084: XTEF Interrupt Event Register + * Bit 0 XTEF_LOST_SYNCI + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_XTEF_LOST_SYNCI 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x3085: XTEF Interrupt Enable Register + * Bit 0 XTEF_LOST_SYNCE + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_XTEF_LOST_SYNCE 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x3086: XTEF Visibility Register + * Bit 0 XTEF_LOST_SYNCV + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_XTEF_LOST_SYNCV 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x30C0: TXOAM OAM Configuration + * Bit 15 TXOAM_HEC_EN + * Bit 14 TXOAM_EMPTYCODE_EN + * Bit 13 TXOAM_FORCE_IDLE + * Bit 12 TXOAM_IGNORE_IDLE + * Bit 11-6 TXOAM_PX_OVERWRITE + * Bit 5-0 TXOAM_PX_SEL + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_TXOAM_HEC_EN 0x8000 +#define SUNI1x10GEXP_BITMSK_TXOAM_EMPTYCODE_EN 0x4000 +#define SUNI1x10GEXP_BITMSK_TXOAM_FORCE_IDLE 0x2000 +#define SUNI1x10GEXP_BITMSK_TXOAM_IGNORE_IDLE 0x1000 +#define SUNI1x10GEXP_BITMSK_TXOAM_PX_OVERWRITE 0x0FC0 +#define SUNI1x10GEXP_BITOFF_TXOAM_PX_OVERWRITE 6 +#define SUNI1x10GEXP_BITMSK_TXOAM_PX_SEL 0x003F +#define SUNI1x10GEXP_BITOFF_TXOAM_PX_SEL 0 + +/*---------------------------------------------------------------------------- + * Register 0x30C1: TXOAM Mini-Packet Rate Configuration + * Bit 15 TXOAM_MINIDIS + * Bit 14 TXOAM_BUSY + * Bit 13 TXOAM_TRANS_EN + * Bit 10-0 TXOAM_MINIRATE + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_TXOAM_MINIDIS 0x8000 +#define SUNI1x10GEXP_BITMSK_TXOAM_BUSY 0x4000 +#define SUNI1x10GEXP_BITMSK_TXOAM_TRANS_EN 0x2000 +#define SUNI1x10GEXP_BITMSK_TXOAM_MINIRATE 0x07FF + +/*---------------------------------------------------------------------------- + * Register 0x30C2: TXOAM Mini-Packet Gap and FIFO Configuration + * Bit 13-10 TXOAM_FTHRESH + * Bit 9-6 TXOAM_MINIPOST + * Bit 5-0 TXOAM_MINIPRE + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_TXOAM_FTHRESH 0x3C00 +#define SUNI1x10GEXP_BITOFF_TXOAM_FTHRESH 10 +#define SUNI1x10GEXP_BITMSK_TXOAM_MINIPOST 0x03C0 +#define SUNI1x10GEXP_BITOFF_TXOAM_MINIPOST 6 +#define SUNI1x10GEXP_BITMSK_TXOAM_MINIPRE 0x003F + +/*---------------------------------------------------------------------------- + * Register 0x30C6: TXOAM Interrupt Enable + * Bit 2 TXOAM_SOP_ERRE + * Bit 1 TXOAM_OFLE + * Bit 0 TXOAM_ERRE + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_TXOAM_SOP_ERRE 0x0004 +#define SUNI1x10GEXP_BITMSK_TXOAM_OFLE 0x0002 +#define SUNI1x10GEXP_BITMSK_TXOAM_ERRE 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x30C7: TXOAM Interrupt Status + * Bit 2 TXOAM_SOP_ERRI + * Bit 1 TXOAM_OFLI + * Bit 0 TXOAM_ERRI + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_TXOAM_SOP_ERRI 0x0004 +#define SUNI1x10GEXP_BITMSK_TXOAM_OFLI 0x0002 +#define SUNI1x10GEXP_BITMSK_TXOAM_ERRI 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x30CF: TXOAM Coset + * Bit 7-0 TXOAM_COSET + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_TXOAM_COSET 0x00FF + +/*---------------------------------------------------------------------------- + * Register 0x3200: EFLX Global Configuration + * Bit 15 EFLX_ERCU_EN + * Bit 7 EFLX_EN_EDSWT + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_EFLX_ERCU_EN 0x8000 +#define SUNI1x10GEXP_BITMSK_EFLX_EN_EDSWT 0x0080 + +/*---------------------------------------------------------------------------- + * Register 0x3201: EFLX ERCU Global Status + * Bit 13 EFLX_OVF_ERR + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_EFLX_OVF_ERR 0x2000 + +/*---------------------------------------------------------------------------- + * Register 0x3202: EFLX Indirect Channel Address + * Bit 15 EFLX_BUSY + * Bit 14 EFLX_RDWRB + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_EFLX_BUSY 0x8000 +#define SUNI1x10GEXP_BITMSK_EFLX_RDWRB 0x4000 + +/*---------------------------------------------------------------------------- + * Register 0x3203: EFLX Indirect Logical FIFO Low Limit + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_EFLX_LOLIM 0x03FF +#define SUNI1x10GEXP_BITOFF_EFLX_LOLIM 0 + +/*---------------------------------------------------------------------------- + * Register 0x3204: EFLX Indirect Logical FIFO High Limit + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_EFLX_HILIM 0x03FF +#define SUNI1x10GEXP_BITOFF_EFLX_HILIM 0 + +/*---------------------------------------------------------------------------- + * Register 0x3205: EFLX Indirect Full/Almost-Full Status and Limit + * Bit 15 EFLX_FULL + * Bit 14 EFLX_AFULL + * Bit 13-0 EFLX_AFTH + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_EFLX_FULL 0x8000 +#define SUNI1x10GEXP_BITMSK_EFLX_AFULL 0x4000 +#define SUNI1x10GEXP_BITMSK_EFLX_AFTH 0x3FFF +#define SUNI1x10GEXP_BITOFF_EFLX_AFTH 0 + +/*---------------------------------------------------------------------------- + * Register 0x3206: EFLX Indirect Empty/Almost-Empty Status and Limit + * Bit 15 EFLX_EMPTY + * Bit 14 EFLX_AEMPTY + * Bit 13-0 EFLX_AETH + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_EFLX_EMPTY 0x8000 +#define SUNI1x10GEXP_BITMSK_EFLX_AEMPTY 0x4000 +#define SUNI1x10GEXP_BITMSK_EFLX_AETH 0x3FFF +#define SUNI1x10GEXP_BITOFF_EFLX_AETH 0 + +/*---------------------------------------------------------------------------- + * Register 0x3207: EFLX Indirect FIFO Cut-Through Threshold + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_EFLX_CUT_THRU 0x3FFF +#define SUNI1x10GEXP_BITOFF_EFLX_CUT_THRU 0 + +/*---------------------------------------------------------------------------- + * Register 0x320C: EFLX FIFO Overflow Error Enable + * Bit 0 EFLX_OVFE + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_EFLX_OVFE 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x320D: EFLX FIFO Overflow Error Indication + * Bit 0 EFLX_OVFI + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_EFLX_OVFI 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x3210: EFLX Channel Provision + * Bit 0 EFLX_PROV + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_EFLX_PROV 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x3280: PL4IDU Configuration + * Bit 2 PL4IDU_SYNCH_ON_TRAIN + * Bit 1 PL4IDU_EN_PORTS + * Bit 0 PL4IDU_EN_DFWD + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_PL4IDU_SYNCH_ON_TRAIN 0x0004 +#define SUNI1x10GEXP_BITMSK_PL4IDU_EN_PORTS 0x0002 +#define SUNI1x10GEXP_BITMSK_PL4IDU_EN_DFWD 0x0001 + +/*---------------------------------------------------------------------------- + * Register 0x3282: PL4IDU Interrupt Mask + * Bit 1 PL4IDU_DIP4E + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_PL4IDU_DIP4E 0x0002 + +/*---------------------------------------------------------------------------- + * Register 0x3283: PL4IDU Interrupt + * Bit 1 PL4IDU_DIP4I + *----------------------------------------------------------------------------*/ +#define SUNI1x10GEXP_BITMSK_PL4IDU_DIP4I 0x0002 + +#endif /* _CXGB_SUNI1x10GEXP_REGS_H_ */ + diff --git a/drivers/net/ethernet/chelsio/cxgb/tp.c b/drivers/net/ethernet/chelsio/cxgb/tp.c new file mode 100644 index 000000000000..8bed4a59e65f --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb/tp.c @@ -0,0 +1,171 @@ +/* $Date: 2006/02/07 04:21:54 $ $RCSfile: tp.c,v $ $Revision: 1.73 $ */ +#include "common.h" +#include "regs.h" +#include "tp.h" +#ifdef CONFIG_CHELSIO_T1_1G +#include "fpga_defs.h" +#endif + +struct petp { + adapter_t *adapter; +}; + +/* Pause deadlock avoidance parameters */ +#define DROP_MSEC 16 +#define DROP_PKTS_CNT 1 + +static void tp_init(adapter_t * ap, const struct tp_params *p, + unsigned int tp_clk) +{ + u32 val; + + if (!t1_is_asic(ap)) + return; + + val = F_TP_IN_CSPI_CPL | F_TP_IN_CSPI_CHECK_IP_CSUM | + F_TP_IN_CSPI_CHECK_TCP_CSUM | F_TP_IN_ESPI_ETHERNET; + if (!p->pm_size) + val |= F_OFFLOAD_DISABLE; + else + val |= F_TP_IN_ESPI_CHECK_IP_CSUM | F_TP_IN_ESPI_CHECK_TCP_CSUM; + writel(val, ap->regs + A_TP_IN_CONFIG); + writel(F_TP_OUT_CSPI_CPL | + F_TP_OUT_ESPI_ETHERNET | + F_TP_OUT_ESPI_GENERATE_IP_CSUM | + F_TP_OUT_ESPI_GENERATE_TCP_CSUM, ap->regs + A_TP_OUT_CONFIG); + writel(V_IP_TTL(64) | + F_PATH_MTU /* IP DF bit */ | + V_5TUPLE_LOOKUP(p->use_5tuple_mode) | + V_SYN_COOKIE_PARAMETER(29), ap->regs + A_TP_GLOBAL_CONFIG); + /* + * Enable pause frame deadlock prevention. + */ + if (is_T2(ap) && ap->params.nports > 1) { + u32 drop_ticks = DROP_MSEC * (tp_clk / 1000); + + writel(F_ENABLE_TX_DROP | F_ENABLE_TX_ERROR | + V_DROP_TICKS_CNT(drop_ticks) | + V_NUM_PKTS_DROPPED(DROP_PKTS_CNT), + ap->regs + A_TP_TX_DROP_CONFIG); + } +} + +void t1_tp_destroy(struct petp *tp) +{ + kfree(tp); +} + +struct petp *__devinit t1_tp_create(adapter_t * adapter, struct tp_params *p) +{ + struct petp *tp = kzalloc(sizeof(*tp), GFP_KERNEL); + + if (!tp) + return NULL; + + tp->adapter = adapter; + + return tp; +} + +void t1_tp_intr_enable(struct petp *tp) +{ + u32 tp_intr = readl(tp->adapter->regs + A_PL_ENABLE); + +#ifdef CONFIG_CHELSIO_T1_1G + if (!t1_is_asic(tp->adapter)) { + /* FPGA */ + writel(0xffffffff, + tp->adapter->regs + FPGA_TP_ADDR_INTERRUPT_ENABLE); + writel(tp_intr | FPGA_PCIX_INTERRUPT_TP, + tp->adapter->regs + A_PL_ENABLE); + } else +#endif + { + /* We don't use any TP interrupts */ + writel(0, tp->adapter->regs + A_TP_INT_ENABLE); + writel(tp_intr | F_PL_INTR_TP, + tp->adapter->regs + A_PL_ENABLE); + } +} + +void t1_tp_intr_disable(struct petp *tp) +{ + u32 tp_intr = readl(tp->adapter->regs + A_PL_ENABLE); + +#ifdef CONFIG_CHELSIO_T1_1G + if (!t1_is_asic(tp->adapter)) { + /* FPGA */ + writel(0, tp->adapter->regs + FPGA_TP_ADDR_INTERRUPT_ENABLE); + writel(tp_intr & ~FPGA_PCIX_INTERRUPT_TP, + tp->adapter->regs + A_PL_ENABLE); + } else +#endif + { + writel(0, tp->adapter->regs + A_TP_INT_ENABLE); + writel(tp_intr & ~F_PL_INTR_TP, + tp->adapter->regs + A_PL_ENABLE); + } +} + +void t1_tp_intr_clear(struct petp *tp) +{ +#ifdef CONFIG_CHELSIO_T1_1G + if (!t1_is_asic(tp->adapter)) { + writel(0xffffffff, + tp->adapter->regs + FPGA_TP_ADDR_INTERRUPT_CAUSE); + writel(FPGA_PCIX_INTERRUPT_TP, tp->adapter->regs + A_PL_CAUSE); + return; + } +#endif + writel(0xffffffff, tp->adapter->regs + A_TP_INT_CAUSE); + writel(F_PL_INTR_TP, tp->adapter->regs + A_PL_CAUSE); +} + +int t1_tp_intr_handler(struct petp *tp) +{ + u32 cause; + +#ifdef CONFIG_CHELSIO_T1_1G + /* FPGA doesn't support TP interrupts. */ + if (!t1_is_asic(tp->adapter)) + return 1; +#endif + + cause = readl(tp->adapter->regs + A_TP_INT_CAUSE); + writel(cause, tp->adapter->regs + A_TP_INT_CAUSE); + return 0; +} + +static void set_csum_offload(struct petp *tp, u32 csum_bit, int enable) +{ + u32 val = readl(tp->adapter->regs + A_TP_GLOBAL_CONFIG); + + if (enable) + val |= csum_bit; + else + val &= ~csum_bit; + writel(val, tp->adapter->regs + A_TP_GLOBAL_CONFIG); +} + +void t1_tp_set_ip_checksum_offload(struct petp *tp, int enable) +{ + set_csum_offload(tp, F_IP_CSUM, enable); +} + +void t1_tp_set_tcp_checksum_offload(struct petp *tp, int enable) +{ + set_csum_offload(tp, F_TCP_CSUM, enable); +} + +/* + * Initialize TP state. tp_params contains initial settings for some TP + * parameters, particularly the one-time PM and CM settings. + */ +int t1_tp_reset(struct petp *tp, struct tp_params *p, unsigned int tp_clk) +{ + adapter_t *adapter = tp->adapter; + + tp_init(adapter, p, tp_clk); + writel(F_TP_RESET, adapter->regs + A_TP_RESET); + return 0; +} diff --git a/drivers/net/ethernet/chelsio/cxgb/tp.h b/drivers/net/ethernet/chelsio/cxgb/tp.h new file mode 100644 index 000000000000..dfd8ce25106a --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb/tp.h @@ -0,0 +1,72 @@ +/* $Date: 2005/03/07 23:59:05 $ $RCSfile: tp.h,v $ $Revision: 1.20 $ */ +#ifndef CHELSIO_TP_H +#define CHELSIO_TP_H + +#include "common.h" + +#define TP_MAX_RX_COALESCING_SIZE 16224U + +struct tp_mib_statistics { + + /* IP */ + u32 ipInReceive_hi; + u32 ipInReceive_lo; + u32 ipInHdrErrors_hi; + u32 ipInHdrErrors_lo; + u32 ipInAddrErrors_hi; + u32 ipInAddrErrors_lo; + u32 ipInUnknownProtos_hi; + u32 ipInUnknownProtos_lo; + u32 ipInDiscards_hi; + u32 ipInDiscards_lo; + u32 ipInDelivers_hi; + u32 ipInDelivers_lo; + u32 ipOutRequests_hi; + u32 ipOutRequests_lo; + u32 ipOutDiscards_hi; + u32 ipOutDiscards_lo; + u32 ipOutNoRoutes_hi; + u32 ipOutNoRoutes_lo; + u32 ipReasmTimeout; + u32 ipReasmReqds; + u32 ipReasmOKs; + u32 ipReasmFails; + + u32 reserved[8]; + + /* TCP */ + u32 tcpActiveOpens; + u32 tcpPassiveOpens; + u32 tcpAttemptFails; + u32 tcpEstabResets; + u32 tcpOutRsts; + u32 tcpCurrEstab; + u32 tcpInSegs_hi; + u32 tcpInSegs_lo; + u32 tcpOutSegs_hi; + u32 tcpOutSegs_lo; + u32 tcpRetransSeg_hi; + u32 tcpRetransSeg_lo; + u32 tcpInErrs_hi; + u32 tcpInErrs_lo; + u32 tcpRtoMin; + u32 tcpRtoMax; +}; + +struct petp; +struct tp_params; + +struct petp *t1_tp_create(adapter_t *adapter, struct tp_params *p); +void t1_tp_destroy(struct petp *tp); + +void t1_tp_intr_disable(struct petp *tp); +void t1_tp_intr_enable(struct petp *tp); +void t1_tp_intr_clear(struct petp *tp); +int t1_tp_intr_handler(struct petp *tp); + +void t1_tp_get_mib_statistics(adapter_t *adap, struct tp_mib_statistics *tps); +void t1_tp_set_tcp_checksum_offload(struct petp *tp, int enable); +void t1_tp_set_ip_checksum_offload(struct petp *tp, int enable); +int t1_tp_set_coalescing_size(struct petp *tp, unsigned int size); +int t1_tp_reset(struct petp *tp, struct tp_params *p, unsigned int tp_clk); +#endif diff --git a/drivers/net/ethernet/chelsio/cxgb/vsc7326.c b/drivers/net/ethernet/chelsio/cxgb/vsc7326.c new file mode 100644 index 000000000000..b0cb388f5e12 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb/vsc7326.c @@ -0,0 +1,730 @@ +/* $Date: 2006/04/28 19:20:06 $ $RCSfile: vsc7326.c,v $ $Revision: 1.19 $ */ + +/* Driver for Vitesse VSC7326 (Schaumburg) MAC */ + +#include "gmac.h" +#include "elmer0.h" +#include "vsc7326_reg.h" + +/* Update fast changing statistics every 15 seconds */ +#define STATS_TICK_SECS 15 +/* 30 minutes for full statistics update */ +#define MAJOR_UPDATE_TICKS (1800 / STATS_TICK_SECS) + +#define MAX_MTU 9600 + +/* The egress WM value 0x01a01fff should be used only when the + * interface is down (MAC port disabled). This is a workaround + * for disabling the T2/MAC flow-control. When the interface is + * enabled, the WM value should be set to 0x014a03F0. + */ +#define WM_DISABLE 0x01a01fff +#define WM_ENABLE 0x014a03F0 + +struct init_table { + u32 addr; + u32 data; +}; + +struct _cmac_instance { + u32 index; + u32 ticks; +}; + +#define INITBLOCK_SLEEP 0xffffffff + +static void vsc_read(adapter_t *adapter, u32 addr, u32 *val) +{ + u32 status, vlo, vhi; + int i; + + spin_lock_bh(&adapter->mac_lock); + t1_tpi_read(adapter, (addr << 2) + 4, &vlo); + i = 0; + do { + t1_tpi_read(adapter, (REG_LOCAL_STATUS << 2) + 4, &vlo); + t1_tpi_read(adapter, REG_LOCAL_STATUS << 2, &vhi); + status = (vhi << 16) | vlo; + i++; + } while (((status & 1) == 0) && (i < 50)); + if (i == 50) + pr_err("Invalid tpi read from MAC, breaking loop.\n"); + + t1_tpi_read(adapter, (REG_LOCAL_DATA << 2) + 4, &vlo); + t1_tpi_read(adapter, REG_LOCAL_DATA << 2, &vhi); + + *val = (vhi << 16) | vlo; + + /* pr_err("rd: block: 0x%x sublock: 0x%x reg: 0x%x data: 0x%x\n", + ((addr&0xe000)>>13), ((addr&0x1e00)>>9), + ((addr&0x01fe)>>1), *val); */ + spin_unlock_bh(&adapter->mac_lock); +} + +static void vsc_write(adapter_t *adapter, u32 addr, u32 data) +{ + spin_lock_bh(&adapter->mac_lock); + t1_tpi_write(adapter, (addr << 2) + 4, data & 0xFFFF); + t1_tpi_write(adapter, addr << 2, (data >> 16) & 0xFFFF); + /* pr_err("wr: block: 0x%x sublock: 0x%x reg: 0x%x data: 0x%x\n", + ((addr&0xe000)>>13), ((addr&0x1e00)>>9), + ((addr&0x01fe)>>1), data); */ + spin_unlock_bh(&adapter->mac_lock); +} + +/* Hard reset the MAC. This wipes out *all* configuration. */ +static void vsc7326_full_reset(adapter_t* adapter) +{ + u32 val; + u32 result = 0xffff; + + t1_tpi_read(adapter, A_ELMER0_GPO, &val); + val &= ~1; + t1_tpi_write(adapter, A_ELMER0_GPO, val); + udelay(2); + val |= 0x1; /* Enable mac MAC itself */ + val |= 0x800; /* Turn off the red LED */ + t1_tpi_write(adapter, A_ELMER0_GPO, val); + mdelay(1); + vsc_write(adapter, REG_SW_RESET, 0x80000001); + do { + mdelay(1); + vsc_read(adapter, REG_SW_RESET, &result); + } while (result != 0x0); +} + +static struct init_table vsc7326_reset[] = { + { REG_IFACE_MODE, 0x00000000 }, + { REG_CRC_CFG, 0x00000020 }, + { REG_PLL_CLK_SPEED, 0x00050c00 }, + { REG_PLL_CLK_SPEED, 0x00050c00 }, + { REG_MSCH, 0x00002f14 }, + { REG_SPI4_MISC, 0x00040409 }, + { REG_SPI4_DESKEW, 0x00080000 }, + { REG_SPI4_ING_SETUP2, 0x08080004 }, + { REG_SPI4_ING_SETUP0, 0x04111004 }, + { REG_SPI4_EGR_SETUP0, 0x80001a04 }, + { REG_SPI4_ING_SETUP1, 0x02010000 }, + { REG_AGE_INC(0), 0x00000000 }, + { REG_AGE_INC(1), 0x00000000 }, + { REG_ING_CONTROL, 0x0a200011 }, + { REG_EGR_CONTROL, 0xa0010091 }, +}; + +static struct init_table vsc7326_portinit[4][22] = { + { /* Port 0 */ + /* FIFO setup */ + { REG_DBG(0), 0x000004f0 }, + { REG_HDX(0), 0x00073101 }, + { REG_TEST(0,0), 0x00000022 }, + { REG_TEST(1,0), 0x00000022 }, + { REG_TOP_BOTTOM(0,0), 0x003f0000 }, + { REG_TOP_BOTTOM(1,0), 0x00120000 }, + { REG_HIGH_LOW_WM(0,0), 0x07460757 }, + { REG_HIGH_LOW_WM(1,0), WM_DISABLE }, + { REG_CT_THRHLD(0,0), 0x00000000 }, + { REG_CT_THRHLD(1,0), 0x00000000 }, + { REG_BUCKE(0), 0x0002ffff }, + { REG_BUCKI(0), 0x0002ffff }, + { REG_TEST(0,0), 0x00000020 }, + { REG_TEST(1,0), 0x00000020 }, + /* Port config */ + { REG_MAX_LEN(0), 0x00002710 }, + { REG_PORT_FAIL(0), 0x00000002 }, + { REG_NORMALIZER(0), 0x00000a64 }, + { REG_DENORM(0), 0x00000010 }, + { REG_STICK_BIT(0), 0x03baa370 }, + { REG_DEV_SETUP(0), 0x00000083 }, + { REG_DEV_SETUP(0), 0x00000082 }, + { REG_MODE_CFG(0), 0x0200259f }, + }, + { /* Port 1 */ + /* FIFO setup */ + { REG_DBG(1), 0x000004f0 }, + { REG_HDX(1), 0x00073101 }, + { REG_TEST(0,1), 0x00000022 }, + { REG_TEST(1,1), 0x00000022 }, + { REG_TOP_BOTTOM(0,1), 0x007e003f }, + { REG_TOP_BOTTOM(1,1), 0x00240012 }, + { REG_HIGH_LOW_WM(0,1), 0x07460757 }, + { REG_HIGH_LOW_WM(1,1), WM_DISABLE }, + { REG_CT_THRHLD(0,1), 0x00000000 }, + { REG_CT_THRHLD(1,1), 0x00000000 }, + { REG_BUCKE(1), 0x0002ffff }, + { REG_BUCKI(1), 0x0002ffff }, + { REG_TEST(0,1), 0x00000020 }, + { REG_TEST(1,1), 0x00000020 }, + /* Port config */ + { REG_MAX_LEN(1), 0x00002710 }, + { REG_PORT_FAIL(1), 0x00000002 }, + { REG_NORMALIZER(1), 0x00000a64 }, + { REG_DENORM(1), 0x00000010 }, + { REG_STICK_BIT(1), 0x03baa370 }, + { REG_DEV_SETUP(1), 0x00000083 }, + { REG_DEV_SETUP(1), 0x00000082 }, + { REG_MODE_CFG(1), 0x0200259f }, + }, + { /* Port 2 */ + /* FIFO setup */ + { REG_DBG(2), 0x000004f0 }, + { REG_HDX(2), 0x00073101 }, + { REG_TEST(0,2), 0x00000022 }, + { REG_TEST(1,2), 0x00000022 }, + { REG_TOP_BOTTOM(0,2), 0x00bd007e }, + { REG_TOP_BOTTOM(1,2), 0x00360024 }, + { REG_HIGH_LOW_WM(0,2), 0x07460757 }, + { REG_HIGH_LOW_WM(1,2), WM_DISABLE }, + { REG_CT_THRHLD(0,2), 0x00000000 }, + { REG_CT_THRHLD(1,2), 0x00000000 }, + { REG_BUCKE(2), 0x0002ffff }, + { REG_BUCKI(2), 0x0002ffff }, + { REG_TEST(0,2), 0x00000020 }, + { REG_TEST(1,2), 0x00000020 }, + /* Port config */ + { REG_MAX_LEN(2), 0x00002710 }, + { REG_PORT_FAIL(2), 0x00000002 }, + { REG_NORMALIZER(2), 0x00000a64 }, + { REG_DENORM(2), 0x00000010 }, + { REG_STICK_BIT(2), 0x03baa370 }, + { REG_DEV_SETUP(2), 0x00000083 }, + { REG_DEV_SETUP(2), 0x00000082 }, + { REG_MODE_CFG(2), 0x0200259f }, + }, + { /* Port 3 */ + /* FIFO setup */ + { REG_DBG(3), 0x000004f0 }, + { REG_HDX(3), 0x00073101 }, + { REG_TEST(0,3), 0x00000022 }, + { REG_TEST(1,3), 0x00000022 }, + { REG_TOP_BOTTOM(0,3), 0x00fc00bd }, + { REG_TOP_BOTTOM(1,3), 0x00480036 }, + { REG_HIGH_LOW_WM(0,3), 0x07460757 }, + { REG_HIGH_LOW_WM(1,3), WM_DISABLE }, + { REG_CT_THRHLD(0,3), 0x00000000 }, + { REG_CT_THRHLD(1,3), 0x00000000 }, + { REG_BUCKE(3), 0x0002ffff }, + { REG_BUCKI(3), 0x0002ffff }, + { REG_TEST(0,3), 0x00000020 }, + { REG_TEST(1,3), 0x00000020 }, + /* Port config */ + { REG_MAX_LEN(3), 0x00002710 }, + { REG_PORT_FAIL(3), 0x00000002 }, + { REG_NORMALIZER(3), 0x00000a64 }, + { REG_DENORM(3), 0x00000010 }, + { REG_STICK_BIT(3), 0x03baa370 }, + { REG_DEV_SETUP(3), 0x00000083 }, + { REG_DEV_SETUP(3), 0x00000082 }, + { REG_MODE_CFG(3), 0x0200259f }, + }, +}; + +static void run_table(adapter_t *adapter, struct init_table *ib, int len) +{ + int i; + + for (i = 0; i < len; i++) { + if (ib[i].addr == INITBLOCK_SLEEP) { + udelay( ib[i].data ); + pr_err("sleep %d us\n",ib[i].data); + } else + vsc_write( adapter, ib[i].addr, ib[i].data ); + } +} + +static int bist_rd(adapter_t *adapter, int moduleid, int address) +{ + int data = 0; + u32 result = 0; + + if ((address != 0x0) && + (address != 0x1) && + (address != 0x2) && + (address != 0xd) && + (address != 0xe)) + pr_err("No bist address: 0x%x\n", address); + + data = ((0x00 << 24) | ((address & 0xff) << 16) | (0x00 << 8) | + ((moduleid & 0xff) << 0)); + vsc_write(adapter, REG_RAM_BIST_CMD, data); + + udelay(10); + + vsc_read(adapter, REG_RAM_BIST_RESULT, &result); + if ((result & (1 << 9)) != 0x0) + pr_err("Still in bist read: 0x%x\n", result); + else if ((result & (1 << 8)) != 0x0) + pr_err("bist read error: 0x%x\n", result); + + return result & 0xff; +} + +static int bist_wr(adapter_t *adapter, int moduleid, int address, int value) +{ + int data = 0; + u32 result = 0; + + if ((address != 0x0) && + (address != 0x1) && + (address != 0x2) && + (address != 0xd) && + (address != 0xe)) + pr_err("No bist address: 0x%x\n", address); + + if (value > 255) + pr_err("Suspicious write out of range value: 0x%x\n", value); + + data = ((0x01 << 24) | ((address & 0xff) << 16) | (value << 8) | + ((moduleid & 0xff) << 0)); + vsc_write(adapter, REG_RAM_BIST_CMD, data); + + udelay(5); + + vsc_read(adapter, REG_RAM_BIST_CMD, &result); + if ((result & (1 << 27)) != 0x0) + pr_err("Still in bist write: 0x%x\n", result); + else if ((result & (1 << 26)) != 0x0) + pr_err("bist write error: 0x%x\n", result); + + return 0; +} + +static int run_bist(adapter_t *adapter, int moduleid) +{ + /*run bist*/ + (void) bist_wr(adapter,moduleid, 0x00, 0x02); + (void) bist_wr(adapter,moduleid, 0x01, 0x01); + + return 0; +} + +static int check_bist(adapter_t *adapter, int moduleid) +{ + int result=0; + int column=0; + /*check bist*/ + result = bist_rd(adapter,moduleid, 0x02); + column = ((bist_rd(adapter,moduleid, 0x0e)<<8) + + (bist_rd(adapter,moduleid, 0x0d))); + if ((result & 3) != 0x3) + pr_err("Result: 0x%x BIST error in ram %d, column: 0x%04x\n", + result, moduleid, column); + return 0; +} + +static int enable_mem(adapter_t *adapter, int moduleid) +{ + /*enable mem*/ + (void) bist_wr(adapter,moduleid, 0x00, 0x00); + return 0; +} + +static int run_bist_all(adapter_t *adapter) +{ + int port = 0; + u32 val = 0; + + vsc_write(adapter, REG_MEM_BIST, 0x5); + vsc_read(adapter, REG_MEM_BIST, &val); + + for (port = 0; port < 12; port++) + vsc_write(adapter, REG_DEV_SETUP(port), 0x0); + + udelay(300); + vsc_write(adapter, REG_SPI4_MISC, 0x00040409); + udelay(300); + + (void) run_bist(adapter,13); + (void) run_bist(adapter,14); + (void) run_bist(adapter,20); + (void) run_bist(adapter,21); + mdelay(200); + (void) check_bist(adapter,13); + (void) check_bist(adapter,14); + (void) check_bist(adapter,20); + (void) check_bist(adapter,21); + udelay(100); + (void) enable_mem(adapter,13); + (void) enable_mem(adapter,14); + (void) enable_mem(adapter,20); + (void) enable_mem(adapter,21); + udelay(300); + vsc_write(adapter, REG_SPI4_MISC, 0x60040400); + udelay(300); + for (port = 0; port < 12; port++) + vsc_write(adapter, REG_DEV_SETUP(port), 0x1); + + udelay(300); + vsc_write(adapter, REG_MEM_BIST, 0x0); + mdelay(10); + return 0; +} + +static int mac_intr_handler(struct cmac *mac) +{ + return 0; +} + +static int mac_intr_enable(struct cmac *mac) +{ + return 0; +} + +static int mac_intr_disable(struct cmac *mac) +{ + return 0; +} + +static int mac_intr_clear(struct cmac *mac) +{ + return 0; +} + +/* Expect MAC address to be in network byte order. */ +static int mac_set_address(struct cmac* mac, u8 addr[6]) +{ + u32 val; + int port = mac->instance->index; + + vsc_write(mac->adapter, REG_MAC_LOW_ADDR(port), + (addr[3] << 16) | (addr[4] << 8) | addr[5]); + vsc_write(mac->adapter, REG_MAC_HIGH_ADDR(port), + (addr[0] << 16) | (addr[1] << 8) | addr[2]); + + vsc_read(mac->adapter, REG_ING_FFILT_UM_EN, &val); + val &= ~0xf0000000; + vsc_write(mac->adapter, REG_ING_FFILT_UM_EN, val | (port << 28)); + + vsc_write(mac->adapter, REG_ING_FFILT_MASK0, + 0xffff0000 | (addr[4] << 8) | addr[5]); + vsc_write(mac->adapter, REG_ING_FFILT_MASK1, + 0xffff0000 | (addr[2] << 8) | addr[3]); + vsc_write(mac->adapter, REG_ING_FFILT_MASK2, + 0xffff0000 | (addr[0] << 8) | addr[1]); + return 0; +} + +static int mac_get_address(struct cmac *mac, u8 addr[6]) +{ + u32 addr_lo, addr_hi; + int port = mac->instance->index; + + vsc_read(mac->adapter, REG_MAC_LOW_ADDR(port), &addr_lo); + vsc_read(mac->adapter, REG_MAC_HIGH_ADDR(port), &addr_hi); + + addr[0] = (u8) (addr_hi >> 16); + addr[1] = (u8) (addr_hi >> 8); + addr[2] = (u8) addr_hi; + addr[3] = (u8) (addr_lo >> 16); + addr[4] = (u8) (addr_lo >> 8); + addr[5] = (u8) addr_lo; + return 0; +} + +/* This is intended to reset a port, not the whole MAC */ +static int mac_reset(struct cmac *mac) +{ + int index = mac->instance->index; + + run_table(mac->adapter, vsc7326_portinit[index], + ARRAY_SIZE(vsc7326_portinit[index])); + + return 0; +} + +static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm) +{ + u32 v; + int port = mac->instance->index; + + vsc_read(mac->adapter, REG_ING_FFILT_UM_EN, &v); + v |= 1 << 12; + + if (t1_rx_mode_promisc(rm)) + v &= ~(1 << (port + 16)); + else + v |= 1 << (port + 16); + + vsc_write(mac->adapter, REG_ING_FFILT_UM_EN, v); + return 0; +} + +static int mac_set_mtu(struct cmac *mac, int mtu) +{ + int port = mac->instance->index; + + if (mtu > MAX_MTU) + return -EINVAL; + + /* max_len includes header and FCS */ + vsc_write(mac->adapter, REG_MAX_LEN(port), mtu + 14 + 4); + return 0; +} + +static int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, + int fc) +{ + u32 v; + int enable, port = mac->instance->index; + + if (speed >= 0 && speed != SPEED_10 && speed != SPEED_100 && + speed != SPEED_1000) + return -1; + if (duplex > 0 && duplex != DUPLEX_FULL) + return -1; + + if (speed >= 0) { + vsc_read(mac->adapter, REG_MODE_CFG(port), &v); + enable = v & 3; /* save tx/rx enables */ + v &= ~0xf; + v |= 4; /* full duplex */ + if (speed == SPEED_1000) + v |= 8; /* GigE */ + enable |= v; + vsc_write(mac->adapter, REG_MODE_CFG(port), v); + + if (speed == SPEED_1000) + v = 0x82; + else if (speed == SPEED_100) + v = 0x84; + else /* SPEED_10 */ + v = 0x86; + vsc_write(mac->adapter, REG_DEV_SETUP(port), v | 1); /* reset */ + vsc_write(mac->adapter, REG_DEV_SETUP(port), v); + vsc_read(mac->adapter, REG_DBG(port), &v); + v &= ~0xff00; + if (speed == SPEED_1000) + v |= 0x400; + else if (speed == SPEED_100) + v |= 0x2000; + else /* SPEED_10 */ + v |= 0xff00; + vsc_write(mac->adapter, REG_DBG(port), v); + + vsc_write(mac->adapter, REG_TX_IFG(port), + speed == SPEED_1000 ? 5 : 0x11); + if (duplex == DUPLEX_HALF) + enable = 0x0; /* 100 or 10 */ + else if (speed == SPEED_1000) + enable = 0xc; + else /* SPEED_100 or 10 */ + enable = 0x4; + enable |= 0x9 << 10; /* IFG1 */ + enable |= 0x6 << 6; /* IFG2 */ + enable |= 0x1 << 4; /* VLAN */ + enable |= 0x3; /* RX/TX EN */ + vsc_write(mac->adapter, REG_MODE_CFG(port), enable); + + } + + vsc_read(mac->adapter, REG_PAUSE_CFG(port), &v); + v &= 0xfff0ffff; + v |= 0x20000; /* xon/xoff */ + if (fc & PAUSE_RX) + v |= 0x40000; + if (fc & PAUSE_TX) + v |= 0x80000; + if (fc == (PAUSE_RX | PAUSE_TX)) + v |= 0x10000; + vsc_write(mac->adapter, REG_PAUSE_CFG(port), v); + return 0; +} + +static int mac_enable(struct cmac *mac, int which) +{ + u32 val; + int port = mac->instance->index; + + /* Write the correct WM value when the port is enabled. */ + vsc_write(mac->adapter, REG_HIGH_LOW_WM(1,port), WM_ENABLE); + + vsc_read(mac->adapter, REG_MODE_CFG(port), &val); + if (which & MAC_DIRECTION_RX) + val |= 0x2; + if (which & MAC_DIRECTION_TX) + val |= 1; + vsc_write(mac->adapter, REG_MODE_CFG(port), val); + return 0; +} + +static int mac_disable(struct cmac *mac, int which) +{ + u32 val; + int i, port = mac->instance->index; + + /* Reset the port, this also writes the correct WM value */ + mac_reset(mac); + + vsc_read(mac->adapter, REG_MODE_CFG(port), &val); + if (which & MAC_DIRECTION_RX) + val &= ~0x2; + if (which & MAC_DIRECTION_TX) + val &= ~0x1; + vsc_write(mac->adapter, REG_MODE_CFG(port), val); + vsc_read(mac->adapter, REG_MODE_CFG(port), &val); + + /* Clear stats */ + for (i = 0; i <= 0x3a; ++i) + vsc_write(mac->adapter, CRA(4, port, i), 0); + + /* Clear software counters */ + memset(&mac->stats, 0, sizeof(struct cmac_statistics)); + + return 0; +} + +static void rmon_update(struct cmac *mac, unsigned int addr, u64 *stat) +{ + u32 v, lo; + + vsc_read(mac->adapter, addr, &v); + lo = *stat; + *stat = *stat - lo + v; + + if (v == 0) + return; + + if (v < lo) + *stat += (1ULL << 32); +} + +static void port_stats_update(struct cmac *mac) +{ + struct { + unsigned int reg; + unsigned int offset; + } hw_stats[] = { + +#define HW_STAT(reg, stat_name) \ + { reg, (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL } + + /* Rx stats */ + HW_STAT(RxUnicast, RxUnicastFramesOK), + HW_STAT(RxMulticast, RxMulticastFramesOK), + HW_STAT(RxBroadcast, RxBroadcastFramesOK), + HW_STAT(Crc, RxFCSErrors), + HW_STAT(RxAlignment, RxAlignErrors), + HW_STAT(RxOversize, RxFrameTooLongErrors), + HW_STAT(RxPause, RxPauseFrames), + HW_STAT(RxJabbers, RxJabberErrors), + HW_STAT(RxFragments, RxRuntErrors), + HW_STAT(RxUndersize, RxRuntErrors), + HW_STAT(RxSymbolCarrier, RxSymbolErrors), + HW_STAT(RxSize1519ToMax, RxJumboFramesOK), + + /* Tx stats (skip collision stats as we are full-duplex only) */ + HW_STAT(TxUnicast, TxUnicastFramesOK), + HW_STAT(TxMulticast, TxMulticastFramesOK), + HW_STAT(TxBroadcast, TxBroadcastFramesOK), + HW_STAT(TxPause, TxPauseFrames), + HW_STAT(TxUnderrun, TxUnderrun), + HW_STAT(TxSize1519ToMax, TxJumboFramesOK), + }, *p = hw_stats; + unsigned int port = mac->instance->index; + u64 *stats = (u64 *)&mac->stats; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(hw_stats); i++) + rmon_update(mac, CRA(0x4, port, p->reg), stats + p->offset); + + rmon_update(mac, REG_TX_OK_BYTES(port), &mac->stats.TxOctetsOK); + rmon_update(mac, REG_RX_OK_BYTES(port), &mac->stats.RxOctetsOK); + rmon_update(mac, REG_RX_BAD_BYTES(port), &mac->stats.RxOctetsBad); +} + +/* + * This function is called periodically to accumulate the current values of the + * RMON counters into the port statistics. Since the counters are only 32 bits + * some of them can overflow in less than a minute at GigE speeds, so this + * function should be called every 30 seconds or so. + * + * To cut down on reading costs we update only the octet counters at each tick + * and do a full update at major ticks, which can be every 30 minutes or more. + */ +static const struct cmac_statistics *mac_update_statistics(struct cmac *mac, + int flag) +{ + if (flag == MAC_STATS_UPDATE_FULL || + mac->instance->ticks >= MAJOR_UPDATE_TICKS) { + port_stats_update(mac); + mac->instance->ticks = 0; + } else { + int port = mac->instance->index; + + rmon_update(mac, REG_RX_OK_BYTES(port), + &mac->stats.RxOctetsOK); + rmon_update(mac, REG_RX_BAD_BYTES(port), + &mac->stats.RxOctetsBad); + rmon_update(mac, REG_TX_OK_BYTES(port), + &mac->stats.TxOctetsOK); + mac->instance->ticks++; + } + return &mac->stats; +} + +static void mac_destroy(struct cmac *mac) +{ + kfree(mac); +} + +static struct cmac_ops vsc7326_ops = { + .destroy = mac_destroy, + .reset = mac_reset, + .interrupt_handler = mac_intr_handler, + .interrupt_enable = mac_intr_enable, + .interrupt_disable = mac_intr_disable, + .interrupt_clear = mac_intr_clear, + .enable = mac_enable, + .disable = mac_disable, + .set_mtu = mac_set_mtu, + .set_rx_mode = mac_set_rx_mode, + .set_speed_duplex_fc = mac_set_speed_duplex_fc, + .statistics_update = mac_update_statistics, + .macaddress_get = mac_get_address, + .macaddress_set = mac_set_address, +}; + +static struct cmac *vsc7326_mac_create(adapter_t *adapter, int index) +{ + struct cmac *mac; + u32 val; + int i; + + mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL); + if (!mac) + return NULL; + + mac->ops = &vsc7326_ops; + mac->instance = (cmac_instance *)(mac + 1); + mac->adapter = adapter; + + mac->instance->index = index; + mac->instance->ticks = 0; + + i = 0; + do { + u32 vhi, vlo; + + vhi = vlo = 0; + t1_tpi_read(adapter, (REG_LOCAL_STATUS << 2) + 4, &vlo); + udelay(1); + t1_tpi_read(adapter, REG_LOCAL_STATUS << 2, &vhi); + udelay(5); + val = (vhi << 16) | vlo; + } while ((++i < 10000) && (val == 0xffffffff)); + + return mac; +} + +static int vsc7326_mac_reset(adapter_t *adapter) +{ + vsc7326_full_reset(adapter); + (void) run_bist_all(adapter); + run_table(adapter, vsc7326_reset, ARRAY_SIZE(vsc7326_reset)); + return 0; +} + +const struct gmac t1_vsc7326_ops = { + .stats_update_period = STATS_TICK_SECS, + .create = vsc7326_mac_create, + .reset = vsc7326_mac_reset, +}; diff --git a/drivers/net/ethernet/chelsio/cxgb/vsc7326_reg.h b/drivers/net/ethernet/chelsio/cxgb/vsc7326_reg.h new file mode 100644 index 000000000000..479edbcabe68 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb/vsc7326_reg.h @@ -0,0 +1,297 @@ +/* $Date: 2006/04/28 19:20:17 $ $RCSfile: vsc7326_reg.h,v $ $Revision: 1.5 $ */ +#ifndef _VSC7321_REG_H_ +#define _VSC7321_REG_H_ + +/* Register definitions for Vitesse VSC7321 (Meigs II) MAC + * + * Straight off the data sheet, VMDS-10038 Rev 2.0 and + * PD0011-01-14-Meigs-II 2002-12-12 + */ + +/* Just 'cause it's in here doesn't mean it's used. */ + +#define CRA(blk,sub,adr) ((((blk) & 0x7) << 13) | (((sub) & 0xf) << 9) | (((adr) & 0xff) << 1)) + +/* System and CPU comm's registers */ +#define REG_CHIP_ID CRA(0x7,0xf,0x00) /* Chip ID */ +#define REG_BLADE_ID CRA(0x7,0xf,0x01) /* Blade ID */ +#define REG_SW_RESET CRA(0x7,0xf,0x02) /* Global Soft Reset */ +#define REG_MEM_BIST CRA(0x7,0xf,0x04) /* mem */ +#define REG_IFACE_MODE CRA(0x7,0xf,0x07) /* Interface mode */ +#define REG_MSCH CRA(0x7,0x2,0x06) /* CRC error count */ +#define REG_CRC_CNT CRA(0x7,0x2,0x0a) /* CRC error count */ +#define REG_CRC_CFG CRA(0x7,0x2,0x0b) /* CRC config */ +#define REG_SI_TRANSFER_SEL CRA(0x7,0xf,0x18) /* SI Transfer Select */ +#define REG_PLL_CLK_SPEED CRA(0x7,0xf,0x19) /* Clock Speed Selection */ +#define REG_SYS_CLK_SELECT CRA(0x7,0xf,0x1c) /* System Clock Select */ +#define REG_GPIO_CTRL CRA(0x7,0xf,0x1d) /* GPIO Control */ +#define REG_GPIO_OUT CRA(0x7,0xf,0x1e) /* GPIO Out */ +#define REG_GPIO_IN CRA(0x7,0xf,0x1f) /* GPIO In */ +#define REG_CPU_TRANSFER_SEL CRA(0x7,0xf,0x20) /* CPU Transfer Select */ +#define REG_LOCAL_DATA CRA(0x7,0xf,0xfe) /* Local CPU Data Register */ +#define REG_LOCAL_STATUS CRA(0x7,0xf,0xff) /* Local CPU Status Register */ + +/* Aggregator registers */ +#define REG_AGGR_SETUP CRA(0x7,0x1,0x00) /* Aggregator Setup */ +#define REG_PMAP_TABLE CRA(0x7,0x1,0x01) /* Port map table */ +#define REG_MPLS_BIT0 CRA(0x7,0x1,0x08) /* MPLS bit0 position */ +#define REG_MPLS_BIT1 CRA(0x7,0x1,0x09) /* MPLS bit1 position */ +#define REG_MPLS_BIT2 CRA(0x7,0x1,0x0a) /* MPLS bit2 position */ +#define REG_MPLS_BIT3 CRA(0x7,0x1,0x0b) /* MPLS bit3 position */ +#define REG_MPLS_BITMASK CRA(0x7,0x1,0x0c) /* MPLS bit mask */ +#define REG_PRE_BIT0POS CRA(0x7,0x1,0x10) /* Preamble bit0 position */ +#define REG_PRE_BIT1POS CRA(0x7,0x1,0x11) /* Preamble bit1 position */ +#define REG_PRE_BIT2POS CRA(0x7,0x1,0x12) /* Preamble bit2 position */ +#define REG_PRE_BIT3POS CRA(0x7,0x1,0x13) /* Preamble bit3 position */ +#define REG_PRE_ERR_CNT CRA(0x7,0x1,0x14) /* Preamble parity error count */ + +/* BIST registers */ +/*#define REG_RAM_BIST_CMD CRA(0x7,0x2,0x00)*/ /* RAM BIST Command Register */ +/*#define REG_RAM_BIST_RESULT CRA(0x7,0x2,0x01)*/ /* RAM BIST Read Status/Result */ +#define REG_RAM_BIST_CMD CRA(0x7,0x1,0x00) /* RAM BIST Command Register */ +#define REG_RAM_BIST_RESULT CRA(0x7,0x1,0x01) /* RAM BIST Read Status/Result */ +#define BIST_PORT_SELECT 0x00 /* BIST port select */ +#define BIST_COMMAND 0x01 /* BIST enable/disable */ +#define BIST_STATUS 0x02 /* BIST operation status */ +#define BIST_ERR_CNT_LSB 0x03 /* BIST error count lo 8b */ +#define BIST_ERR_CNT_MSB 0x04 /* BIST error count hi 8b */ +#define BIST_ERR_SEL_LSB 0x05 /* BIST error select lo 8b */ +#define BIST_ERR_SEL_MSB 0x06 /* BIST error select hi 8b */ +#define BIST_ERROR_STATE 0x07 /* BIST engine internal state */ +#define BIST_ERR_ADR0 0x08 /* BIST error address lo 8b */ +#define BIST_ERR_ADR1 0x09 /* BIST error address lomid 8b */ +#define BIST_ERR_ADR2 0x0a /* BIST error address himid 8b */ +#define BIST_ERR_ADR3 0x0b /* BIST error address hi 8b */ + +/* FIFO registers + * ie = 0 for ingress, 1 for egress + * fn = FIFO number, 0-9 + */ +#define REG_TEST(ie,fn) CRA(0x2,ie&1,0x00+fn) /* Mode & Test Register */ +#define REG_TOP_BOTTOM(ie,fn) CRA(0x2,ie&1,0x10+fn) /* FIFO Buffer Top & Bottom */ +#define REG_TAIL(ie,fn) CRA(0x2,ie&1,0x20+fn) /* FIFO Write Pointer */ +#define REG_HEAD(ie,fn) CRA(0x2,ie&1,0x30+fn) /* FIFO Read Pointer */ +#define REG_HIGH_LOW_WM(ie,fn) CRA(0x2,ie&1,0x40+fn) /* Flow Control Water Marks */ +#define REG_CT_THRHLD(ie,fn) CRA(0x2,ie&1,0x50+fn) /* Cut Through Threshold */ +#define REG_FIFO_DROP_CNT(ie,fn) CRA(0x2,ie&1,0x60+fn) /* Drop & CRC Error Counter */ +#define REG_DEBUG_BUF_CNT(ie,fn) CRA(0x2,ie&1,0x70+fn) /* Input Side Debug Counter */ +#define REG_BUCKI(fn) CRA(0x2,2,0x20+fn) /* Input Side Debug Counter */ +#define REG_BUCKE(fn) CRA(0x2,3,0x20+fn) /* Input Side Debug Counter */ + +/* Traffic shaper buckets + * ie = 0 for ingress, 1 for egress + * bn = bucket number 0-10 (yes, 11 buckets) + */ +/* OK, this one's kinda ugly. Some hardware designers are perverse. */ +#define REG_TRAFFIC_SHAPER_BUCKET(ie,bn) CRA(0x2,ie&1,0x0a + (bn>7) | ((bn&7)<<4)) +#define REG_TRAFFIC_SHAPER_CONTROL(ie) CRA(0x2,ie&1,0x3b) + +#define REG_SRAM_ADR(ie) CRA(0x2,ie&1,0x0e) /* FIFO SRAM address */ +#define REG_SRAM_WR_STRB(ie) CRA(0x2,ie&1,0x1e) /* FIFO SRAM write strobe */ +#define REG_SRAM_RD_STRB(ie) CRA(0x2,ie&1,0x2e) /* FIFO SRAM read strobe */ +#define REG_SRAM_DATA_0(ie) CRA(0x2,ie&1,0x3e) /* FIFO SRAM data lo 8b */ +#define REG_SRAM_DATA_1(ie) CRA(0x2,ie&1,0x4e) /* FIFO SRAM data lomid 8b */ +#define REG_SRAM_DATA_2(ie) CRA(0x2,ie&1,0x5e) /* FIFO SRAM data himid 8b */ +#define REG_SRAM_DATA_3(ie) CRA(0x2,ie&1,0x6e) /* FIFO SRAM data hi 8b */ +#define REG_SRAM_DATA_BLK_TYPE(ie) CRA(0x2,ie&1,0x7e) /* FIFO SRAM tag */ +/* REG_ING_CONTROL equals REG_CONTROL with ie = 0, likewise REG_EGR_CONTROL is ie = 1 */ +#define REG_CONTROL(ie) CRA(0x2,ie&1,0x0f) /* FIFO control */ +#define REG_ING_CONTROL CRA(0x2,0x0,0x0f) /* Ingress control (alias) */ +#define REG_EGR_CONTROL CRA(0x2,0x1,0x0f) /* Egress control (alias) */ +#define REG_AGE_TIMER(ie) CRA(0x2,ie&1,0x1f) /* Aging timer */ +#define REG_AGE_INC(ie) CRA(0x2,ie&1,0x2f) /* Aging increment */ +#define DEBUG_OUT(ie) CRA(0x2,ie&1,0x3f) /* Output debug counter control */ +#define DEBUG_CNT(ie) CRA(0x2,ie&1,0x4f) /* Output debug counter */ + +/* SPI4 interface */ +#define REG_SPI4_MISC CRA(0x5,0x0,0x00) /* Misc Register */ +#define REG_SPI4_STATUS CRA(0x5,0x0,0x01) /* CML Status */ +#define REG_SPI4_ING_SETUP0 CRA(0x5,0x0,0x02) /* Ingress Status Channel Setup */ +#define REG_SPI4_ING_SETUP1 CRA(0x5,0x0,0x03) /* Ingress Data Training Setup */ +#define REG_SPI4_ING_SETUP2 CRA(0x5,0x0,0x04) /* Ingress Data Burst Size Setup */ +#define REG_SPI4_EGR_SETUP0 CRA(0x5,0x0,0x05) /* Egress Status Channel Setup */ +#define REG_SPI4_DBG_CNT(n) CRA(0x5,0x0,0x10+n) /* Debug counters 0-9 */ +#define REG_SPI4_DBG_SETUP CRA(0x5,0x0,0x1A) /* Debug counters setup */ +#define REG_SPI4_TEST CRA(0x5,0x0,0x20) /* Test Setup Register */ +#define REG_TPGEN_UP0 CRA(0x5,0x0,0x21) /* Test Pattern generator user pattern 0 */ +#define REG_TPGEN_UP1 CRA(0x5,0x0,0x22) /* Test Pattern generator user pattern 1 */ +#define REG_TPCHK_UP0 CRA(0x5,0x0,0x23) /* Test Pattern checker user pattern 0 */ +#define REG_TPCHK_UP1 CRA(0x5,0x0,0x24) /* Test Pattern checker user pattern 1 */ +#define REG_TPSAM_P0 CRA(0x5,0x0,0x25) /* Sampled pattern 0 */ +#define REG_TPSAM_P1 CRA(0x5,0x0,0x26) /* Sampled pattern 1 */ +#define REG_TPERR_CNT CRA(0x5,0x0,0x27) /* Pattern checker error counter */ +#define REG_SPI4_STICKY CRA(0x5,0x0,0x30) /* Sticky bits register */ +#define REG_SPI4_DBG_INH CRA(0x5,0x0,0x31) /* Core egress & ingress inhibit */ +#define REG_SPI4_DBG_STATUS CRA(0x5,0x0,0x32) /* Sampled ingress status */ +#define REG_SPI4_DBG_GRANT CRA(0x5,0x0,0x33) /* Ingress cranted credit value */ + +#define REG_SPI4_DESKEW CRA(0x5,0x0,0x43) /* Ingress cranted credit value */ + +/* 10GbE MAC Block Registers */ +/* Note that those registers that are exactly the same for 10GbE as for + * tri-speed are only defined with the version that needs a port number. + * Pass 0xa in those cases. + * + * Also note that despite the presence of a MAC address register, this part + * does no ingress MAC address filtering. That register is used only for + * pause frame detection and generation. + */ +/* 10GbE specific, and different from tri-speed */ +#define REG_MISC_10G CRA(0x1,0xa,0x00) /* Misc 10GbE setup */ +#define REG_PAUSE_10G CRA(0x1,0xa,0x01) /* Pause register */ +#define REG_NORMALIZER_10G CRA(0x1,0xa,0x05) /* 10G normalizer */ +#define REG_STICKY_RX CRA(0x1,0xa,0x06) /* RX debug register */ +#define REG_DENORM_10G CRA(0x1,0xa,0x07) /* Denormalizer */ +#define REG_STICKY_TX CRA(0x1,0xa,0x08) /* TX sticky bits */ +#define REG_MAX_RXHIGH CRA(0x1,0xa,0x0a) /* XGMII lane 0-3 debug */ +#define REG_MAX_RXLOW CRA(0x1,0xa,0x0b) /* XGMII lane 4-7 debug */ +#define REG_MAC_TX_STICKY CRA(0x1,0xa,0x0c) /* MAC Tx state sticky debug */ +#define REG_MAC_TX_RUNNING CRA(0x1,0xa,0x0d) /* MAC Tx state running debug */ +#define REG_TX_ABORT_AGE CRA(0x1,0xa,0x14) /* Aged Tx frames discarded */ +#define REG_TX_ABORT_SHORT CRA(0x1,0xa,0x15) /* Short Tx frames discarded */ +#define REG_TX_ABORT_TAXI CRA(0x1,0xa,0x16) /* Taxi error frames discarded */ +#define REG_TX_ABORT_UNDERRUN CRA(0x1,0xa,0x17) /* Tx Underrun abort counter */ +#define REG_TX_DENORM_DISCARD CRA(0x1,0xa,0x18) /* Tx denormalizer discards */ +#define REG_XAUI_STAT_A CRA(0x1,0xa,0x20) /* XAUI status A */ +#define REG_XAUI_STAT_B CRA(0x1,0xa,0x21) /* XAUI status B */ +#define REG_XAUI_STAT_C CRA(0x1,0xa,0x22) /* XAUI status C */ +#define REG_XAUI_CONF_A CRA(0x1,0xa,0x23) /* XAUI configuration A */ +#define REG_XAUI_CONF_B CRA(0x1,0xa,0x24) /* XAUI configuration B */ +#define REG_XAUI_CODE_GRP_CNT CRA(0x1,0xa,0x25) /* XAUI code group error count */ +#define REG_XAUI_CONF_TEST_A CRA(0x1,0xa,0x26) /* XAUI test register A */ +#define REG_PDERRCNT CRA(0x1,0xa,0x27) /* XAUI test register B */ + +/* pn = port number 0-9 for tri-speed, 10 for 10GbE */ +/* Both tri-speed and 10GbE */ +#define REG_MAX_LEN(pn) CRA(0x1,pn,0x02) /* Max length */ +#define REG_MAC_HIGH_ADDR(pn) CRA(0x1,pn,0x03) /* Upper 24 bits of MAC addr */ +#define REG_MAC_LOW_ADDR(pn) CRA(0x1,pn,0x04) /* Lower 24 bits of MAC addr */ + +/* tri-speed only + * pn = port number, 0-9 + */ +#define REG_MODE_CFG(pn) CRA(0x1,pn,0x00) /* Mode configuration */ +#define REG_PAUSE_CFG(pn) CRA(0x1,pn,0x01) /* Pause configuration */ +#define REG_NORMALIZER(pn) CRA(0x1,pn,0x05) /* Normalizer */ +#define REG_TBI_STATUS(pn) CRA(0x1,pn,0x06) /* TBI status */ +#define REG_PCS_STATUS_DBG(pn) CRA(0x1,pn,0x07) /* PCS status debug */ +#define REG_PCS_CTRL(pn) CRA(0x1,pn,0x08) /* PCS control */ +#define REG_TBI_CONFIG(pn) CRA(0x1,pn,0x09) /* TBI configuration */ +#define REG_STICK_BIT(pn) CRA(0x1,pn,0x0a) /* Sticky bits */ +#define REG_DEV_SETUP(pn) CRA(0x1,pn,0x0b) /* MAC clock/reset setup */ +#define REG_DROP_CNT(pn) CRA(0x1,pn,0x0c) /* Drop counter */ +#define REG_PORT_POS(pn) CRA(0x1,pn,0x0d) /* Preamble port position */ +#define REG_PORT_FAIL(pn) CRA(0x1,pn,0x0e) /* Preamble port position */ +#define REG_SERDES_CONF(pn) CRA(0x1,pn,0x0f) /* SerDes configuration */ +#define REG_SERDES_TEST(pn) CRA(0x1,pn,0x10) /* SerDes test */ +#define REG_SERDES_STAT(pn) CRA(0x1,pn,0x11) /* SerDes status */ +#define REG_SERDES_COM_CNT(pn) CRA(0x1,pn,0x12) /* SerDes comma counter */ +#define REG_DENORM(pn) CRA(0x1,pn,0x15) /* Frame denormalization */ +#define REG_DBG(pn) CRA(0x1,pn,0x16) /* Device 1G debug */ +#define REG_TX_IFG(pn) CRA(0x1,pn,0x18) /* Tx IFG config */ +#define REG_HDX(pn) CRA(0x1,pn,0x19) /* Half-duplex config */ + +/* Statistics */ +/* CRA(0x4,pn,reg) */ +/* reg below */ +/* pn = port number, 0-a, a = 10GbE */ + +enum { + RxInBytes = 0x00, // # Rx in octets + RxSymbolCarrier = 0x01, // Frames w/ symbol errors + RxPause = 0x02, // # pause frames received + RxUnsupOpcode = 0x03, // # control frames with unsupported opcode + RxOkBytes = 0x04, // # octets in good frames + RxBadBytes = 0x05, // # octets in bad frames + RxUnicast = 0x06, // # good unicast frames + RxMulticast = 0x07, // # good multicast frames + RxBroadcast = 0x08, // # good broadcast frames + Crc = 0x09, // # frames w/ bad CRC only + RxAlignment = 0x0a, // # frames w/ alignment err + RxUndersize = 0x0b, // # frames undersize + RxFragments = 0x0c, // # frames undersize w/ crc err + RxInRangeLengthError = 0x0d, // # frames with length error + RxOutOfRangeError = 0x0e, // # frames with illegal length field + RxOversize = 0x0f, // # frames oversize + RxJabbers = 0x10, // # frames oversize w/ crc err + RxSize64 = 0x11, // # frames 64 octets long + RxSize65To127 = 0x12, // # frames 65-127 octets + RxSize128To255 = 0x13, // # frames 128-255 + RxSize256To511 = 0x14, // # frames 256-511 + RxSize512To1023 = 0x15, // # frames 512-1023 + RxSize1024To1518 = 0x16, // # frames 1024-1518 + RxSize1519ToMax = 0x17, // # frames 1519-max + + TxOutBytes = 0x18, // # octets tx + TxPause = 0x19, // # pause frames sent + TxOkBytes = 0x1a, // # octets tx OK + TxUnicast = 0x1b, // # frames unicast + TxMulticast = 0x1c, // # frames multicast + TxBroadcast = 0x1d, // # frames broadcast + TxMultipleColl = 0x1e, // # frames tx after multiple collisions + TxLateColl = 0x1f, // # late collisions detected + TxXcoll = 0x20, // # frames lost, excessive collisions + TxDefer = 0x21, // # frames deferred on first tx attempt + TxXdefer = 0x22, // # frames excessively deferred + TxCsense = 0x23, // carrier sense errors at frame end + TxSize64 = 0x24, // # frames 64 octets long + TxSize65To127 = 0x25, // # frames 65-127 octets + TxSize128To255 = 0x26, // # frames 128-255 + TxSize256To511 = 0x27, // # frames 256-511 + TxSize512To1023 = 0x28, // # frames 512-1023 + TxSize1024To1518 = 0x29, // # frames 1024-1518 + TxSize1519ToMax = 0x2a, // # frames 1519-max + TxSingleColl = 0x2b, // # frames tx after single collision + TxBackoff2 = 0x2c, // # frames tx ok after 2 backoffs/collisions + TxBackoff3 = 0x2d, // after 3 backoffs/collisions + TxBackoff4 = 0x2e, // after 4 + TxBackoff5 = 0x2f, // after 5 + TxBackoff6 = 0x30, // after 6 + TxBackoff7 = 0x31, // after 7 + TxBackoff8 = 0x32, // after 8 + TxBackoff9 = 0x33, // after 9 + TxBackoff10 = 0x34, // after 10 + TxBackoff11 = 0x35, // after 11 + TxBackoff12 = 0x36, // after 12 + TxBackoff13 = 0x37, // after 13 + TxBackoff14 = 0x38, // after 14 + TxBackoff15 = 0x39, // after 15 + TxUnderrun = 0x3a, // # frames dropped from underrun + // Hole. See REG_RX_XGMII_PROT_ERR below. + RxIpgShrink = 0x3c, // # of IPG shrinks detected + // Duplicate. See REG_STAT_STICKY10G below. + StatSticky1G = 0x3e, // tri-speed sticky bits + StatInit = 0x3f // Clear all statistics +}; + +#define REG_RX_XGMII_PROT_ERR CRA(0x4,0xa,0x3b) /* # protocol errors detected on XGMII interface */ +#define REG_STAT_STICKY10G CRA(0x4,0xa,StatSticky1G) /* 10GbE sticky bits */ + +#define REG_RX_OK_BYTES(pn) CRA(0x4,pn,RxOkBytes) +#define REG_RX_BAD_BYTES(pn) CRA(0x4,pn,RxBadBytes) +#define REG_TX_OK_BYTES(pn) CRA(0x4,pn,TxOkBytes) + +/* MII-Management Block registers */ +/* These are for MII-M interface 0, which is the bidirectional LVTTL one. If + * we hooked up to the one with separate directions, the middle 0x0 needs to + * change to 0x1. And the current errata states that MII-M 1 doesn't work. + */ + +#define REG_MIIM_STATUS CRA(0x3,0x0,0x00) /* MII-M Status */ +#define REG_MIIM_CMD CRA(0x3,0x0,0x01) /* MII-M Command */ +#define REG_MIIM_DATA CRA(0x3,0x0,0x02) /* MII-M Data */ +#define REG_MIIM_PRESCALE CRA(0x3,0x0,0x03) /* MII-M MDC Prescale */ + +#define REG_ING_FFILT_UM_EN CRA(0x2, 0, 0xd) +#define REG_ING_FFILT_BE_EN CRA(0x2, 0, 0x1d) +#define REG_ING_FFILT_VAL0 CRA(0x2, 0, 0x2d) +#define REG_ING_FFILT_VAL1 CRA(0x2, 0, 0x3d) +#define REG_ING_FFILT_MASK0 CRA(0x2, 0, 0x4d) +#define REG_ING_FFILT_MASK1 CRA(0x2, 0, 0x5d) +#define REG_ING_FFILT_MASK2 CRA(0x2, 0, 0x6d) +#define REG_ING_FFILT_ETYPE CRA(0x2, 0, 0x7d) + + +/* Whew. */ + +#endif diff --git a/drivers/net/ethernet/chelsio/cxgb3/Makefile b/drivers/net/ethernet/chelsio/cxgb3/Makefile new file mode 100644 index 000000000000..29aff78c7820 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb3/Makefile @@ -0,0 +1,8 @@ +# +# Chelsio T3 driver +# + +obj-$(CONFIG_CHELSIO_T3) += cxgb3.o + +cxgb3-objs := cxgb3_main.o ael1002.o vsc8211.o t3_hw.o mc5.o \ + xgmac.o sge.o l2t.o cxgb3_offload.o aq100x.o diff --git a/drivers/net/ethernet/chelsio/cxgb3/adapter.h b/drivers/net/ethernet/chelsio/cxgb3/adapter.h new file mode 100644 index 000000000000..8b395b537330 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb3/adapter.h @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* This file should not be included directly. Include common.h instead. */ + +#ifndef __T3_ADAPTER_H__ +#define __T3_ADAPTER_H__ + +#include +#include +#include +#include +#include +#include +#include +#include "t3cdev.h" +#include + +struct adapter; +struct sge_qset; +struct port_info; + +enum mac_idx_types { + LAN_MAC_IDX = 0, + SAN_MAC_IDX, + + MAX_MAC_IDX +}; + +struct iscsi_config { + __u8 mac_addr[ETH_ALEN]; + __u32 flags; + int (*send)(struct port_info *pi, struct sk_buff **skb); + int (*recv)(struct port_info *pi, struct sk_buff *skb); +}; + +struct port_info { + struct adapter *adapter; + struct sge_qset *qs; + u8 port_id; + u8 nqsets; + u8 first_qset; + struct cphy phy; + struct cmac mac; + struct link_config link_config; + struct net_device_stats netstats; + int activity; + __be32 iscsi_ipv4addr; + struct iscsi_config iscsic; + + int link_fault; /* link fault was detected */ +}; + +enum { /* adapter flags */ + FULL_INIT_DONE = (1 << 0), + USING_MSI = (1 << 1), + USING_MSIX = (1 << 2), + QUEUES_BOUND = (1 << 3), + TP_PARITY_INIT = (1 << 4), + NAPI_INIT = (1 << 5), +}; + +struct fl_pg_chunk { + struct page *page; + void *va; + unsigned int offset; + unsigned long *p_cnt; + dma_addr_t mapping; +}; + +struct rx_desc; +struct rx_sw_desc; + +struct sge_fl { /* SGE per free-buffer list state */ + unsigned int buf_size; /* size of each Rx buffer */ + unsigned int credits; /* # of available Rx buffers */ + unsigned int pend_cred; /* new buffers since last FL DB ring */ + unsigned int size; /* capacity of free list */ + unsigned int cidx; /* consumer index */ + unsigned int pidx; /* producer index */ + unsigned int gen; /* free list generation */ + struct fl_pg_chunk pg_chunk;/* page chunk cache */ + unsigned int use_pages; /* whether FL uses pages or sk_buffs */ + unsigned int order; /* order of page allocations */ + unsigned int alloc_size; /* size of allocated buffer */ + struct rx_desc *desc; /* address of HW Rx descriptor ring */ + struct rx_sw_desc *sdesc; /* address of SW Rx descriptor ring */ + dma_addr_t phys_addr; /* physical address of HW ring start */ + unsigned int cntxt_id; /* SGE context id for the free list */ + unsigned long empty; /* # of times queue ran out of buffers */ + unsigned long alloc_failed; /* # of times buffer allocation failed */ +}; + +/* + * Bundle size for grouping offload RX packets for delivery to the stack. + * Don't make this too big as we do prefetch on each packet in a bundle. + */ +# define RX_BUNDLE_SIZE 8 + +struct rsp_desc; + +struct sge_rspq { /* state for an SGE response queue */ + unsigned int credits; /* # of pending response credits */ + unsigned int size; /* capacity of response queue */ + unsigned int cidx; /* consumer index */ + unsigned int gen; /* current generation bit */ + unsigned int polling; /* is the queue serviced through NAPI? */ + unsigned int holdoff_tmr; /* interrupt holdoff timer in 100ns */ + unsigned int next_holdoff; /* holdoff time for next interrupt */ + unsigned int rx_recycle_buf; /* whether recycling occurred + within current sop-eop */ + struct rsp_desc *desc; /* address of HW response ring */ + dma_addr_t phys_addr; /* physical address of the ring */ + unsigned int cntxt_id; /* SGE context id for the response q */ + spinlock_t lock; /* guards response processing */ + struct sk_buff_head rx_queue; /* offload packet receive queue */ + struct sk_buff *pg_skb; /* used to build frag list in napi handler */ + + unsigned long offload_pkts; + unsigned long offload_bundles; + unsigned long eth_pkts; /* # of ethernet packets */ + unsigned long pure_rsps; /* # of pure (non-data) responses */ + unsigned long imm_data; /* responses with immediate data */ + unsigned long rx_drops; /* # of packets dropped due to no mem */ + unsigned long async_notif; /* # of asynchronous notification events */ + unsigned long empty; /* # of times queue ran out of credits */ + unsigned long nomem; /* # of responses deferred due to no mem */ + unsigned long unhandled_irqs; /* # of spurious intrs */ + unsigned long starved; + unsigned long restarted; +}; + +struct tx_desc; +struct tx_sw_desc; + +struct sge_txq { /* state for an SGE Tx queue */ + unsigned long flags; /* HW DMA fetch status */ + unsigned int in_use; /* # of in-use Tx descriptors */ + unsigned int size; /* # of descriptors */ + unsigned int processed; /* total # of descs HW has processed */ + unsigned int cleaned; /* total # of descs SW has reclaimed */ + unsigned int stop_thres; /* SW TX queue suspend threshold */ + unsigned int cidx; /* consumer index */ + unsigned int pidx; /* producer index */ + unsigned int gen; /* current value of generation bit */ + unsigned int unacked; /* Tx descriptors used since last COMPL */ + struct tx_desc *desc; /* address of HW Tx descriptor ring */ + struct tx_sw_desc *sdesc; /* address of SW Tx descriptor ring */ + spinlock_t lock; /* guards enqueueing of new packets */ + unsigned int token; /* WR token */ + dma_addr_t phys_addr; /* physical address of the ring */ + struct sk_buff_head sendq; /* List of backpressured offload packets */ + struct tasklet_struct qresume_tsk; /* restarts the queue */ + unsigned int cntxt_id; /* SGE context id for the Tx q */ + unsigned long stops; /* # of times q has been stopped */ + unsigned long restarts; /* # of queue restarts */ +}; + +enum { /* per port SGE statistics */ + SGE_PSTAT_TSO, /* # of TSO requests */ + SGE_PSTAT_RX_CSUM_GOOD, /* # of successful RX csum offloads */ + SGE_PSTAT_TX_CSUM, /* # of TX checksum offloads */ + SGE_PSTAT_VLANEX, /* # of VLAN tag extractions */ + SGE_PSTAT_VLANINS, /* # of VLAN tag insertions */ + + SGE_PSTAT_MAX /* must be last */ +}; + +struct napi_gro_fraginfo; + +struct sge_qset { /* an SGE queue set */ + struct adapter *adap; + struct napi_struct napi; + struct sge_rspq rspq; + struct sge_fl fl[SGE_RXQ_PER_SET]; + struct sge_txq txq[SGE_TXQ_PER_SET]; + int nomem; + void *lro_va; + struct net_device *netdev; + struct netdev_queue *tx_q; /* associated netdev TX queue */ + unsigned long txq_stopped; /* which Tx queues are stopped */ + struct timer_list tx_reclaim_timer; /* reclaims TX buffers */ + struct timer_list rx_reclaim_timer; /* reclaims RX buffers */ + unsigned long port_stats[SGE_PSTAT_MAX]; +} ____cacheline_aligned; + +struct sge { + struct sge_qset qs[SGE_QSETS]; + spinlock_t reg_lock; /* guards non-atomic SGE registers (eg context) */ +}; + +struct adapter { + struct t3cdev tdev; + struct list_head adapter_list; + void __iomem *regs; + struct pci_dev *pdev; + unsigned long registered_device_map; + unsigned long open_device_map; + unsigned long flags; + + const char *name; + int msg_enable; + unsigned int mmio_len; + + struct adapter_params params; + unsigned int slow_intr_mask; + unsigned long irq_stats[IRQ_NUM_STATS]; + + int msix_nvectors; + struct { + unsigned short vec; + char desc[22]; + } msix_info[SGE_QSETS + 1]; + + /* T3 modules */ + struct sge sge; + struct mc7 pmrx; + struct mc7 pmtx; + struct mc7 cm; + struct mc5 mc5; + + struct net_device *port[MAX_NPORTS]; + unsigned int check_task_cnt; + struct delayed_work adap_check_task; + struct work_struct ext_intr_handler_task; + struct work_struct fatal_error_handler_task; + struct work_struct link_fault_handler_task; + + struct work_struct db_full_task; + struct work_struct db_empty_task; + struct work_struct db_drop_task; + + struct dentry *debugfs_root; + + struct mutex mdio_lock; + spinlock_t stats_lock; + spinlock_t work_lock; + + struct sk_buff *nofail_skb; +}; + +static inline u32 t3_read_reg(struct adapter *adapter, u32 reg_addr) +{ + u32 val = readl(adapter->regs + reg_addr); + + CH_DBG(adapter, MMIO, "read register 0x%x value 0x%x\n", reg_addr, val); + return val; +} + +static inline void t3_write_reg(struct adapter *adapter, u32 reg_addr, u32 val) +{ + CH_DBG(adapter, MMIO, "setting register 0x%x to 0x%x\n", reg_addr, val); + writel(val, adapter->regs + reg_addr); +} + +static inline struct port_info *adap2pinfo(struct adapter *adap, int idx) +{ + return netdev_priv(adap->port[idx]); +} + +static inline int phy2portid(struct cphy *phy) +{ + struct adapter *adap = phy->adapter; + struct port_info *port0 = adap2pinfo(adap, 0); + + return &port0->phy == phy ? 0 : 1; +} + +#define OFFLOAD_DEVMAP_BIT 15 + +#define tdev2adap(d) container_of(d, struct adapter, tdev) + +static inline int offload_running(struct adapter *adapter) +{ + return test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map); +} + +int t3_offload_tx(struct t3cdev *tdev, struct sk_buff *skb); + +void t3_os_ext_intr_handler(struct adapter *adapter); +void t3_os_link_changed(struct adapter *adapter, int port_id, int link_status, + int speed, int duplex, int fc); +void t3_os_phymod_changed(struct adapter *adap, int port_id); +void t3_os_link_fault(struct adapter *adapter, int port_id, int state); +void t3_os_link_fault_handler(struct adapter *adapter, int port_id); + +void t3_sge_start(struct adapter *adap); +void t3_sge_stop(struct adapter *adap); +void t3_start_sge_timers(struct adapter *adap); +void t3_stop_sge_timers(struct adapter *adap); +void t3_free_sge_resources(struct adapter *adap); +void t3_sge_err_intr_handler(struct adapter *adapter); +irq_handler_t t3_intr_handler(struct adapter *adap, int polling); +netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev); +int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb); +void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p); +int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, + int irq_vec_idx, const struct qset_params *p, + int ntxq, struct net_device *dev, + struct netdev_queue *netdevq); +extern struct workqueue_struct *cxgb3_wq; + +int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size); + +#endif /* __T3_ADAPTER_H__ */ diff --git a/drivers/net/ethernet/chelsio/cxgb3/ael1002.c b/drivers/net/ethernet/chelsio/cxgb3/ael1002.c new file mode 100644 index 000000000000..2028da95afa1 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb3/ael1002.c @@ -0,0 +1,941 @@ +/* + * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "common.h" +#include "regs.h" + +enum { + AEL100X_TX_CONFIG1 = 0xc002, + AEL1002_PWR_DOWN_HI = 0xc011, + AEL1002_PWR_DOWN_LO = 0xc012, + AEL1002_XFI_EQL = 0xc015, + AEL1002_LB_EN = 0xc017, + AEL_OPT_SETTINGS = 0xc017, + AEL_I2C_CTRL = 0xc30a, + AEL_I2C_DATA = 0xc30b, + AEL_I2C_STAT = 0xc30c, + AEL2005_GPIO_CTRL = 0xc214, + AEL2005_GPIO_STAT = 0xc215, + + AEL2020_GPIO_INTR = 0xc103, /* Latch High (LH) */ + AEL2020_GPIO_CTRL = 0xc108, /* Store Clear (SC) */ + AEL2020_GPIO_STAT = 0xc10c, /* Read Only (RO) */ + AEL2020_GPIO_CFG = 0xc110, /* Read Write (RW) */ + + AEL2020_GPIO_SDA = 0, /* IN: i2c serial data */ + AEL2020_GPIO_MODDET = 1, /* IN: Module Detect */ + AEL2020_GPIO_0 = 3, /* IN: unassigned */ + AEL2020_GPIO_1 = 2, /* OUT: unassigned */ + AEL2020_GPIO_LSTAT = AEL2020_GPIO_1, /* wired to link status LED */ +}; + +enum { edc_none, edc_sr, edc_twinax }; + +/* PHY module I2C device address */ +enum { + MODULE_DEV_ADDR = 0xa0, + SFF_DEV_ADDR = 0xa2, +}; + +/* PHY transceiver type */ +enum { + phy_transtype_unknown = 0, + phy_transtype_sfp = 3, + phy_transtype_xfp = 6, +}; + +#define AEL2005_MODDET_IRQ 4 + +struct reg_val { + unsigned short mmd_addr; + unsigned short reg_addr; + unsigned short clear_bits; + unsigned short set_bits; +}; + +static int set_phy_regs(struct cphy *phy, const struct reg_val *rv) +{ + int err; + + for (err = 0; rv->mmd_addr && !err; rv++) { + if (rv->clear_bits == 0xffff) + err = t3_mdio_write(phy, rv->mmd_addr, rv->reg_addr, + rv->set_bits); + else + err = t3_mdio_change_bits(phy, rv->mmd_addr, + rv->reg_addr, rv->clear_bits, + rv->set_bits); + } + return err; +} + +static void ael100x_txon(struct cphy *phy) +{ + int tx_on_gpio = + phy->mdio.prtad == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL; + + msleep(100); + t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio); + msleep(30); +} + +/* + * Read an 8-bit word from a device attached to the PHY's i2c bus. + */ +static int ael_i2c_rd(struct cphy *phy, int dev_addr, int word_addr) +{ + int i, err; + unsigned int stat, data; + + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL_I2C_CTRL, + (dev_addr << 8) | (1 << 8) | word_addr); + if (err) + return err; + + for (i = 0; i < 200; i++) { + msleep(1); + err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_STAT, &stat); + if (err) + return err; + if ((stat & 3) == 1) { + err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_DATA, + &data); + if (err) + return err; + return data >> 8; + } + } + CH_WARN(phy->adapter, "PHY %u i2c read of dev.addr %#x.%#x timed out\n", + phy->mdio.prtad, dev_addr, word_addr); + return -ETIMEDOUT; +} + +static int ael1002_power_down(struct cphy *phy, int enable) +{ + int err; + + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, MDIO_PMA_TXDIS, !!enable); + if (!err) + err = mdio_set_flag(&phy->mdio, phy->mdio.prtad, + MDIO_MMD_PMAPMD, MDIO_CTRL1, + MDIO_CTRL1_LPOWER, enable); + return err; +} + +static int ael1002_reset(struct cphy *phy, int wait) +{ + int err; + + if ((err = ael1002_power_down(phy, 0)) || + (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL100X_TX_CONFIG1, 1)) || + (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL1002_PWR_DOWN_HI, 0)) || + (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL1002_PWR_DOWN_LO, 0)) || + (err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL1002_XFI_EQL, 0x18)) || + (err = t3_mdio_change_bits(phy, MDIO_MMD_PMAPMD, AEL1002_LB_EN, + 0, 1 << 5))) + return err; + return 0; +} + +static int ael1002_intr_noop(struct cphy *phy) +{ + return 0; +} + +/* + * Get link status for a 10GBASE-R device. + */ +static int get_link_status_r(struct cphy *phy, int *link_ok, int *speed, + int *duplex, int *fc) +{ + if (link_ok) { + unsigned int stat0, stat1, stat2; + int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, + MDIO_PMA_RXDET, &stat0); + + if (!err) + err = t3_mdio_read(phy, MDIO_MMD_PCS, + MDIO_PCS_10GBRT_STAT1, &stat1); + if (!err) + err = t3_mdio_read(phy, MDIO_MMD_PHYXS, + MDIO_PHYXS_LNSTAT, &stat2); + if (err) + return err; + *link_ok = (stat0 & stat1 & (stat2 >> 12)) & 1; + } + if (speed) + *speed = SPEED_10000; + if (duplex) + *duplex = DUPLEX_FULL; + return 0; +} + +static struct cphy_ops ael1002_ops = { + .reset = ael1002_reset, + .intr_enable = ael1002_intr_noop, + .intr_disable = ael1002_intr_noop, + .intr_clear = ael1002_intr_noop, + .intr_handler = ael1002_intr_noop, + .get_link_status = get_link_status_r, + .power_down = ael1002_power_down, + .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, +}; + +int t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) +{ + cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops, + SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE, + "10GBASE-R"); + ael100x_txon(phy); + return 0; +} + +static int ael1006_reset(struct cphy *phy, int wait) +{ + return t3_phy_reset(phy, MDIO_MMD_PMAPMD, wait); +} + +static struct cphy_ops ael1006_ops = { + .reset = ael1006_reset, + .intr_enable = t3_phy_lasi_intr_enable, + .intr_disable = t3_phy_lasi_intr_disable, + .intr_clear = t3_phy_lasi_intr_clear, + .intr_handler = t3_phy_lasi_intr_handler, + .get_link_status = get_link_status_r, + .power_down = ael1002_power_down, + .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, +}; + +int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) +{ + cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops, + SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE, + "10GBASE-SR"); + ael100x_txon(phy); + return 0; +} + +/* + * Decode our module type. + */ +static int ael2xxx_get_module_type(struct cphy *phy, int delay_ms) +{ + int v; + + if (delay_ms) + msleep(delay_ms); + + /* see SFF-8472 for below */ + v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 3); + if (v < 0) + return v; + + if (v == 0x10) + return phy_modtype_sr; + if (v == 0x20) + return phy_modtype_lr; + if (v == 0x40) + return phy_modtype_lrm; + + v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 6); + if (v < 0) + return v; + if (v != 4) + goto unknown; + + v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 10); + if (v < 0) + return v; + + if (v & 0x80) { + v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 0x12); + if (v < 0) + return v; + return v > 10 ? phy_modtype_twinax_long : phy_modtype_twinax; + } +unknown: + return phy_modtype_unknown; +} + +/* + * Code to support the Aeluros/NetLogic 2005 10Gb PHY. + */ +static int ael2005_setup_sr_edc(struct cphy *phy) +{ + static const struct reg_val regs[] = { + { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x181 }, + { MDIO_MMD_PMAPMD, 0xc010, 0xffff, 0x448a }, + { MDIO_MMD_PMAPMD, 0xc04a, 0xffff, 0x5200 }, + { 0, 0, 0, 0 } + }; + + int i, err; + + err = set_phy_regs(phy, regs); + if (err) + return err; + + msleep(50); + + if (phy->priv != edc_sr) + err = t3_get_edc_fw(phy, EDC_OPT_AEL2005, + EDC_OPT_AEL2005_SIZE); + if (err) + return err; + + for (i = 0; i < EDC_OPT_AEL2005_SIZE / sizeof(u16) && !err; i += 2) + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, + phy->phy_cache[i], + phy->phy_cache[i + 1]); + if (!err) + phy->priv = edc_sr; + return err; +} + +static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype) +{ + static const struct reg_val regs[] = { + { MDIO_MMD_PMAPMD, 0xc04a, 0xffff, 0x5a00 }, + { 0, 0, 0, 0 } + }; + static const struct reg_val preemphasis[] = { + { MDIO_MMD_PMAPMD, 0xc014, 0xffff, 0xfe16 }, + { MDIO_MMD_PMAPMD, 0xc015, 0xffff, 0xa000 }, + { 0, 0, 0, 0 } + }; + int i, err; + + err = set_phy_regs(phy, regs); + if (!err && modtype == phy_modtype_twinax_long) + err = set_phy_regs(phy, preemphasis); + if (err) + return err; + + msleep(50); + + if (phy->priv != edc_twinax) + err = t3_get_edc_fw(phy, EDC_TWX_AEL2005, + EDC_TWX_AEL2005_SIZE); + if (err) + return err; + + for (i = 0; i < EDC_TWX_AEL2005_SIZE / sizeof(u16) && !err; i += 2) + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, + phy->phy_cache[i], + phy->phy_cache[i + 1]); + if (!err) + phy->priv = edc_twinax; + return err; +} + +static int ael2005_get_module_type(struct cphy *phy, int delay_ms) +{ + int v; + unsigned int stat; + + v = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, &stat); + if (v) + return v; + + if (stat & (1 << 8)) /* module absent */ + return phy_modtype_none; + + return ael2xxx_get_module_type(phy, delay_ms); +} + +static int ael2005_intr_enable(struct cphy *phy) +{ + int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, 0x200); + return err ? err : t3_phy_lasi_intr_enable(phy); +} + +static int ael2005_intr_disable(struct cphy *phy) +{ + int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, 0x100); + return err ? err : t3_phy_lasi_intr_disable(phy); +} + +static int ael2005_intr_clear(struct cphy *phy) +{ + int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, 0xd00); + return err ? err : t3_phy_lasi_intr_clear(phy); +} + +static int ael2005_reset(struct cphy *phy, int wait) +{ + static const struct reg_val regs0[] = { + { MDIO_MMD_PMAPMD, 0xc001, 0, 1 << 5 }, + { MDIO_MMD_PMAPMD, 0xc017, 0, 1 << 5 }, + { MDIO_MMD_PMAPMD, 0xc013, 0xffff, 0xf341 }, + { MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0x8000 }, + { MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0x8100 }, + { MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0x8000 }, + { MDIO_MMD_PMAPMD, 0xc210, 0xffff, 0 }, + { 0, 0, 0, 0 } + }; + static const struct reg_val regs1[] = { + { MDIO_MMD_PMAPMD, 0xca00, 0xffff, 0x0080 }, + { MDIO_MMD_PMAPMD, 0xca12, 0xffff, 0 }, + { 0, 0, 0, 0 } + }; + + int err; + unsigned int lasi_ctrl; + + err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, + &lasi_ctrl); + if (err) + return err; + + err = t3_phy_reset(phy, MDIO_MMD_PMAPMD, 0); + if (err) + return err; + + msleep(125); + phy->priv = edc_none; + err = set_phy_regs(phy, regs0); + if (err) + return err; + + msleep(50); + + err = ael2005_get_module_type(phy, 0); + if (err < 0) + return err; + phy->modtype = err; + + if (err == phy_modtype_twinax || err == phy_modtype_twinax_long) + err = ael2005_setup_twinax_edc(phy, err); + else + err = ael2005_setup_sr_edc(phy); + if (err) + return err; + + err = set_phy_regs(phy, regs1); + if (err) + return err; + + /* reset wipes out interrupts, reenable them if they were on */ + if (lasi_ctrl & 1) + err = ael2005_intr_enable(phy); + return err; +} + +static int ael2005_intr_handler(struct cphy *phy) +{ + unsigned int stat; + int ret, edc_needed, cause = 0; + + ret = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_STAT, &stat); + if (ret) + return ret; + + if (stat & AEL2005_MODDET_IRQ) { + ret = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2005_GPIO_CTRL, + 0xd00); + if (ret) + return ret; + + /* modules have max 300 ms init time after hot plug */ + ret = ael2005_get_module_type(phy, 300); + if (ret < 0) + return ret; + + phy->modtype = ret; + if (ret == phy_modtype_none) + edc_needed = phy->priv; /* on unplug retain EDC */ + else if (ret == phy_modtype_twinax || + ret == phy_modtype_twinax_long) + edc_needed = edc_twinax; + else + edc_needed = edc_sr; + + if (edc_needed != phy->priv) { + ret = ael2005_reset(phy, 0); + return ret ? ret : cphy_cause_module_change; + } + cause = cphy_cause_module_change; + } + + ret = t3_phy_lasi_intr_handler(phy); + if (ret < 0) + return ret; + + ret |= cause; + return ret ? ret : cphy_cause_link_change; +} + +static struct cphy_ops ael2005_ops = { + .reset = ael2005_reset, + .intr_enable = ael2005_intr_enable, + .intr_disable = ael2005_intr_disable, + .intr_clear = ael2005_intr_clear, + .intr_handler = ael2005_intr_handler, + .get_link_status = get_link_status_r, + .power_down = ael1002_power_down, + .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, +}; + +int t3_ael2005_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) +{ + cphy_init(phy, adapter, phy_addr, &ael2005_ops, mdio_ops, + SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE | + SUPPORTED_IRQ, "10GBASE-R"); + msleep(125); + return t3_mdio_change_bits(phy, MDIO_MMD_PMAPMD, AEL_OPT_SETTINGS, 0, + 1 << 5); +} + +/* + * Setup EDC and other parameters for operation with an optical module. + */ +static int ael2020_setup_sr_edc(struct cphy *phy) +{ + static const struct reg_val regs[] = { + /* set CDR offset to 10 */ + { MDIO_MMD_PMAPMD, 0xcc01, 0xffff, 0x488a }, + + /* adjust 10G RX bias current */ + { MDIO_MMD_PMAPMD, 0xcb1b, 0xffff, 0x0200 }, + { MDIO_MMD_PMAPMD, 0xcb1c, 0xffff, 0x00f0 }, + { MDIO_MMD_PMAPMD, 0xcc06, 0xffff, 0x00e0 }, + + /* end */ + { 0, 0, 0, 0 } + }; + int err; + + err = set_phy_regs(phy, regs); + msleep(50); + if (err) + return err; + + phy->priv = edc_sr; + return 0; +} + +/* + * Setup EDC and other parameters for operation with an TWINAX module. + */ +static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype) +{ + /* set uC to 40MHz */ + static const struct reg_val uCclock40MHz[] = { + { MDIO_MMD_PMAPMD, 0xff28, 0xffff, 0x4001 }, + { MDIO_MMD_PMAPMD, 0xff2a, 0xffff, 0x0002 }, + { 0, 0, 0, 0 } + }; + + /* activate uC clock */ + static const struct reg_val uCclockActivate[] = { + { MDIO_MMD_PMAPMD, 0xd000, 0xffff, 0x5200 }, + { 0, 0, 0, 0 } + }; + + /* set PC to start of SRAM and activate uC */ + static const struct reg_val uCactivate[] = { + { MDIO_MMD_PMAPMD, 0xd080, 0xffff, 0x0100 }, + { MDIO_MMD_PMAPMD, 0xd092, 0xffff, 0x0000 }, + { 0, 0, 0, 0 } + }; + int i, err; + + /* set uC clock and activate it */ + err = set_phy_regs(phy, uCclock40MHz); + msleep(500); + if (err) + return err; + err = set_phy_regs(phy, uCclockActivate); + msleep(500); + if (err) + return err; + + if (phy->priv != edc_twinax) + err = t3_get_edc_fw(phy, EDC_TWX_AEL2020, + EDC_TWX_AEL2020_SIZE); + if (err) + return err; + + for (i = 0; i < EDC_TWX_AEL2020_SIZE / sizeof(u16) && !err; i += 2) + err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, + phy->phy_cache[i], + phy->phy_cache[i + 1]); + /* activate uC */ + err = set_phy_regs(phy, uCactivate); + if (!err) + phy->priv = edc_twinax; + return err; +} + +/* + * Return Module Type. + */ +static int ael2020_get_module_type(struct cphy *phy, int delay_ms) +{ + int v; + unsigned int stat; + + v = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_STAT, &stat); + if (v) + return v; + + if (stat & (0x1 << (AEL2020_GPIO_MODDET*4))) { + /* module absent */ + return phy_modtype_none; + } + + return ael2xxx_get_module_type(phy, delay_ms); +} + +/* + * Enable PHY interrupts. We enable "Module Detection" interrupts (on any + * state transition) and then generic Link Alarm Status Interrupt (LASI). + */ +static int ael2020_intr_enable(struct cphy *phy) +{ + static const struct reg_val regs[] = { + /* output Module's Loss Of Signal (LOS) to LED */ + { MDIO_MMD_PMAPMD, AEL2020_GPIO_CFG+AEL2020_GPIO_LSTAT, + 0xffff, 0x4 }, + { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, + 0xffff, 0x8 << (AEL2020_GPIO_LSTAT*4) }, + + /* enable module detect status change interrupts */ + { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, + 0xffff, 0x2 << (AEL2020_GPIO_MODDET*4) }, + + /* end */ + { 0, 0, 0, 0 } + }; + int err, link_ok = 0; + + /* set up "link status" LED and enable module change interrupts */ + err = set_phy_regs(phy, regs); + if (err) + return err; + + err = get_link_status_r(phy, &link_ok, NULL, NULL, NULL); + if (err) + return err; + if (link_ok) + t3_link_changed(phy->adapter, + phy2portid(phy)); + + err = t3_phy_lasi_intr_enable(phy); + if (err) + return err; + + return 0; +} + +/* + * Disable PHY interrupts. The mirror of the above ... + */ +static int ael2020_intr_disable(struct cphy *phy) +{ + static const struct reg_val regs[] = { + /* reset "link status" LED to "off" */ + { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, + 0xffff, 0xb << (AEL2020_GPIO_LSTAT*4) }, + + /* disable module detect status change interrupts */ + { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL, + 0xffff, 0x1 << (AEL2020_GPIO_MODDET*4) }, + + /* end */ + { 0, 0, 0, 0 } + }; + int err; + + /* turn off "link status" LED and disable module change interrupts */ + err = set_phy_regs(phy, regs); + if (err) + return err; + + return t3_phy_lasi_intr_disable(phy); +} + +/* + * Clear PHY interrupt state. + */ +static int ael2020_intr_clear(struct cphy *phy) +{ + /* + * The GPIO Interrupt register on the AEL2020 is a "Latching High" + * (LH) register which is cleared to the current state when it's read. + * Thus, we simply read the register and discard the result. + */ + unsigned int stat; + int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_INTR, &stat); + return err ? err : t3_phy_lasi_intr_clear(phy); +} + +static const struct reg_val ael2020_reset_regs[] = { + /* Erratum #2: CDRLOL asserted, causing PMA link down status */ + { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x3101 }, + + /* force XAUI to send LF when RX_LOS is asserted */ + { MDIO_MMD_PMAPMD, 0xcd40, 0xffff, 0x0001 }, + + /* allow writes to transceiver module EEPROM on i2c bus */ + { MDIO_MMD_PMAPMD, 0xff02, 0xffff, 0x0023 }, + { MDIO_MMD_PMAPMD, 0xff03, 0xffff, 0x0000 }, + { MDIO_MMD_PMAPMD, 0xff04, 0xffff, 0x0000 }, + + /* end */ + { 0, 0, 0, 0 } +}; +/* + * Reset the PHY and put it into a canonical operating state. + */ +static int ael2020_reset(struct cphy *phy, int wait) +{ + int err; + unsigned int lasi_ctrl; + + /* grab current interrupt state */ + err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, + &lasi_ctrl); + if (err) + return err; + + err = t3_phy_reset(phy, MDIO_MMD_PMAPMD, 125); + if (err) + return err; + msleep(100); + + /* basic initialization for all module types */ + phy->priv = edc_none; + err = set_phy_regs(phy, ael2020_reset_regs); + if (err) + return err; + + /* determine module type and perform appropriate initialization */ + err = ael2020_get_module_type(phy, 0); + if (err < 0) + return err; + phy->modtype = (u8)err; + if (err == phy_modtype_twinax || err == phy_modtype_twinax_long) + err = ael2020_setup_twinax_edc(phy, err); + else + err = ael2020_setup_sr_edc(phy); + if (err) + return err; + + /* reset wipes out interrupts, reenable them if they were on */ + if (lasi_ctrl & 1) + err = ael2005_intr_enable(phy); + return err; +} + +/* + * Handle a PHY interrupt. + */ +static int ael2020_intr_handler(struct cphy *phy) +{ + unsigned int stat; + int ret, edc_needed, cause = 0; + + ret = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_INTR, &stat); + if (ret) + return ret; + + if (stat & (0x1 << AEL2020_GPIO_MODDET)) { + /* modules have max 300 ms init time after hot plug */ + ret = ael2020_get_module_type(phy, 300); + if (ret < 0) + return ret; + + phy->modtype = (u8)ret; + if (ret == phy_modtype_none) + edc_needed = phy->priv; /* on unplug retain EDC */ + else if (ret == phy_modtype_twinax || + ret == phy_modtype_twinax_long) + edc_needed = edc_twinax; + else + edc_needed = edc_sr; + + if (edc_needed != phy->priv) { + ret = ael2020_reset(phy, 0); + return ret ? ret : cphy_cause_module_change; + } + cause = cphy_cause_module_change; + } + + ret = t3_phy_lasi_intr_handler(phy); + if (ret < 0) + return ret; + + ret |= cause; + return ret ? ret : cphy_cause_link_change; +} + +static struct cphy_ops ael2020_ops = { + .reset = ael2020_reset, + .intr_enable = ael2020_intr_enable, + .intr_disable = ael2020_intr_disable, + .intr_clear = ael2020_intr_clear, + .intr_handler = ael2020_intr_handler, + .get_link_status = get_link_status_r, + .power_down = ael1002_power_down, + .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, +}; + +int t3_ael2020_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, + const struct mdio_ops *mdio_ops) +{ + int err; + + cphy_init(phy, adapter, phy_addr, &ael2020_ops, mdio_ops, + SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE | + SUPPORTED_IRQ, "10GBASE-R"); + msleep(125); + + err = set_phy_regs(phy, ael2020_reset_regs); + if (err) + return err; + return 0; +} + +/* + * Get link status for a 10GBASE-X device. + */ +static int get_link_status_x(struct cphy *phy, int *link_ok, int *speed, + int *duplex, int *fc) +{ + if (link_ok) { + unsigned int stat0, stat1, stat2; + int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, + MDIO_PMA_RXDET, &stat0); + + if (!err) + err = t3_mdio_read(phy, MDIO_MMD_PCS, + MDIO_PCS_10GBX_STAT1, &stat1); + if (!err) + err = t3_mdio_read(phy, MDIO_MMD_PHYXS, + MDIO_PHYXS_LNSTAT, &stat2); + if (err) + return err; + *link_ok = (stat0 & (stat1 >> 12) & (stat2 >> 12)) & 1; + } + if (speed) + *speed = SPEED_10000; + if (duplex) + *duplex = DUPLEX_FULL; + return 0; +} + +static struct cphy_ops qt2045_ops = { + .reset = ael1006_reset, + .intr_enable = t3_phy_lasi_intr_enable, + .intr_disable = t3_phy_lasi_intr_disable, + .intr_clear = t3_phy_lasi_intr_clear, + .intr_handler = t3_phy_lasi_intr_handler, + .get_link_status = get_link_status_x, + .power_down = ael1002_power_down, + .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, +}; + +int t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) +{ + unsigned int stat; + + cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops, + SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP, + "10GBASE-CX4"); + + /* + * Some cards where the PHY is supposed to be at address 0 actually + * have it at 1. + */ + if (!phy_addr && + !t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_STAT1, &stat) && + stat == 0xffff) + phy->mdio.prtad = 1; + return 0; +} + +static int xaui_direct_reset(struct cphy *phy, int wait) +{ + return 0; +} + +static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok, + int *speed, int *duplex, int *fc) +{ + if (link_ok) { + unsigned int status; + int prtad = phy->mdio.prtad; + + status = t3_read_reg(phy->adapter, + XGM_REG(A_XGM_SERDES_STAT0, prtad)) | + t3_read_reg(phy->adapter, + XGM_REG(A_XGM_SERDES_STAT1, prtad)) | + t3_read_reg(phy->adapter, + XGM_REG(A_XGM_SERDES_STAT2, prtad)) | + t3_read_reg(phy->adapter, + XGM_REG(A_XGM_SERDES_STAT3, prtad)); + *link_ok = !(status & F_LOWSIG0); + } + if (speed) + *speed = SPEED_10000; + if (duplex) + *duplex = DUPLEX_FULL; + return 0; +} + +static int xaui_direct_power_down(struct cphy *phy, int enable) +{ + return 0; +} + +static struct cphy_ops xaui_direct_ops = { + .reset = xaui_direct_reset, + .intr_enable = ael1002_intr_noop, + .intr_disable = ael1002_intr_noop, + .intr_clear = ael1002_intr_noop, + .intr_handler = ael1002_intr_noop, + .get_link_status = xaui_direct_get_link_status, + .power_down = xaui_direct_power_down, +}; + +int t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) +{ + cphy_init(phy, adapter, phy_addr, &xaui_direct_ops, mdio_ops, + SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_TP, + "10GBASE-CX4"); + return 0; +} diff --git a/drivers/net/ethernet/chelsio/cxgb3/aq100x.c b/drivers/net/ethernet/chelsio/cxgb3/aq100x.c new file mode 100644 index 000000000000..341b7ef1508f --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb3/aq100x.c @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "common.h" +#include "regs.h" + +enum { + /* MDIO_DEV_PMA_PMD registers */ + AQ_LINK_STAT = 0xe800, + AQ_IMASK_PMA = 0xf000, + + /* MDIO_DEV_XGXS registers */ + AQ_XAUI_RX_CFG = 0xc400, + AQ_XAUI_TX_CFG = 0xe400, + + /* MDIO_DEV_ANEG registers */ + AQ_1G_CTRL = 0xc400, + AQ_ANEG_STAT = 0xc800, + + /* MDIO_DEV_VEND1 registers */ + AQ_FW_VERSION = 0x0020, + AQ_IFLAG_GLOBAL = 0xfc00, + AQ_IMASK_GLOBAL = 0xff00, +}; + +enum { + IMASK_PMA = 1 << 2, + IMASK_GLOBAL = 1 << 15, + ADV_1G_FULL = 1 << 15, + ADV_1G_HALF = 1 << 14, + ADV_10G_FULL = 1 << 12, + AQ_RESET = (1 << 14) | (1 << 15), + AQ_LOWPOWER = 1 << 12, +}; + +static int aq100x_reset(struct cphy *phy, int wait) +{ + /* + * Ignore the caller specified wait time; always wait for the reset to + * complete. Can take up to 3s. + */ + int err = t3_phy_reset(phy, MDIO_MMD_VEND1, 3000); + + if (err) + CH_WARN(phy->adapter, "PHY%d: reset failed (0x%x).\n", + phy->mdio.prtad, err); + + return err; +} + +static int aq100x_intr_enable(struct cphy *phy) +{ + int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AQ_IMASK_PMA, IMASK_PMA); + if (err) + return err; + + err = t3_mdio_write(phy, MDIO_MMD_VEND1, AQ_IMASK_GLOBAL, IMASK_GLOBAL); + return err; +} + +static int aq100x_intr_disable(struct cphy *phy) +{ + return t3_mdio_write(phy, MDIO_MMD_VEND1, AQ_IMASK_GLOBAL, 0); +} + +static int aq100x_intr_clear(struct cphy *phy) +{ + unsigned int v; + + t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_IFLAG_GLOBAL, &v); + t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_STAT1, &v); + + return 0; +} + +static int aq100x_intr_handler(struct cphy *phy) +{ + int err; + unsigned int cause, v; + + err = t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_IFLAG_GLOBAL, &cause); + if (err) + return err; + + /* Read (and reset) the latching version of the status */ + t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_STAT1, &v); + + return cphy_cause_link_change; +} + +static int aq100x_power_down(struct cphy *phy, int off) +{ + return mdio_set_flag(&phy->mdio, phy->mdio.prtad, + MDIO_MMD_PMAPMD, MDIO_CTRL1, + MDIO_CTRL1_LPOWER, off); +} + +static int aq100x_autoneg_enable(struct cphy *phy) +{ + int err; + + err = aq100x_power_down(phy, 0); + if (!err) + err = mdio_set_flag(&phy->mdio, phy->mdio.prtad, + MDIO_MMD_AN, MDIO_CTRL1, + BMCR_ANENABLE | BMCR_ANRESTART, 1); + + return err; +} + +static int aq100x_autoneg_restart(struct cphy *phy) +{ + int err; + + err = aq100x_power_down(phy, 0); + if (!err) + err = mdio_set_flag(&phy->mdio, phy->mdio.prtad, + MDIO_MMD_AN, MDIO_CTRL1, + BMCR_ANENABLE | BMCR_ANRESTART, 1); + + return err; +} + +static int aq100x_advertise(struct cphy *phy, unsigned int advertise_map) +{ + unsigned int adv; + int err; + + /* 10G advertisement */ + adv = 0; + if (advertise_map & ADVERTISED_10000baseT_Full) + adv |= ADV_10G_FULL; + err = t3_mdio_change_bits(phy, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL, + ADV_10G_FULL, adv); + if (err) + return err; + + /* 1G advertisement */ + adv = 0; + if (advertise_map & ADVERTISED_1000baseT_Full) + adv |= ADV_1G_FULL; + if (advertise_map & ADVERTISED_1000baseT_Half) + adv |= ADV_1G_HALF; + err = t3_mdio_change_bits(phy, MDIO_MMD_AN, AQ_1G_CTRL, + ADV_1G_FULL | ADV_1G_HALF, adv); + if (err) + return err; + + /* 100M, pause advertisement */ + adv = 0; + if (advertise_map & ADVERTISED_100baseT_Half) + adv |= ADVERTISE_100HALF; + if (advertise_map & ADVERTISED_100baseT_Full) + adv |= ADVERTISE_100FULL; + if (advertise_map & ADVERTISED_Pause) + adv |= ADVERTISE_PAUSE_CAP; + if (advertise_map & ADVERTISED_Asym_Pause) + adv |= ADVERTISE_PAUSE_ASYM; + err = t3_mdio_change_bits(phy, MDIO_MMD_AN, MDIO_AN_ADVERTISE, + 0xfe0, adv); + + return err; +} + +static int aq100x_set_loopback(struct cphy *phy, int mmd, int dir, int enable) +{ + return mdio_set_flag(&phy->mdio, phy->mdio.prtad, + MDIO_MMD_PMAPMD, MDIO_CTRL1, + BMCR_LOOPBACK, enable); +} + +static int aq100x_set_speed_duplex(struct cphy *phy, int speed, int duplex) +{ + /* no can do */ + return -1; +} + +static int aq100x_get_link_status(struct cphy *phy, int *link_ok, + int *speed, int *duplex, int *fc) +{ + int err; + unsigned int v; + + if (link_ok) { + err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AQ_LINK_STAT, &v); + if (err) + return err; + + *link_ok = v & 1; + if (!*link_ok) + return 0; + } + + err = t3_mdio_read(phy, MDIO_MMD_AN, AQ_ANEG_STAT, &v); + if (err) + return err; + + if (speed) { + switch (v & 0x6) { + case 0x6: + *speed = SPEED_10000; + break; + case 0x4: + *speed = SPEED_1000; + break; + case 0x2: + *speed = SPEED_100; + break; + case 0x0: + *speed = SPEED_10; + break; + } + } + + if (duplex) + *duplex = v & 1 ? DUPLEX_FULL : DUPLEX_HALF; + + return 0; +} + +static struct cphy_ops aq100x_ops = { + .reset = aq100x_reset, + .intr_enable = aq100x_intr_enable, + .intr_disable = aq100x_intr_disable, + .intr_clear = aq100x_intr_clear, + .intr_handler = aq100x_intr_handler, + .autoneg_enable = aq100x_autoneg_enable, + .autoneg_restart = aq100x_autoneg_restart, + .advertise = aq100x_advertise, + .set_loopback = aq100x_set_loopback, + .set_speed_duplex = aq100x_set_speed_duplex, + .get_link_status = aq100x_get_link_status, + .power_down = aq100x_power_down, + .mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS, +}; + +int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, + const struct mdio_ops *mdio_ops) +{ + unsigned int v, v2, gpio, wait; + int err; + + cphy_init(phy, adapter, phy_addr, &aq100x_ops, mdio_ops, + SUPPORTED_1000baseT_Full | SUPPORTED_10000baseT_Full | + SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_AUI, + "1000/10GBASE-T"); + + /* + * The PHY has been out of reset ever since the system powered up. So + * we do a hard reset over here. + */ + gpio = phy_addr ? F_GPIO10_OUT_VAL : F_GPIO6_OUT_VAL; + t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, 0); + msleep(1); + t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, gpio); + + /* + * Give it enough time to load the firmware and get ready for mdio. + */ + msleep(1000); + wait = 500; /* in 10ms increments */ + do { + err = t3_mdio_read(phy, MDIO_MMD_VEND1, MDIO_CTRL1, &v); + if (err || v == 0xffff) { + + /* Allow prep_adapter to succeed when ffff is read */ + + CH_WARN(adapter, "PHY%d: reset failed (0x%x, 0x%x).\n", + phy_addr, err, v); + goto done; + } + + v &= AQ_RESET; + if (v) + msleep(10); + } while (v && --wait); + if (v) { + CH_WARN(adapter, "PHY%d: reset timed out (0x%x).\n", + phy_addr, v); + + goto done; /* let prep_adapter succeed */ + } + + /* Datasheet says 3s max but this has been observed */ + wait = (500 - wait) * 10 + 1000; + if (wait > 3000) + CH_WARN(adapter, "PHY%d: reset took %ums\n", phy_addr, wait); + + /* Firmware version check. */ + t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_FW_VERSION, &v); + if (v != 101) + CH_WARN(adapter, "PHY%d: unsupported firmware %d\n", + phy_addr, v); + + /* + * The PHY should start in really-low-power mode. Prepare it for normal + * operations. + */ + err = t3_mdio_read(phy, MDIO_MMD_VEND1, MDIO_CTRL1, &v); + if (err) + return err; + if (v & AQ_LOWPOWER) { + err = t3_mdio_change_bits(phy, MDIO_MMD_VEND1, MDIO_CTRL1, + AQ_LOWPOWER, 0); + if (err) + return err; + msleep(10); + } else + CH_WARN(adapter, "PHY%d does not start in low power mode.\n", + phy_addr); + + /* + * Verify XAUI settings, but let prep succeed no matter what. + */ + v = v2 = 0; + t3_mdio_read(phy, MDIO_MMD_PHYXS, AQ_XAUI_RX_CFG, &v); + t3_mdio_read(phy, MDIO_MMD_PHYXS, AQ_XAUI_TX_CFG, &v2); + if (v != 0x1b || v2 != 0x1b) + CH_WARN(adapter, + "PHY%d: incorrect XAUI settings (0x%x, 0x%x).\n", + phy_addr, v, v2); + +done: + return err; +} diff --git a/drivers/net/ethernet/chelsio/cxgb3/common.h b/drivers/net/ethernet/chelsio/cxgb3/common.h new file mode 100644 index 000000000000..df01b6343241 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb3/common.h @@ -0,0 +1,775 @@ +/* + * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __CHELSIO_COMMON_H +#define __CHELSIO_COMMON_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "version.h" + +#define CH_ERR(adap, fmt, ...) dev_err(&adap->pdev->dev, fmt, ## __VA_ARGS__) +#define CH_WARN(adap, fmt, ...) dev_warn(&adap->pdev->dev, fmt, ## __VA_ARGS__) +#define CH_ALERT(adap, fmt, ...) \ + dev_printk(KERN_ALERT, &adap->pdev->dev, fmt, ## __VA_ARGS__) + +/* + * More powerful macro that selectively prints messages based on msg_enable. + * For info and debugging messages. + */ +#define CH_MSG(adapter, level, category, fmt, ...) do { \ + if ((adapter)->msg_enable & NETIF_MSG_##category) \ + dev_printk(KERN_##level, &adapter->pdev->dev, fmt, \ + ## __VA_ARGS__); \ +} while (0) + +#ifdef DEBUG +# define CH_DBG(adapter, category, fmt, ...) \ + CH_MSG(adapter, DEBUG, category, fmt, ## __VA_ARGS__) +#else +# define CH_DBG(adapter, category, fmt, ...) +#endif + +/* Additional NETIF_MSG_* categories */ +#define NETIF_MSG_MMIO 0x8000000 + +enum { + MAX_NPORTS = 2, /* max # of ports */ + MAX_FRAME_SIZE = 10240, /* max MAC frame size, including header + FCS */ + EEPROMSIZE = 8192, /* Serial EEPROM size */ + SERNUM_LEN = 16, /* Serial # length */ + 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 */ + PROTO_SRAM_LINES = 128, /* size of TP sram */ +}; + +#define MAX_RX_COALESCING_LEN 12288U + +enum { + PAUSE_RX = 1 << 0, + PAUSE_TX = 1 << 1, + PAUSE_AUTONEG = 1 << 2 +}; + +enum { + SUPPORTED_IRQ = 1 << 24 +}; + +enum { /* adapter interrupt-maintained statistics */ + STAT_ULP_CH0_PBL_OOB, + STAT_ULP_CH1_PBL_OOB, + STAT_PCI_CORR_ECC, + + IRQ_NUM_STATS /* keep last */ +}; + +#define TP_VERSION_MAJOR 1 +#define TP_VERSION_MINOR 1 +#define TP_VERSION_MICRO 0 + +#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 { + SGE_QSETS = 8, /* # of SGE Tx/Rx/RspQ sets */ + SGE_RXQ_PER_SET = 2, /* # of Rx queues per set */ + SGE_TXQ_PER_SET = 3 /* # of Tx queues per set */ +}; + +enum sge_context_type { /* SGE egress context types */ + SGE_CNTXT_RDMA = 0, + SGE_CNTXT_ETH = 2, + SGE_CNTXT_OFLD = 4, + SGE_CNTXT_CTRL = 5 +}; + +enum { + AN_PKT_SIZE = 32, /* async notification packet size */ + IMMED_PKT_SIZE = 48 /* packet size for immediate data */ +}; + +struct sg_ent { /* SGE scatter/gather entry */ + __be32 len[2]; + __be64 addr[2]; +}; + +#ifndef SGE_NUM_GENBITS +/* Must be 1 or 2 */ +# define SGE_NUM_GENBITS 2 +#endif + +#define TX_DESC_FLITS 16U +#define WR_FLITS (TX_DESC_FLITS + 1 - SGE_NUM_GENBITS) + +struct cphy; +struct adapter; + +struct mdio_ops { + int (*read)(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr); + int (*write)(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr, u16 val); + unsigned mode_support; +}; + +struct adapter_info { + 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 int gpio_out; /* GPIO output settings */ + unsigned char gpio_intr[MAX_NPORTS]; /* GPIO PHY IRQ pins */ + unsigned long caps; /* adapter capabilities */ + const struct mdio_ops *mdio_ops; /* MDIO operations */ + const char *desc; /* product description */ +}; + +struct mc5_stats { + unsigned long parity_err; + unsigned long active_rgn_full; + unsigned long nfa_srch_err; + unsigned long unknown_cmd; + unsigned long reqq_parity_err; + unsigned long dispq_parity_err; + unsigned long del_act_empty; +}; + +struct mc7_stats { + unsigned long corr_err; + unsigned long uncorr_err; + unsigned long parity_err; + unsigned long addr_err; +}; + +struct mac_stats { + u64 tx_octets; /* total # of octets in good frames */ + u64 tx_octets_bad; /* total # of octets in error frames */ + u64 tx_frames; /* all good frames */ + u64 tx_mcast_frames; /* good multicast frames */ + u64 tx_bcast_frames; /* good broadcast frames */ + u64 tx_pause; /* # of transmitted pause frames */ + u64 tx_deferred; /* frames with deferred transmissions */ + u64 tx_late_collisions; /* # of late collisions */ + u64 tx_total_collisions; /* # of total collisions */ + u64 tx_excess_collisions; /* frame errors from excessive collissions */ + u64 tx_underrun; /* # of Tx FIFO underruns */ + u64 tx_len_errs; /* # of Tx length errors */ + u64 tx_mac_internal_errs; /* # of internal MAC errors on Tx */ + u64 tx_excess_deferral; /* # of frames with excessive deferral */ + u64 tx_fcs_errs; /* # of frames with bad FCS */ + + u64 tx_frames_64; /* # of Tx frames in a particular range */ + u64 tx_frames_65_127; + u64 tx_frames_128_255; + u64 tx_frames_256_511; + u64 tx_frames_512_1023; + u64 tx_frames_1024_1518; + u64 tx_frames_1519_max; + + u64 rx_octets; /* total # of octets in good frames */ + u64 rx_octets_bad; /* total # of octets in error frames */ + u64 rx_frames; /* all good frames */ + u64 rx_mcast_frames; /* good multicast frames */ + u64 rx_bcast_frames; /* good broadcast frames */ + u64 rx_pause; /* # of received pause frames */ + u64 rx_fcs_errs; /* # of received frames with bad FCS */ + u64 rx_align_errs; /* alignment errors */ + u64 rx_symbol_errs; /* symbol errors */ + u64 rx_data_errs; /* data errors */ + u64 rx_sequence_errs; /* sequence errors */ + u64 rx_runt; /* # of runt frames */ + u64 rx_jabber; /* # of jabber frames */ + u64 rx_short; /* # of short frames */ + u64 rx_too_long; /* # of oversized frames */ + u64 rx_mac_internal_errs; /* # of internal MAC errors on Rx */ + + u64 rx_frames_64; /* # of Rx frames in a particular range */ + u64 rx_frames_65_127; + u64 rx_frames_128_255; + u64 rx_frames_256_511; + u64 rx_frames_512_1023; + u64 rx_frames_1024_1518; + u64 rx_frames_1519_max; + + u64 rx_cong_drops; /* # of Rx drops due to SGE congestion */ + + unsigned long tx_fifo_parity_err; + unsigned long rx_fifo_parity_err; + unsigned long tx_fifo_urun; + unsigned long rx_fifo_ovfl; + unsigned long serdes_signal_loss; + unsigned long xaui_pcs_ctc_err; + unsigned long xaui_pcs_align_change; + + unsigned long num_toggled; /* # times toggled TxEn due to stuck TX */ + unsigned long num_resets; /* # times reset due to stuck TX */ + + unsigned long link_faults; /* # detected link faults */ +}; + +struct tp_mib_stats { + u32 ipInReceive_hi; + u32 ipInReceive_lo; + u32 ipInHdrErrors_hi; + u32 ipInHdrErrors_lo; + u32 ipInAddrErrors_hi; + u32 ipInAddrErrors_lo; + u32 ipInUnknownProtos_hi; + u32 ipInUnknownProtos_lo; + u32 ipInDiscards_hi; + u32 ipInDiscards_lo; + u32 ipInDelivers_hi; + u32 ipInDelivers_lo; + u32 ipOutRequests_hi; + u32 ipOutRequests_lo; + u32 ipOutDiscards_hi; + u32 ipOutDiscards_lo; + u32 ipOutNoRoutes_hi; + u32 ipOutNoRoutes_lo; + u32 ipReasmTimeout; + u32 ipReasmReqds; + u32 ipReasmOKs; + u32 ipReasmFails; + + u32 reserved[8]; + + u32 tcpActiveOpens; + u32 tcpPassiveOpens; + u32 tcpAttemptFails; + u32 tcpEstabResets; + u32 tcpOutRsts; + u32 tcpCurrEstab; + u32 tcpInSegs_hi; + u32 tcpInSegs_lo; + u32 tcpOutSegs_hi; + u32 tcpOutSegs_lo; + u32 tcpRetransSeg_hi; + u32 tcpRetransSeg_lo; + u32 tcpInErrs_hi; + u32 tcpInErrs_lo; + u32 tcpRtoMin; + u32 tcpRtoMax; +}; + +struct tp_params { + unsigned int nchan; /* # of channels */ + unsigned int pmrx_size; /* total PMRX capacity */ + unsigned int pmtx_size; /* total PMTX capacity */ + unsigned int cm_size; /* total CM capacity */ + unsigned int chan_rx_size; /* per channel Rx size */ + unsigned int chan_tx_size; /* per channel Tx size */ + unsigned int rx_pg_size; /* Rx page size */ + unsigned int tx_pg_size; /* Tx page size */ + unsigned int rx_num_pgs; /* # of Rx pages */ + unsigned int tx_num_pgs; /* # of Tx pages */ + unsigned int ntimer_qs; /* # of timer queues */ +}; + +struct qset_params { /* SGE queue set parameters */ + unsigned int polling; /* polling/interrupt service for rspq */ + unsigned int coalesce_usecs; /* irq coalescing timer */ + unsigned int rspq_size; /* # of entries in response queue */ + unsigned int fl_size; /* # of entries in regular free list */ + unsigned int jumbo_size; /* # of entries in jumbo free list */ + unsigned int txq_size[SGE_TXQ_PER_SET]; /* Tx queue sizes */ + unsigned int cong_thres; /* FL congestion threshold */ + unsigned int vector; /* Interrupt (line or vector) number */ +}; + +struct sge_params { + unsigned int max_pkt_size; /* max offload pkt size */ + struct qset_params qset[SGE_QSETS]; +}; + +struct mc5_params { + unsigned int mode; /* selects MC5 width */ + unsigned int nservers; /* size of server region */ + unsigned int nfilters; /* size of filter region */ + unsigned int nroutes; /* size of routing region */ +}; + +/* Default MC5 region sizes */ +enum { + DEFAULT_NSERVERS = 512, + DEFAULT_NFILTERS = 128 +}; + +/* MC5 modes, these must be non-0 */ +enum { + MC5_MODE_144_BIT = 1, + MC5_MODE_72_BIT = 2 +}; + +/* MC5 min active region size */ +enum { MC5_MIN_TIDS = 16 }; + +struct vpd_params { + unsigned int cclk; + unsigned int mclk; + unsigned int uclk; + unsigned int mdc; + unsigned int mem_timing; + u8 sn[SERNUM_LEN + 1]; + u8 eth_base[6]; + u8 port_type[MAX_NPORTS]; + unsigned short xauicfg[2]; +}; + +struct pci_params { + unsigned int vpd_cap_addr; + unsigned short speed; + unsigned char width; + unsigned char variant; +}; + +enum { + PCI_VARIANT_PCI, + PCI_VARIANT_PCIX_MODE1_PARITY, + PCI_VARIANT_PCIX_MODE1_ECC, + PCI_VARIANT_PCIX_266_MODE2, + PCI_VARIANT_PCIE +}; + +struct adapter_params { + struct sge_params sge; + struct mc5_params mc5; + struct tp_params tp; + struct vpd_params vpd; + struct pci_params pci; + + const struct adapter_info *info; + + unsigned short mtus[NMTUS]; + unsigned short a_wnd[NCCTRL_WIN]; + unsigned short b_wnd[NCCTRL_WIN]; + + 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 */ + unsigned int offload; +}; + +enum { /* chip revisions */ + T3_REV_A = 0, + T3_REV_B = 2, + T3_REV_B2 = 3, + T3_REV_C = 4, +}; + +struct trace_params { + u32 sip; + u32 sip_mask; + u32 dip; + u32 dip_mask; + u16 sport; + u16 sport_mask; + u16 dport; + u16 dport_mask; + u32 vlan:12; + u32 vlan_mask:12; + u32 intf:4; + u32 intf_mask:4; + u8 proto; + u8 proto_mask; +}; + +struct link_config { + unsigned int supported; /* link capabilities */ + unsigned int advertising; /* advertised capabilities */ + unsigned short requested_speed; /* speed user has requested */ + unsigned short speed; /* actual link speed */ + unsigned char requested_duplex; /* duplex user has requested */ + unsigned char duplex; /* actual link duplex */ + unsigned char requested_fc; /* flow control user has requested */ + unsigned char fc; /* actual link flow control */ + unsigned char autoneg; /* autonegotiating? */ + unsigned int link_ok; /* link up? */ +}; + +#define SPEED_INVALID 0xffff +#define DUPLEX_INVALID 0xff + +struct mc5 { + struct adapter *adapter; + unsigned int tcam_size; + unsigned char part_type; + unsigned char parity_enabled; + unsigned char mode; + struct mc5_stats stats; +}; + +static inline unsigned int t3_mc5_size(const struct mc5 *p) +{ + return p->tcam_size; +} + +struct mc7 { + struct adapter *adapter; /* backpointer to adapter */ + unsigned int size; /* memory size in bytes */ + unsigned int width; /* MC7 interface width */ + unsigned int offset; /* register address offset for MC7 instance */ + const char *name; /* name of MC7 instance */ + struct mc7_stats stats; /* MC7 statistics */ +}; + +static inline unsigned int t3_mc7_size(const struct mc7 *p) +{ + return p->size; +} + +struct cmac { + struct adapter *adapter; + unsigned int offset; + unsigned int nucast; /* # of address filters for unicast MACs */ + unsigned int tx_tcnt; + 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; + u64 rx_pause; + struct mac_stats stats; +}; + +enum { + MAC_DIRECTION_RX = 1, + MAC_DIRECTION_TX = 2, + MAC_RXFIFO_SIZE = 32768 +}; + +/* PHY loopback direction */ +enum { + PHY_LOOPBACK_TX = 1, + PHY_LOOPBACK_RX = 2 +}; + +/* PHY interrupt types */ +enum { + cphy_cause_link_change = 1, + cphy_cause_fifo_error = 2, + cphy_cause_module_change = 4, +}; + +/* PHY module types */ +enum { + phy_modtype_none, + phy_modtype_sr, + phy_modtype_lr, + phy_modtype_lrm, + phy_modtype_twinax, + phy_modtype_twinax_long, + phy_modtype_unknown +}; + +/* PHY operations */ +struct cphy_ops { + int (*reset)(struct cphy *phy, int wait); + + int (*intr_enable)(struct cphy *phy); + int (*intr_disable)(struct cphy *phy); + int (*intr_clear)(struct cphy *phy); + int (*intr_handler)(struct cphy *phy); + + int (*autoneg_enable)(struct cphy *phy); + int (*autoneg_restart)(struct cphy *phy); + + int (*advertise)(struct cphy *phy, unsigned int advertise_map); + int (*set_loopback)(struct cphy *phy, int mmd, int dir, int enable); + int (*set_speed_duplex)(struct cphy *phy, int speed, int duplex); + int (*get_link_status)(struct cphy *phy, int *link_ok, int *speed, + int *duplex, int *fc); + int (*power_down)(struct cphy *phy, int enable); + + u32 mmds; +}; +enum { + EDC_OPT_AEL2005 = 0, + EDC_OPT_AEL2005_SIZE = 1084, + EDC_TWX_AEL2005 = 1, + EDC_TWX_AEL2005_SIZE = 1464, + EDC_TWX_AEL2020 = 2, + EDC_TWX_AEL2020_SIZE = 1628, + EDC_MAX_SIZE = EDC_TWX_AEL2020_SIZE, /* Max cache size */ +}; + +/* A PHY instance */ +struct cphy { + u8 modtype; /* PHY module type */ + short priv; /* scratch pad */ + unsigned int caps; /* PHY capabilities */ + struct adapter *adapter; /* associated adapter */ + const char *desc; /* PHY description */ + unsigned long fifo_errors; /* FIFO over/under-flows */ + const struct cphy_ops *ops; /* PHY operations */ + struct mdio_if_info mdio; + u16 phy_cache[EDC_MAX_SIZE]; /* EDC cache */ +}; + +/* Convenience MDIO read/write wrappers */ +static inline int t3_mdio_read(struct cphy *phy, int mmd, int reg, + unsigned int *valp) +{ + int rc = phy->mdio.mdio_read(phy->mdio.dev, phy->mdio.prtad, mmd, reg); + *valp = (rc >= 0) ? rc : -1; + return (rc >= 0) ? 0 : rc; +} + +static inline int t3_mdio_write(struct cphy *phy, int mmd, int reg, + unsigned int val) +{ + return phy->mdio.mdio_write(phy->mdio.dev, phy->mdio.prtad, mmd, + reg, val); +} + +/* Convenience initializer */ +static inline void cphy_init(struct cphy *phy, struct adapter *adapter, + int phy_addr, struct cphy_ops *phy_ops, + const struct mdio_ops *mdio_ops, + unsigned int caps, const char *desc) +{ + phy->caps = caps; + phy->adapter = adapter; + phy->desc = desc; + phy->ops = phy_ops; + if (mdio_ops) { + phy->mdio.prtad = phy_addr; + phy->mdio.mmds = phy_ops->mmds; + phy->mdio.mode_support = mdio_ops->mode_support; + phy->mdio.mdio_read = mdio_ops->read; + phy->mdio.mdio_write = mdio_ops->write; + } +} + +/* Accumulate MAC statistics every 180 seconds. For 1G we multiply by 10. */ +#define MAC_STATS_ACCUM_SECS 180 + +#define XGM_REG(reg_addr, idx) \ + ((reg_addr) + (idx) * (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR)) + +struct addr_val_pair { + unsigned int reg_addr; + unsigned int val; +}; + +#include "adapter.h" + +#ifndef PCI_VENDOR_ID_CHELSIO +# define PCI_VENDOR_ID_CHELSIO 0x1425 +#endif + +#define for_each_port(adapter, iter) \ + for (iter = 0; iter < (adapter)->params.nports; ++iter) + +#define adapter_info(adap) ((adap)->params.info) + +static inline int uses_xaui(const struct adapter *adap) +{ + return adapter_info(adap)->caps & SUPPORTED_AUI; +} + +static inline int is_10G(const struct adapter *adap) +{ + return adapter_info(adap)->caps & SUPPORTED_10000baseT_Full; +} + +static inline int is_offload(const struct adapter *adap) +{ + return adap->params.offload; +} + +static inline unsigned int core_ticks_per_usec(const struct adapter *adap) +{ + return adap->params.vpd.cclk / 1000; +} + +static inline unsigned int is_pcie(const struct adapter *adap) +{ + return adap->params.pci.variant == PCI_VARIANT_PCIE; +} + +void t3_set_reg_field(struct adapter *adap, unsigned int addr, u32 mask, + u32 val); +void t3_write_regs(struct adapter *adapter, const struct addr_val_pair *p, + int n, unsigned int offset); +int t3_wait_op_done_val(struct adapter *adapter, int reg, u32 mask, + int polarity, int attempts, int delay, u32 *valp); +static inline int t3_wait_op_done(struct adapter *adapter, int reg, u32 mask, + int polarity, int attempts, int delay) +{ + return t3_wait_op_done_val(adapter, reg, mask, polarity, attempts, + delay, NULL); +} +int t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear, + unsigned int set); +int t3_phy_reset(struct cphy *phy, int mmd, int wait); +int t3_phy_advertise(struct cphy *phy, unsigned int advert); +int t3_phy_advertise_fiber(struct cphy *phy, unsigned int advert); +int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex); +int t3_phy_lasi_intr_enable(struct cphy *phy); +int t3_phy_lasi_intr_disable(struct cphy *phy); +int t3_phy_lasi_intr_clear(struct cphy *phy); +int t3_phy_lasi_intr_handler(struct cphy *phy); + +void t3_intr_enable(struct adapter *adapter); +void t3_intr_disable(struct adapter *adapter); +void t3_intr_clear(struct adapter *adapter); +void t3_xgm_intr_enable(struct adapter *adapter, int idx); +void t3_xgm_intr_disable(struct adapter *adapter, int idx); +void t3_port_intr_enable(struct adapter *adapter, int idx); +void t3_port_intr_disable(struct adapter *adapter, int idx); +int t3_slow_intr_handler(struct adapter *adapter); +int t3_phy_intr_handler(struct adapter *adapter); + +void t3_link_changed(struct adapter *adapter, int port_id); +void t3_link_fault(struct adapter *adapter, int port_id); +int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc); +const struct adapter_info *t3_get_adapter_info(unsigned int board_id); +int t3_seeprom_read(struct adapter *adapter, u32 addr, __le32 *data); +int t3_seeprom_write(struct adapter *adapter, u32 addr, __le32 data); +int t3_seeprom_wp(struct adapter *adapter, int enable); +int t3_get_tp_version(struct adapter *adapter, u32 *vers); +int t3_check_tpsram_version(struct adapter *adapter); +int t3_check_tpsram(struct adapter *adapter, const u8 *tp_ram, + unsigned int size); +int t3_set_proto_sram(struct adapter *adap, const u8 *data); +int t3_load_fw(struct adapter *adapter, const u8 * fw_data, unsigned int size); +int t3_get_fw_version(struct adapter *adapter, u32 *vers); +int t3_check_fw_version(struct adapter *adapter); +int t3_init_hw(struct adapter *adapter, u32 fw_params); +int t3_reset_adapter(struct adapter *adapter); +int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai, + int reset); +int t3_replay_prep_adapter(struct adapter *adapter); +void t3_led_ready(struct adapter *adapter); +void t3_fatal_err(struct adapter *adapter); +void t3_set_vlan_accel(struct adapter *adapter, unsigned int ports, int on); +void t3_config_rss(struct adapter *adapter, unsigned int rss_config, + const u8 * cpus, const u16 *rspq); +int t3_cim_ctl_blk_read(struct adapter *adap, unsigned int addr, + unsigned int n, unsigned int *valp); +int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n, + u64 *buf); + +int t3_mac_reset(struct cmac *mac); +void t3b_pcs_reset(struct cmac *mac); +void t3_mac_disable_exact_filters(struct cmac *mac); +void t3_mac_enable_exact_filters(struct cmac *mac); +int t3_mac_enable(struct cmac *mac, int which); +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 net_device *dev); +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); +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); +int t3b2_mac_watchdog_task(struct cmac *mac); + +void t3_mc5_prep(struct adapter *adapter, struct mc5 *mc5, int mode); +int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters, + unsigned int nroutes); +void t3_mc5_intr_handler(struct mc5 *mc5); + +void t3_tp_set_offload_mode(struct adapter *adap, int enable); +void t3_tp_get_mib_stats(struct adapter *adap, struct tp_mib_stats *tps); +void t3_load_mtus(struct adapter *adap, unsigned short mtus[NMTUS], + unsigned short alpha[NCCTRL_WIN], + unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap); +void t3_config_trace_filter(struct adapter *adapter, + const struct trace_params *tp, int filter_index, + int invert, int enable); +int t3_config_sched(struct adapter *adap, unsigned int kbps, int sched); + +void t3_sge_prep(struct adapter *adap, struct sge_params *p); +void t3_sge_init(struct adapter *adap, struct sge_params *p); +int t3_sge_init_ecntxt(struct adapter *adapter, unsigned int id, int gts_enable, + enum sge_context_type type, int respq, u64 base_addr, + unsigned int size, unsigned int token, int gen, + unsigned int cidx); +int t3_sge_init_flcntxt(struct adapter *adapter, unsigned int id, + int gts_enable, u64 base_addr, unsigned int size, + unsigned int esize, unsigned int cong_thres, int gen, + unsigned int cidx); +int t3_sge_init_rspcntxt(struct adapter *adapter, unsigned int id, + int irq_vec_idx, u64 base_addr, unsigned int size, + unsigned int fl_thres, int gen, unsigned int cidx); +int t3_sge_init_cqcntxt(struct adapter *adapter, unsigned int id, u64 base_addr, + unsigned int size, int rspq, int ovfl_mode, + unsigned int credits, unsigned int credit_thres); +int t3_sge_enable_ecntxt(struct adapter *adapter, unsigned int id, int enable); +int t3_sge_disable_fl(struct adapter *adapter, unsigned int id); +int t3_sge_disable_rspcntxt(struct adapter *adapter, unsigned int id); +int t3_sge_disable_cqcntxt(struct adapter *adapter, unsigned int id); +int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op, + unsigned int credits); + +int t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops); +int t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops); +int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops); +int t3_ael2005_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops); +int t3_ael2020_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops); +int t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, + const struct mdio_ops *mdio_ops); +int t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops); +int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops); +#endif /* __CHELSIO_COMMON_H */ diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_ctl_defs.h b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_ctl_defs.h new file mode 100644 index 000000000000..369fe711fd7f --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_ctl_defs.h @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _CXGB3_OFFLOAD_CTL_DEFS_H +#define _CXGB3_OFFLOAD_CTL_DEFS_H + +enum { + GET_MAX_OUTSTANDING_WR = 0, + GET_TX_MAX_CHUNK = 1, + GET_TID_RANGE = 2, + GET_STID_RANGE = 3, + GET_RTBL_RANGE = 4, + GET_L2T_CAPACITY = 5, + GET_MTUS = 6, + GET_WR_LEN = 7, + GET_IFF_FROM_MAC = 8, + GET_DDP_PARAMS = 9, + GET_PORTS = 10, + + ULP_ISCSI_GET_PARAMS = 11, + ULP_ISCSI_SET_PARAMS = 12, + + RDMA_GET_PARAMS = 13, + RDMA_CQ_OP = 14, + RDMA_CQ_SETUP = 15, + RDMA_CQ_DISABLE = 16, + RDMA_CTRL_QP_SETUP = 17, + RDMA_GET_MEM = 18, + RDMA_GET_MIB = 19, + + GET_RX_PAGE_INFO = 50, + GET_ISCSI_IPV4ADDR = 51, + + GET_EMBEDDED_INFO = 70, +}; + +/* + * Structure used to describe a TID range. Valid TIDs are [base, base+num). + */ +struct tid_range { + unsigned int base; /* first TID */ + unsigned int num; /* number of TIDs in range */ +}; + +/* + * Structure used to request the size and contents of the MTU table. + */ +struct mtutab { + unsigned int size; /* # of entries in the MTU table */ + const unsigned short *mtus; /* the MTU table values */ +}; + +struct net_device; + +/* + * Structure used to request the adapter net_device owning a given MAC address. + */ +struct iff_mac { + struct net_device *dev; /* the net_device */ + const unsigned char *mac_addr; /* MAC address to lookup */ + u16 vlan_tag; +}; + +/* Structure used to request a port's iSCSI IPv4 address */ +struct iscsi_ipv4addr { + struct net_device *dev; /* the net_device */ + __be32 ipv4addr; /* the return iSCSI IPv4 address */ +}; + +struct pci_dev; + +/* + * Structure used to request the TCP DDP parameters. + */ +struct ddp_params { + unsigned int llimit; /* TDDP region start address */ + unsigned int ulimit; /* TDDP region end address */ + unsigned int tag_mask; /* TDDP tag mask */ + struct pci_dev *pdev; +}; + +struct adap_ports { + unsigned int nports; /* number of ports on this adapter */ + struct net_device *lldevs[2]; +}; + +/* + * Structure used to return information to the iscsi layer. + */ +struct ulp_iscsi_info { + unsigned int offset; + unsigned int llimit; + unsigned int ulimit; + unsigned int tagmask; + u8 pgsz_factor[4]; + unsigned int max_rxsz; + unsigned int max_txsz; + struct pci_dev *pdev; +}; + +/* + * Structure used to return information to the RDMA layer. + */ +struct rdma_info { + unsigned int tpt_base; /* TPT base address */ + unsigned int tpt_top; /* TPT last entry address */ + unsigned int pbl_base; /* PBL base address */ + unsigned int pbl_top; /* PBL last entry address */ + unsigned int rqt_base; /* RQT base address */ + unsigned int rqt_top; /* RQT last entry address */ + unsigned int udbell_len; /* user doorbell region length */ + unsigned long udbell_physbase; /* user doorbell physical start addr */ + void __iomem *kdb_addr; /* kernel doorbell register address */ + struct pci_dev *pdev; /* associated PCI device */ +}; + +/* + * Structure used to request an operation on an RDMA completion queue. + */ +struct rdma_cq_op { + unsigned int id; + unsigned int op; + unsigned int credits; +}; + +/* + * Structure used to setup RDMA completion queues. + */ +struct rdma_cq_setup { + unsigned int id; + unsigned long long base_addr; + unsigned int size; + unsigned int credits; + unsigned int credit_thres; + unsigned int ovfl_mode; +}; + +/* + * Structure used to setup the RDMA control egress context. + */ +struct rdma_ctrlqp_setup { + unsigned long long base_addr; + unsigned int size; +}; + +/* + * 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 get firmware and protocol engine versions. + */ +struct ch_embedded_info { + u32 fw_vers; + u32 tp_vers; +}; +#endif /* _CXGB3_OFFLOAD_CTL_DEFS_H */ diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_defs.h b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_defs.h new file mode 100644 index 000000000000..920d918ed193 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_defs.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2006-2008 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _CHELSIO_DEFS_H +#define _CHELSIO_DEFS_H + +#include +#include + +#include "t3cdev.h" + +#include "cxgb3_offload.h" + +#define VALIDATE_TID 1 + +void *cxgb_alloc_mem(unsigned long size); +void cxgb_free_mem(void *addr); + +/* + * Map an ATID or STID to their entries in the corresponding TID tables. + */ +static inline union active_open_entry *atid2entry(const struct tid_info *t, + unsigned int atid) +{ + return &t->atid_tab[atid - t->atid_base]; +} + +static inline union listen_entry *stid2entry(const struct tid_info *t, + unsigned int stid) +{ + return &t->stid_tab[stid - t->stid_base]; +} + +/* + * Find the connection corresponding to a TID. + */ +static inline struct t3c_tid_entry *lookup_tid(const struct tid_info *t, + unsigned int tid) +{ + struct t3c_tid_entry *t3c_tid = tid < t->ntids ? + &(t->tid_tab[tid]) : NULL; + + return (t3c_tid && t3c_tid->client) ? t3c_tid : NULL; +} + +/* + * Find the connection corresponding to a server TID. + */ +static inline struct t3c_tid_entry *lookup_stid(const struct tid_info *t, + unsigned int tid) +{ + union listen_entry *e; + + if (tid < t->stid_base || tid >= t->stid_base + t->nstids) + return NULL; + + e = stid2entry(t, tid); + if ((void *)e->next >= (void *)t->tid_tab && + (void *)e->next < (void *)&t->atid_tab[t->natids]) + return NULL; + + return &e->t3c_tid; +} + +/* + * Find the connection corresponding to an active-open TID. + */ +static inline struct t3c_tid_entry *lookup_atid(const struct tid_info *t, + unsigned int tid) +{ + union active_open_entry *e; + + if (tid < t->atid_base || tid >= t->atid_base + t->natids) + return NULL; + + e = atid2entry(t, tid); + if ((void *)e->next >= (void *)t->tid_tab && + (void *)e->next < (void *)&t->atid_tab[t->natids]) + return NULL; + + return &e->t3c_tid; +} + +int attach_t3cdev(struct t3cdev *dev); +void detach_t3cdev(struct t3cdev *dev); +#endif diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_ioctl.h b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_ioctl.h new file mode 100644 index 000000000000..b19e4376ba76 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_ioctl.h @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __CHIOCTL_H__ +#define __CHIOCTL_H__ + +/* + * Ioctl commands specific to this driver. + */ +enum { + CHELSIO_GETMTUTAB = 1029, + CHELSIO_SETMTUTAB = 1030, + CHELSIO_SET_PM = 1032, + CHELSIO_GET_PM = 1033, + CHELSIO_GET_MEM = 1038, + CHELSIO_LOAD_FW = 1041, + CHELSIO_SET_TRACE_FILTER = 1044, + CHELSIO_SET_QSET_PARAMS = 1045, + CHELSIO_GET_QSET_PARAMS = 1046, + CHELSIO_SET_QSET_NUM = 1047, + CHELSIO_GET_QSET_NUM = 1048, +}; + +struct ch_reg { + uint32_t cmd; + uint32_t addr; + uint32_t val; +}; + +struct ch_cntxt { + uint32_t cmd; + uint32_t cntxt_type; + uint32_t cntxt_id; + uint32_t data[4]; +}; + +/* context types */ +enum { CNTXT_TYPE_EGRESS, CNTXT_TYPE_FL, CNTXT_TYPE_RSP, CNTXT_TYPE_CQ }; + +struct ch_desc { + uint32_t cmd; + uint32_t queue_num; + uint32_t idx; + uint32_t size; + uint8_t data[128]; +}; + +struct ch_mem_range { + uint32_t cmd; + uint32_t mem_id; + uint32_t addr; + uint32_t len; + uint32_t version; + uint8_t buf[0]; +}; + +struct ch_qset_params { + uint32_t cmd; + uint32_t qset_idx; + int32_t txq_size[3]; + int32_t rspq_size; + int32_t fl_size[2]; + int32_t intr_lat; + int32_t polling; + int32_t lro; + int32_t cong_thres; + int32_t vector; + int32_t qnum; +}; + +struct ch_pktsched_params { + uint32_t cmd; + uint8_t sched; + uint8_t idx; + uint8_t min; + uint8_t max; + uint8_t binding; +}; + +#ifndef TCB_SIZE +# define TCB_SIZE 128 +#endif + +/* TCB size in 32-bit words */ +#define TCB_WORDS (TCB_SIZE / 4) + +enum { MEM_CM, MEM_PMRX, MEM_PMTX }; /* ch_mem_range.mem_id values */ + +struct ch_mtus { + uint32_t cmd; + uint32_t nmtus; + uint16_t mtus[NMTUS]; +}; + +struct ch_pm { + uint32_t cmd; + uint32_t tx_pg_sz; + uint32_t tx_num_pg; + uint32_t rx_pg_sz; + uint32_t rx_num_pg; + uint32_t pm_total; +}; + +struct ch_tcam { + uint32_t cmd; + uint32_t tcam_size; + uint32_t nservers; + uint32_t nroutes; + uint32_t nfilters; +}; + +struct ch_tcb { + uint32_t cmd; + uint32_t tcb_index; + uint32_t tcb_data[TCB_WORDS]; +}; + +struct ch_tcam_word { + uint32_t cmd; + uint32_t addr; + uint32_t buf[3]; +}; + +struct ch_trace { + uint32_t cmd; + uint32_t sip; + uint32_t sip_mask; + uint32_t dip; + uint32_t dip_mask; + uint16_t sport; + uint16_t sport_mask; + uint16_t dport; + uint16_t dport_mask; + uint32_t vlan:12; + uint32_t vlan_mask:12; + uint32_t intf:4; + uint32_t intf_mask:4; + uint8_t proto; + uint8_t proto_mask; + uint8_t invert_match:1; + uint8_t config_tx:1; + uint8_t config_rx:1; + uint8_t trace_tx:1; + uint8_t trace_rx:1; +}; + +#define SIOCCHIOCTL SIOCDEVPRIVATE + +#endif diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c new file mode 100644 index 000000000000..93b41a7ac175 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c @@ -0,0 +1,3448 @@ +/* + * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "cxgb3_ioctl.h" +#include "regs.h" +#include "cxgb3_offload.h" +#include "version.h" + +#include "cxgb3_ctl_defs.h" +#include "t3_cpl.h" +#include "firmware_exports.h" + +enum { + MAX_TXQ_ENTRIES = 16384, + MAX_CTRL_TXQ_ENTRIES = 1024, + MAX_RSPQ_ENTRIES = 16384, + MAX_RX_BUFFERS = 16384, + MAX_RX_JUMBO_BUFFERS = 16384, + MIN_TXQ_ENTRIES = 4, + MIN_CTRL_TXQ_ENTRIES = 4, + MIN_RSPQ_ENTRIES = 32, + MIN_FL_ENTRIES = 32 +}; + +#define PORT_MASK ((1 << MAX_NPORTS) - 1) + +#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \ + NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\ + NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) + +#define EEPROM_MAGIC 0x38E2F10C + +#define CH_DEVICE(devid, idx) \ + { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, PCI_ANY_ID, 0, 0, idx } + +static DEFINE_PCI_DEVICE_TABLE(cxgb3_pci_tbl) = { + CH_DEVICE(0x20, 0), /* PE9000 */ + CH_DEVICE(0x21, 1), /* T302E */ + CH_DEVICE(0x22, 2), /* T310E */ + CH_DEVICE(0x23, 3), /* T320X */ + CH_DEVICE(0x24, 1), /* T302X */ + CH_DEVICE(0x25, 3), /* T320E */ + CH_DEVICE(0x26, 2), /* T310X */ + CH_DEVICE(0x30, 2), /* T3B10 */ + CH_DEVICE(0x31, 3), /* T3B20 */ + CH_DEVICE(0x32, 1), /* T3B02 */ + CH_DEVICE(0x35, 6), /* T3C20-derived T3C10 */ + CH_DEVICE(0x36, 3), /* S320E-CR */ + CH_DEVICE(0x37, 7), /* N320E-G2 */ + {0,} +}; + +MODULE_DESCRIPTION(DRV_DESC); +MODULE_AUTHOR("Chelsio Communications"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_VERSION(DRV_VERSION); +MODULE_DEVICE_TABLE(pci, cxgb3_pci_tbl); + +static int dflt_msg_enable = DFLT_MSG_ENABLE; + +module_param(dflt_msg_enable, int, 0644); +MODULE_PARM_DESC(dflt_msg_enable, "Chelsio T3 default message enable bitmap"); + +/* + * The driver uses the best interrupt scheme available on a platform in the + * order MSI-X, MSI, legacy pin interrupts. This parameter determines which + * of these schemes the driver may consider as follows: + * + * msi = 2: choose from among all three options + * msi = 1: only consider MSI and pin interrupts + * msi = 0: force pin interrupts + */ +static int msi = 2; + +module_param(msi, int, 0644); +MODULE_PARM_DESC(msi, "whether to use MSI or MSI-X"); + +/* + * The driver enables offload as a default. + * To disable it, use ofld_disable = 1. + */ + +static int ofld_disable = 0; + +module_param(ofld_disable, int, 0644); +MODULE_PARM_DESC(ofld_disable, "whether to enable offload at init time or not"); + +/* + * We have work elements that we need to cancel when an interface is taken + * down. Normally the work elements would be executed by keventd but that + * can deadlock because of linkwatch. If our close method takes the rtnl + * lock and linkwatch is ahead of our work elements in keventd, linkwatch + * will block keventd as it needs the rtnl lock, and we'll deadlock waiting + * for our work to complete. Get our own work queue to solve this. + */ +struct workqueue_struct *cxgb3_wq; + +/** + * link_report - show link status and link speed/duplex + * @p: the port whose settings are to be reported + * + * Shows the link status, speed, and duplex of a port. + */ +static void link_report(struct net_device *dev) +{ + if (!netif_carrier_ok(dev)) + printk(KERN_INFO "%s: link down\n", dev->name); + else { + const char *s = "10Mbps"; + const struct port_info *p = netdev_priv(dev); + + switch (p->link_config.speed) { + case SPEED_10000: + s = "10Gbps"; + break; + case SPEED_1000: + s = "1000Mbps"; + break; + case SPEED_100: + s = "100Mbps"; + break; + } + + printk(KERN_INFO "%s: link up, %s, %s-duplex\n", dev->name, s, + p->link_config.duplex == DUPLEX_FULL ? "full" : "half"); + } +} + +static void enable_tx_fifo_drain(struct adapter *adapter, + struct port_info *pi) +{ + t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset, 0, + F_ENDROPPKT); + t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, 0); + t3_write_reg(adapter, A_XGM_TX_CTRL + pi->mac.offset, F_TXEN); + t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, F_RXEN); +} + +static void disable_tx_fifo_drain(struct adapter *adapter, + struct port_info *pi) +{ + t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset, + F_ENDROPPKT, 0); +} + +void t3_os_link_fault(struct adapter *adap, int port_id, int state) +{ + struct net_device *dev = adap->port[port_id]; + struct port_info *pi = netdev_priv(dev); + + if (state == netif_carrier_ok(dev)) + return; + + if (state) { + struct cmac *mac = &pi->mac; + + netif_carrier_on(dev); + + disable_tx_fifo_drain(adap, pi); + + /* Clear local faults */ + t3_xgm_intr_disable(adap, pi->port_id); + t3_read_reg(adap, A_XGM_INT_STATUS + + pi->mac.offset); + t3_write_reg(adap, + A_XGM_INT_CAUSE + pi->mac.offset, + F_XGM_INT); + + t3_set_reg_field(adap, + A_XGM_INT_ENABLE + + pi->mac.offset, + F_XGM_INT, F_XGM_INT); + t3_xgm_intr_enable(adap, pi->port_id); + + t3_mac_enable(mac, MAC_DIRECTION_TX); + } else { + netif_carrier_off(dev); + + /* Flush TX FIFO */ + enable_tx_fifo_drain(adap, pi); + } + link_report(dev); +} + +/** + * t3_os_link_changed - handle link status changes + * @adapter: the adapter associated with the link change + * @port_id: the port index whose limk status has changed + * @link_stat: the new status of the link + * @speed: the new speed setting + * @duplex: the new duplex setting + * @pause: the new flow-control setting + * + * This is the OS-dependent handler for link status changes. The OS + * neutral handler takes care of most of the processing for these events, + * then calls this handler for any OS-specific processing. + */ +void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat, + int speed, int duplex, int pause) +{ + struct net_device *dev = adapter->port[port_id]; + struct port_info *pi = netdev_priv(dev); + struct cmac *mac = &pi->mac; + + /* Skip changes from disabled ports. */ + if (!netif_running(dev)) + return; + + if (link_stat != netif_carrier_ok(dev)) { + if (link_stat) { + disable_tx_fifo_drain(adapter, pi); + + t3_mac_enable(mac, MAC_DIRECTION_RX); + + /* Clear local faults */ + t3_xgm_intr_disable(adapter, pi->port_id); + t3_read_reg(adapter, A_XGM_INT_STATUS + + pi->mac.offset); + t3_write_reg(adapter, + A_XGM_INT_CAUSE + pi->mac.offset, + F_XGM_INT); + + t3_set_reg_field(adapter, + A_XGM_INT_ENABLE + pi->mac.offset, + F_XGM_INT, F_XGM_INT); + t3_xgm_intr_enable(adapter, pi->port_id); + + netif_carrier_on(dev); + } else { + netif_carrier_off(dev); + + t3_xgm_intr_disable(adapter, pi->port_id); + t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset); + t3_set_reg_field(adapter, + A_XGM_INT_ENABLE + pi->mac.offset, + F_XGM_INT, 0); + + if (is_10G(adapter)) + pi->phy.ops->power_down(&pi->phy, 1); + + t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset); + t3_mac_disable(mac, MAC_DIRECTION_RX); + t3_link_start(&pi->phy, mac, &pi->link_config); + + /* Flush TX FIFO */ + enable_tx_fifo_drain(adapter, pi); + } + + link_report(dev); + } +} + +/** + * t3_os_phymod_changed - handle PHY module changes + * @phy: the PHY reporting the module change + * @mod_type: new module type + * + * This is the OS-dependent handler for PHY module changes. It is + * invoked when a PHY module is removed or inserted for any OS-specific + * processing. + */ +void t3_os_phymod_changed(struct adapter *adap, int port_id) +{ + static const char *mod_str[] = { + NULL, "SR", "LR", "LRM", "TWINAX", "TWINAX", "unknown" + }; + + const struct net_device *dev = adap->port[port_id]; + const struct port_info *pi = netdev_priv(dev); + + if (pi->phy.modtype == phy_modtype_none) + printk(KERN_INFO "%s: PHY module unplugged\n", dev->name); + else + printk(KERN_INFO "%s: %s PHY module inserted\n", dev->name, + mod_str[pi->phy.modtype]); +} + +static void cxgb_set_rxmode(struct net_device *dev) +{ + struct port_info *pi = netdev_priv(dev); + + t3_mac_set_rx_mode(&pi->mac, dev); +} + +/** + * link_start - enable a port + * @dev: the device to enable + * + * Performs the MAC and PHY actions needed to enable a port. + */ +static void link_start(struct net_device *dev) +{ + struct port_info *pi = netdev_priv(dev); + struct cmac *mac = &pi->mac; + + t3_mac_reset(mac); + t3_mac_set_num_ucast(mac, MAX_MAC_IDX); + t3_mac_set_mtu(mac, dev->mtu); + t3_mac_set_address(mac, LAN_MAC_IDX, dev->dev_addr); + t3_mac_set_address(mac, SAN_MAC_IDX, pi->iscsic.mac_addr); + t3_mac_set_rx_mode(mac, dev); + t3_link_start(&pi->phy, mac, &pi->link_config); + t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); +} + +static inline void cxgb_disable_msi(struct adapter *adapter) +{ + if (adapter->flags & USING_MSIX) { + pci_disable_msix(adapter->pdev); + adapter->flags &= ~USING_MSIX; + } else if (adapter->flags & USING_MSI) { + pci_disable_msi(adapter->pdev); + adapter->flags &= ~USING_MSI; + } +} + +/* + * Interrupt handler for asynchronous events used with MSI-X. + */ +static irqreturn_t t3_async_intr_handler(int irq, void *cookie) +{ + t3_slow_intr_handler(cookie); + return IRQ_HANDLED; +} + +/* + * Name the MSI-X interrupts. + */ +static void name_msix_vecs(struct adapter *adap) +{ + int i, j, msi_idx = 1, n = sizeof(adap->msix_info[0].desc) - 1; + + snprintf(adap->msix_info[0].desc, n, "%s", adap->name); + adap->msix_info[0].desc[n] = 0; + + for_each_port(adap, j) { + struct net_device *d = adap->port[j]; + const struct port_info *pi = netdev_priv(d); + + for (i = 0; i < pi->nqsets; i++, msi_idx++) { + snprintf(adap->msix_info[msi_idx].desc, n, + "%s-%d", d->name, pi->first_qset + i); + adap->msix_info[msi_idx].desc[n] = 0; + } + } +} + +static int request_msix_data_irqs(struct adapter *adap) +{ + int i, j, err, qidx = 0; + + for_each_port(adap, i) { + int nqsets = adap2pinfo(adap, i)->nqsets; + + for (j = 0; j < nqsets; ++j) { + err = request_irq(adap->msix_info[qidx + 1].vec, + t3_intr_handler(adap, + adap->sge.qs[qidx]. + rspq.polling), 0, + adap->msix_info[qidx + 1].desc, + &adap->sge.qs[qidx]); + if (err) { + while (--qidx >= 0) + free_irq(adap->msix_info[qidx + 1].vec, + &adap->sge.qs[qidx]); + return err; + } + qidx++; + } + } + return 0; +} + +static void free_irq_resources(struct adapter *adapter) +{ + if (adapter->flags & USING_MSIX) { + int i, n = 0; + + free_irq(adapter->msix_info[0].vec, adapter); + for_each_port(adapter, i) + n += adap2pinfo(adapter, i)->nqsets; + + for (i = 0; i < n; ++i) + free_irq(adapter->msix_info[i + 1].vec, + &adapter->sge.qs[i]); + } else + free_irq(adapter->pdev->irq, adapter); +} + +static int await_mgmt_replies(struct adapter *adap, unsigned long init_cnt, + unsigned long n) +{ + int attempts = 10; + + while (adap->sge.qs[0].rspq.offload_pkts < init_cnt + n) { + if (!--attempts) + return -ETIMEDOUT; + msleep(10); + } + return 0; +} + +static int init_tp_parity(struct adapter *adap) +{ + int i; + struct sk_buff *skb; + struct cpl_set_tcb_field *greq; + unsigned long cnt = adap->sge.qs[0].rspq.offload_pkts; + + t3_tp_set_offload_mode(adap, 1); + + for (i = 0; i < 16; i++) { + struct cpl_smt_write_req *req; + + skb = alloc_skb(sizeof(*req), GFP_KERNEL); + if (!skb) + skb = adap->nofail_skb; + if (!skb) + goto alloc_skb_fail; + + req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req)); + memset(req, 0, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i)); + req->mtu_idx = NMTUS - 1; + req->iff = i; + t3_mgmt_tx(adap, skb); + if (skb == adap->nofail_skb) { + await_mgmt_replies(adap, cnt, i + 1); + adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL); + if (!adap->nofail_skb) + goto alloc_skb_fail; + } + } + + for (i = 0; i < 2048; i++) { + struct cpl_l2t_write_req *req; + + skb = alloc_skb(sizeof(*req), GFP_KERNEL); + if (!skb) + skb = adap->nofail_skb; + if (!skb) + goto alloc_skb_fail; + + req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req)); + memset(req, 0, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i)); + req->params = htonl(V_L2T_W_IDX(i)); + t3_mgmt_tx(adap, skb); + if (skb == adap->nofail_skb) { + await_mgmt_replies(adap, cnt, 16 + i + 1); + adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL); + if (!adap->nofail_skb) + goto alloc_skb_fail; + } + } + + for (i = 0; i < 2048; i++) { + struct cpl_rte_write_req *req; + + skb = alloc_skb(sizeof(*req), GFP_KERNEL); + if (!skb) + skb = adap->nofail_skb; + if (!skb) + goto alloc_skb_fail; + + req = (struct cpl_rte_write_req *)__skb_put(skb, sizeof(*req)); + memset(req, 0, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i)); + req->l2t_idx = htonl(V_L2T_W_IDX(i)); + t3_mgmt_tx(adap, skb); + if (skb == adap->nofail_skb) { + await_mgmt_replies(adap, cnt, 16 + 2048 + i + 1); + adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL); + if (!adap->nofail_skb) + goto alloc_skb_fail; + } + } + + skb = alloc_skb(sizeof(*greq), GFP_KERNEL); + if (!skb) + skb = adap->nofail_skb; + if (!skb) + goto alloc_skb_fail; + + greq = (struct cpl_set_tcb_field *)__skb_put(skb, sizeof(*greq)); + memset(greq, 0, sizeof(*greq)); + greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(greq) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, 0)); + greq->mask = cpu_to_be64(1); + t3_mgmt_tx(adap, skb); + + i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1); + if (skb == adap->nofail_skb) { + i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1); + adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL); + } + + t3_tp_set_offload_mode(adap, 0); + return i; + +alloc_skb_fail: + t3_tp_set_offload_mode(adap, 0); + return -ENOMEM; +} + +/** + * setup_rss - configure RSS + * @adap: the adapter + * + * Sets up RSS to distribute packets to multiple receive queues. We + * configure the RSS CPU lookup table to distribute to the number of HW + * receive queues, and the response queue lookup table to narrow that + * down to the response queues actually configured for each port. + * We always configure the RSS mapping for two ports since the mapping + * table has plenty of entries. + */ +static void setup_rss(struct adapter *adap) +{ + int i; + unsigned int nq0 = adap2pinfo(adap, 0)->nqsets; + unsigned int nq1 = adap->port[1] ? adap2pinfo(adap, 1)->nqsets : 1; + u8 cpus[SGE_QSETS + 1]; + u16 rspq_map[RSS_TABLE_SIZE]; + + for (i = 0; i < SGE_QSETS; ++i) + cpus[i] = i; + cpus[SGE_QSETS] = 0xff; /* terminator */ + + for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) { + rspq_map[i] = i % nq0; + rspq_map[i + RSS_TABLE_SIZE / 2] = (i % nq1) + nq0; + } + + t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN | + F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN | + V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ, cpus, rspq_map); +} + +static void ring_dbs(struct adapter *adap) +{ + int i, j; + + for (i = 0; i < SGE_QSETS; i++) { + struct sge_qset *qs = &adap->sge.qs[i]; + + if (qs->adap) + for (j = 0; j < SGE_TXQ_PER_SET; j++) + t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX | V_EGRCNTX(qs->txq[j].cntxt_id)); + } +} + +static void init_napi(struct adapter *adap) +{ + int i; + + for (i = 0; i < SGE_QSETS; i++) { + struct sge_qset *qs = &adap->sge.qs[i]; + + if (qs->adap) + netif_napi_add(qs->netdev, &qs->napi, qs->napi.poll, + 64); + } + + /* + * netif_napi_add() can be called only once per napi_struct because it + * adds each new napi_struct to a list. Be careful not to call it a + * second time, e.g., during EEH recovery, by making a note of it. + */ + adap->flags |= NAPI_INIT; +} + +/* + * Wait until all NAPI handlers are descheduled. This includes the handlers of + * both netdevices representing interfaces and the dummy ones for the extra + * queues. + */ +static void quiesce_rx(struct adapter *adap) +{ + int i; + + for (i = 0; i < SGE_QSETS; i++) + if (adap->sge.qs[i].adap) + napi_disable(&adap->sge.qs[i].napi); +} + +static void enable_all_napi(struct adapter *adap) +{ + int i; + for (i = 0; i < SGE_QSETS; i++) + if (adap->sge.qs[i].adap) + napi_enable(&adap->sge.qs[i].napi); +} + +/** + * setup_sge_qsets - configure SGE Tx/Rx/response queues + * @adap: the adapter + * + * Determines how many sets of SGE queues to use and initializes them. + * We support multiple queue sets per port if we have MSI-X, otherwise + * just one queue set per port. + */ +static int setup_sge_qsets(struct adapter *adap) +{ + int i, j, err, irq_idx = 0, qset_idx = 0; + unsigned int ntxq = SGE_TXQ_PER_SET; + + if (adap->params.rev > 0 && !(adap->flags & USING_MSI)) + irq_idx = -1; + + for_each_port(adap, i) { + struct net_device *dev = adap->port[i]; + struct port_info *pi = netdev_priv(dev); + + pi->qs = &adap->sge.qs[pi->first_qset]; + for (j = 0; j < pi->nqsets; ++j, ++qset_idx) { + err = t3_sge_alloc_qset(adap, qset_idx, 1, + (adap->flags & USING_MSIX) ? qset_idx + 1 : + irq_idx, + &adap->params.sge.qset[qset_idx], ntxq, dev, + netdev_get_tx_queue(dev, j)); + if (err) { + t3_free_sge_resources(adap); + return err; + } + } + } + + return 0; +} + +static ssize_t attr_show(struct device *d, char *buf, + ssize_t(*format) (struct net_device *, char *)) +{ + ssize_t len; + + /* Synchronize with ioctls that may shut down the device */ + rtnl_lock(); + len = (*format) (to_net_dev(d), buf); + rtnl_unlock(); + return len; +} + +static ssize_t attr_store(struct device *d, + const char *buf, size_t len, + ssize_t(*set) (struct net_device *, unsigned int), + unsigned int min_val, unsigned int max_val) +{ + char *endp; + ssize_t ret; + unsigned int val; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + val = simple_strtoul(buf, &endp, 0); + if (endp == buf || val < min_val || val > max_val) + return -EINVAL; + + rtnl_lock(); + ret = (*set) (to_net_dev(d), val); + if (!ret) + ret = len; + rtnl_unlock(); + return ret; +} + +#define CXGB3_SHOW(name, val_expr) \ +static ssize_t format_##name(struct net_device *dev, char *buf) \ +{ \ + struct port_info *pi = netdev_priv(dev); \ + struct adapter *adap = pi->adapter; \ + return sprintf(buf, "%u\n", val_expr); \ +} \ +static ssize_t show_##name(struct device *d, struct device_attribute *attr, \ + char *buf) \ +{ \ + return attr_show(d, buf, format_##name); \ +} + +static ssize_t set_nfilters(struct net_device *dev, unsigned int val) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adap = pi->adapter; + int min_tids = is_offload(adap) ? MC5_MIN_TIDS : 0; + + if (adap->flags & FULL_INIT_DONE) + return -EBUSY; + if (val && adap->params.rev == 0) + return -EINVAL; + if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers - + min_tids) + return -EINVAL; + adap->params.mc5.nfilters = val; + return 0; +} + +static ssize_t store_nfilters(struct device *d, struct device_attribute *attr, + const char *buf, size_t len) +{ + return attr_store(d, buf, len, set_nfilters, 0, ~0); +} + +static ssize_t set_nservers(struct net_device *dev, unsigned int val) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adap = pi->adapter; + + if (adap->flags & FULL_INIT_DONE) + return -EBUSY; + if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nfilters - + MC5_MIN_TIDS) + return -EINVAL; + adap->params.mc5.nservers = val; + return 0; +} + +static ssize_t store_nservers(struct device *d, struct device_attribute *attr, + const char *buf, size_t len) +{ + return attr_store(d, buf, len, set_nservers, 0, ~0); +} + +#define CXGB3_ATTR_R(name, val_expr) \ +CXGB3_SHOW(name, val_expr) \ +static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) + +#define CXGB3_ATTR_RW(name, val_expr, store_method) \ +CXGB3_SHOW(name, val_expr) \ +static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_method) + +CXGB3_ATTR_R(cam_size, t3_mc5_size(&adap->mc5)); +CXGB3_ATTR_RW(nfilters, adap->params.mc5.nfilters, store_nfilters); +CXGB3_ATTR_RW(nservers, adap->params.mc5.nservers, store_nservers); + +static struct attribute *cxgb3_attrs[] = { + &dev_attr_cam_size.attr, + &dev_attr_nfilters.attr, + &dev_attr_nservers.attr, + NULL +}; + +static struct attribute_group cxgb3_attr_group = {.attrs = cxgb3_attrs }; + +static ssize_t tm_attr_show(struct device *d, + char *buf, int sched) +{ + struct port_info *pi = netdev_priv(to_net_dev(d)); + struct adapter *adap = pi->adapter; + unsigned int v, addr, bpt, cpt; + ssize_t len; + + addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2; + rtnl_lock(); + t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr); + v = t3_read_reg(adap, A_TP_TM_PIO_DATA); + if (sched & 1) + v >>= 16; + bpt = (v >> 8) & 0xff; + cpt = v & 0xff; + if (!cpt) + len = sprintf(buf, "disabled\n"); + else { + v = (adap->params.vpd.cclk * 1000) / cpt; + len = sprintf(buf, "%u Kbps\n", (v * bpt) / 125); + } + rtnl_unlock(); + return len; +} + +static ssize_t tm_attr_store(struct device *d, + const char *buf, size_t len, int sched) +{ + struct port_info *pi = netdev_priv(to_net_dev(d)); + struct adapter *adap = pi->adapter; + unsigned int val; + char *endp; + ssize_t ret; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + val = simple_strtoul(buf, &endp, 0); + if (endp == buf || val > 10000000) + return -EINVAL; + + rtnl_lock(); + ret = t3_config_sched(adap, val, sched); + if (!ret) + ret = len; + rtnl_unlock(); + return ret; +} + +#define TM_ATTR(name, sched) \ +static ssize_t show_##name(struct device *d, struct device_attribute *attr, \ + char *buf) \ +{ \ + return tm_attr_show(d, buf, sched); \ +} \ +static ssize_t store_##name(struct device *d, struct device_attribute *attr, \ + const char *buf, size_t len) \ +{ \ + return tm_attr_store(d, buf, len, sched); \ +} \ +static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name) + +TM_ATTR(sched0, 0); +TM_ATTR(sched1, 1); +TM_ATTR(sched2, 2); +TM_ATTR(sched3, 3); +TM_ATTR(sched4, 4); +TM_ATTR(sched5, 5); +TM_ATTR(sched6, 6); +TM_ATTR(sched7, 7); + +static struct attribute *offload_attrs[] = { + &dev_attr_sched0.attr, + &dev_attr_sched1.attr, + &dev_attr_sched2.attr, + &dev_attr_sched3.attr, + &dev_attr_sched4.attr, + &dev_attr_sched5.attr, + &dev_attr_sched6.attr, + &dev_attr_sched7.attr, + NULL +}; + +static struct attribute_group offload_attr_group = {.attrs = offload_attrs }; + +/* + * Sends an sk_buff to an offload queue driver + * after dealing with any active network taps. + */ +static inline int offload_tx(struct t3cdev *tdev, struct sk_buff *skb) +{ + int ret; + + local_bh_disable(); + ret = t3_offload_tx(tdev, skb); + local_bh_enable(); + return ret; +} + +static int write_smt_entry(struct adapter *adapter, int idx) +{ + struct cpl_smt_write_req *req; + struct port_info *pi = netdev_priv(adapter->port[idx]); + struct sk_buff *skb = alloc_skb(sizeof(*req), GFP_KERNEL); + + if (!skb) + return -ENOMEM; + + req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx)); + req->mtu_idx = NMTUS - 1; /* should be 0 but there's a T3 bug */ + req->iff = idx; + memcpy(req->src_mac0, adapter->port[idx]->dev_addr, ETH_ALEN); + memcpy(req->src_mac1, pi->iscsic.mac_addr, ETH_ALEN); + skb->priority = 1; + offload_tx(&adapter->tdev, skb); + return 0; +} + +static int init_smt(struct adapter *adapter) +{ + int i; + + for_each_port(adapter, i) + write_smt_entry(adapter, i); + return 0; +} + +static void init_port_mtus(struct adapter *adapter) +{ + unsigned int mtus = adapter->port[0]->mtu; + + if (adapter->port[1]) + mtus |= adapter->port[1]->mtu << 16; + t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus); +} + +static int send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo, + int hi, int port) +{ + struct sk_buff *skb; + struct mngt_pktsched_wr *req; + int ret; + + skb = alloc_skb(sizeof(*req), GFP_KERNEL); + if (!skb) + skb = adap->nofail_skb; + if (!skb) + return -ENOMEM; + + req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req)); + req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT)); + req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET; + req->sched = sched; + req->idx = qidx; + req->min = lo; + req->max = hi; + req->binding = port; + ret = t3_mgmt_tx(adap, skb); + if (skb == adap->nofail_skb) { + adap->nofail_skb = alloc_skb(sizeof(struct cpl_set_tcb_field), + GFP_KERNEL); + if (!adap->nofail_skb) + ret = -ENOMEM; + } + + return ret; +} + +static int bind_qsets(struct adapter *adap) +{ + int i, j, err = 0; + + for_each_port(adap, i) { + const struct port_info *pi = adap2pinfo(adap, i); + + for (j = 0; j < pi->nqsets; ++j) { + int ret = send_pktsched_cmd(adap, 1, + pi->first_qset + j, -1, + -1, i); + if (ret) + err = ret; + } + } + + return err; +} + +#define FW_VERSION __stringify(FW_VERSION_MAJOR) "." \ + __stringify(FW_VERSION_MINOR) "." __stringify(FW_VERSION_MICRO) +#define FW_FNAME "cxgb3/t3fw-" FW_VERSION ".bin" +#define TPSRAM_VERSION __stringify(TP_VERSION_MAJOR) "." \ + __stringify(TP_VERSION_MINOR) "." __stringify(TP_VERSION_MICRO) +#define TPSRAM_NAME "cxgb3/t3%c_psram-" TPSRAM_VERSION ".bin" +#define AEL2005_OPT_EDC_NAME "cxgb3/ael2005_opt_edc.bin" +#define AEL2005_TWX_EDC_NAME "cxgb3/ael2005_twx_edc.bin" +#define AEL2020_TWX_EDC_NAME "cxgb3/ael2020_twx_edc.bin" +MODULE_FIRMWARE(FW_FNAME); +MODULE_FIRMWARE("cxgb3/t3b_psram-" TPSRAM_VERSION ".bin"); +MODULE_FIRMWARE("cxgb3/t3c_psram-" TPSRAM_VERSION ".bin"); +MODULE_FIRMWARE(AEL2005_OPT_EDC_NAME); +MODULE_FIRMWARE(AEL2005_TWX_EDC_NAME); +MODULE_FIRMWARE(AEL2020_TWX_EDC_NAME); + +static inline const char *get_edc_fw_name(int edc_idx) +{ + const char *fw_name = NULL; + + switch (edc_idx) { + case EDC_OPT_AEL2005: + fw_name = AEL2005_OPT_EDC_NAME; + break; + case EDC_TWX_AEL2005: + fw_name = AEL2005_TWX_EDC_NAME; + break; + case EDC_TWX_AEL2020: + fw_name = AEL2020_TWX_EDC_NAME; + break; + } + return fw_name; +} + +int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size) +{ + struct adapter *adapter = phy->adapter; + const struct firmware *fw; + char buf[64]; + u32 csum; + const __be32 *p; + u16 *cache = phy->phy_cache; + int i, ret; + + snprintf(buf, sizeof(buf), get_edc_fw_name(edc_idx)); + + ret = request_firmware(&fw, buf, &adapter->pdev->dev); + if (ret < 0) { + dev_err(&adapter->pdev->dev, + "could not upgrade firmware: unable to load %s\n", + buf); + return ret; + } + + /* check size, take checksum in account */ + if (fw->size > size + 4) { + CH_ERR(adapter, "firmware image too large %u, expected %d\n", + (unsigned int)fw->size, size + 4); + ret = -EINVAL; + } + + /* compute checksum */ + p = (const __be32 *)fw->data; + for (csum = 0, i = 0; i < fw->size / sizeof(csum); i++) + csum += ntohl(p[i]); + + if (csum != 0xffffffff) { + CH_ERR(adapter, "corrupted firmware image, checksum %u\n", + csum); + ret = -EINVAL; + } + + for (i = 0; i < size / 4 ; i++) { + *cache++ = (be32_to_cpu(p[i]) & 0xffff0000) >> 16; + *cache++ = be32_to_cpu(p[i]) & 0xffff; + } + + release_firmware(fw); + + return ret; +} + +static int upgrade_fw(struct adapter *adap) +{ + int ret; + const struct firmware *fw; + struct device *dev = &adap->pdev->dev; + + ret = request_firmware(&fw, FW_FNAME, dev); + if (ret < 0) { + dev_err(dev, "could not upgrade firmware: unable to load %s\n", + FW_FNAME); + return ret; + } + ret = t3_load_fw(adap, fw->data, fw->size); + release_firmware(fw); + + if (ret == 0) + dev_info(dev, "successful upgrade to firmware %d.%d.%d\n", + FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO); + else + dev_err(dev, "failed to upgrade to firmware %d.%d.%d\n", + FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO); + + return ret; +} + +static inline char t3rev2char(struct adapter *adapter) +{ + char rev = 0; + + switch(adapter->params.rev) { + case T3_REV_B: + case T3_REV_B2: + rev = 'b'; + break; + case T3_REV_C: + rev = 'c'; + break; + } + return rev; +} + +static int update_tpsram(struct adapter *adap) +{ + const struct firmware *tpsram; + char buf[64]; + struct device *dev = &adap->pdev->dev; + int ret; + char rev; + + rev = t3rev2char(adap); + if (!rev) + return 0; + + snprintf(buf, sizeof(buf), TPSRAM_NAME, rev); + + ret = request_firmware(&tpsram, buf, dev); + if (ret < 0) { + dev_err(dev, "could not load TP SRAM: unable to load %s\n", + buf); + return ret; + } + + ret = t3_check_tpsram(adap, tpsram->data, tpsram->size); + if (ret) + goto release_tpsram; + + ret = t3_set_proto_sram(adap, tpsram->data); + if (ret == 0) + dev_info(dev, + "successful update of protocol engine " + "to %d.%d.%d\n", + TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO); + else + dev_err(dev, "failed to update of protocol engine %d.%d.%d\n", + TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO); + if (ret) + dev_err(dev, "loading protocol SRAM failed\n"); + +release_tpsram: + release_firmware(tpsram); + + return ret; +} + +/** + * cxgb_up - enable the adapter + * @adapter: adapter being enabled + * + * Called when the first port is enabled, this function performs the + * actions necessary to make an adapter operational, such as completing + * the initialization of HW modules, and enabling interrupts. + * + * Must be called with the rtnl lock held. + */ +static int cxgb_up(struct adapter *adap) +{ + int err; + + if (!(adap->flags & FULL_INIT_DONE)) { + err = t3_check_fw_version(adap); + if (err == -EINVAL) { + err = upgrade_fw(adap); + CH_WARN(adap, "FW upgrade to %d.%d.%d %s\n", + FW_VERSION_MAJOR, FW_VERSION_MINOR, + FW_VERSION_MICRO, err ? "failed" : "succeeded"); + } + + err = t3_check_tpsram_version(adap); + if (err == -EINVAL) { + err = update_tpsram(adap); + CH_WARN(adap, "TP upgrade to %d.%d.%d %s\n", + TP_VERSION_MAJOR, TP_VERSION_MINOR, + TP_VERSION_MICRO, err ? "failed" : "succeeded"); + } + + /* + * Clear interrupts now to catch errors if t3_init_hw fails. + * We clear them again later as initialization may trigger + * conditions that can interrupt. + */ + t3_intr_clear(adap); + + err = t3_init_hw(adap, 0); + if (err) + goto out; + + t3_set_reg_field(adap, A_TP_PARA_REG5, 0, F_RXDDPOFFINIT); + t3_write_reg(adap, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12)); + + err = setup_sge_qsets(adap); + if (err) + goto out; + + setup_rss(adap); + if (!(adap->flags & NAPI_INIT)) + init_napi(adap); + + t3_start_sge_timers(adap); + adap->flags |= FULL_INIT_DONE; + } + + t3_intr_clear(adap); + + if (adap->flags & USING_MSIX) { + name_msix_vecs(adap); + err = request_irq(adap->msix_info[0].vec, + t3_async_intr_handler, 0, + adap->msix_info[0].desc, adap); + if (err) + goto irq_err; + + err = request_msix_data_irqs(adap); + if (err) { + free_irq(adap->msix_info[0].vec, adap); + goto irq_err; + } + } else if ((err = request_irq(adap->pdev->irq, + t3_intr_handler(adap, + adap->sge.qs[0].rspq. + polling), + (adap->flags & USING_MSI) ? + 0 : IRQF_SHARED, + adap->name, adap))) + goto irq_err; + + enable_all_napi(adap); + t3_sge_start(adap); + t3_intr_enable(adap); + + if (adap->params.rev >= T3_REV_C && !(adap->flags & TP_PARITY_INIT) && + is_offload(adap) && init_tp_parity(adap) == 0) + adap->flags |= TP_PARITY_INIT; + + if (adap->flags & TP_PARITY_INIT) { + t3_write_reg(adap, A_TP_INT_CAUSE, + F_CMCACHEPERR | F_ARPLUTPERR); + t3_write_reg(adap, A_TP_INT_ENABLE, 0x7fbfffff); + } + + if (!(adap->flags & QUEUES_BOUND)) { + int ret = bind_qsets(adap); + + if (ret < 0) { + CH_ERR(adap, "failed to bind qsets, err %d\n", ret); + t3_intr_disable(adap); + free_irq_resources(adap); + err = ret; + goto out; + } + adap->flags |= QUEUES_BOUND; + } + +out: + return err; +irq_err: + CH_ERR(adap, "request_irq failed, err %d\n", err); + goto out; +} + +/* + * Release resources when all the ports and offloading have been stopped. + */ +static void cxgb_down(struct adapter *adapter, int on_wq) +{ + t3_sge_stop(adapter); + spin_lock_irq(&adapter->work_lock); /* sync with PHY intr task */ + t3_intr_disable(adapter); + spin_unlock_irq(&adapter->work_lock); + + free_irq_resources(adapter); + quiesce_rx(adapter); + t3_sge_stop(adapter); + if (!on_wq) + flush_workqueue(cxgb3_wq);/* wait for external IRQ handler */ +} + +static void schedule_chk_task(struct adapter *adap) +{ + unsigned int timeo; + + timeo = adap->params.linkpoll_period ? + (HZ * adap->params.linkpoll_period) / 10 : + adap->params.stats_update_period * HZ; + if (timeo) + queue_delayed_work(cxgb3_wq, &adap->adap_check_task, timeo); +} + +static int offload_open(struct net_device *dev) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + struct t3cdev *tdev = dev2t3cdev(dev); + int adap_up = adapter->open_device_map & PORT_MASK; + int err; + + if (test_and_set_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) + return 0; + + if (!adap_up && (err = cxgb_up(adapter)) < 0) + goto out; + + t3_tp_set_offload_mode(adapter, 1); + tdev->lldev = adapter->port[0]; + err = cxgb3_offload_activate(adapter); + if (err) + goto out; + + init_port_mtus(adapter); + t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd, + adapter->params.b_wnd, + adapter->params.rev == 0 ? + adapter->port[0]->mtu : 0xffff); + init_smt(adapter); + + if (sysfs_create_group(&tdev->lldev->dev.kobj, &offload_attr_group)) + dev_dbg(&dev->dev, "cannot create sysfs group\n"); + + /* Call back all registered clients */ + cxgb3_add_clients(tdev); + +out: + /* restore them in case the offload module has changed them */ + if (err) { + t3_tp_set_offload_mode(adapter, 0); + clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map); + cxgb3_set_dummy_ops(tdev); + } + return err; +} + +static int offload_close(struct t3cdev *tdev) +{ + struct adapter *adapter = tdev2adap(tdev); + struct t3c_data *td = T3C_DATA(tdev); + + if (!test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) + return 0; + + /* Call back all registered clients */ + cxgb3_remove_clients(tdev); + + sysfs_remove_group(&tdev->lldev->dev.kobj, &offload_attr_group); + + /* Flush work scheduled while releasing TIDs */ + flush_work_sync(&td->tid_release_task); + + tdev->lldev = NULL; + cxgb3_set_dummy_ops(tdev); + t3_tp_set_offload_mode(adapter, 0); + clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map); + + if (!adapter->open_device_map) + cxgb_down(adapter, 0); + + cxgb3_offload_deactivate(adapter); + return 0; +} + +static int cxgb_open(struct net_device *dev) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + int other_ports = adapter->open_device_map & PORT_MASK; + int err; + + if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0) + return err; + + set_bit(pi->port_id, &adapter->open_device_map); + if (is_offload(adapter) && !ofld_disable) { + err = offload_open(dev); + if (err) + printk(KERN_WARNING + "Could not initialize offload capabilities\n"); + } + + netif_set_real_num_tx_queues(dev, pi->nqsets); + err = netif_set_real_num_rx_queues(dev, pi->nqsets); + if (err) + return err; + link_start(dev); + t3_port_intr_enable(adapter, pi->port_id); + netif_tx_start_all_queues(dev); + if (!other_ports) + schedule_chk_task(adapter); + + cxgb3_event_notify(&adapter->tdev, OFFLOAD_PORT_UP, pi->port_id); + return 0; +} + +static int __cxgb_close(struct net_device *dev, int on_wq) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + + + if (!adapter->open_device_map) + return 0; + + /* Stop link fault interrupts */ + t3_xgm_intr_disable(adapter, pi->port_id); + t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset); + + t3_port_intr_disable(adapter, pi->port_id); + netif_tx_stop_all_queues(dev); + pi->phy.ops->power_down(&pi->phy, 1); + netif_carrier_off(dev); + t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX); + + spin_lock_irq(&adapter->work_lock); /* sync with update task */ + clear_bit(pi->port_id, &adapter->open_device_map); + spin_unlock_irq(&adapter->work_lock); + + if (!(adapter->open_device_map & PORT_MASK)) + cancel_delayed_work_sync(&adapter->adap_check_task); + + if (!adapter->open_device_map) + cxgb_down(adapter, on_wq); + + cxgb3_event_notify(&adapter->tdev, OFFLOAD_PORT_DOWN, pi->port_id); + return 0; +} + +static int cxgb_close(struct net_device *dev) +{ + return __cxgb_close(dev, 0); +} + +static struct net_device_stats *cxgb_get_stats(struct net_device *dev) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + struct net_device_stats *ns = &pi->netstats; + const struct mac_stats *pstats; + + spin_lock(&adapter->stats_lock); + pstats = t3_mac_update_stats(&pi->mac); + spin_unlock(&adapter->stats_lock); + + ns->tx_bytes = pstats->tx_octets; + ns->tx_packets = pstats->tx_frames; + ns->rx_bytes = pstats->rx_octets; + ns->rx_packets = pstats->rx_frames; + ns->multicast = pstats->rx_mcast_frames; + + ns->tx_errors = pstats->tx_underrun; + ns->rx_errors = pstats->rx_symbol_errs + pstats->rx_fcs_errs + + pstats->rx_too_long + pstats->rx_jabber + pstats->rx_short + + pstats->rx_fifo_ovfl; + + /* detailed rx_errors */ + ns->rx_length_errors = pstats->rx_jabber + pstats->rx_too_long; + ns->rx_over_errors = 0; + ns->rx_crc_errors = pstats->rx_fcs_errs; + ns->rx_frame_errors = pstats->rx_symbol_errs; + ns->rx_fifo_errors = pstats->rx_fifo_ovfl; + ns->rx_missed_errors = pstats->rx_cong_drops; + + /* detailed tx_errors */ + ns->tx_aborted_errors = 0; + ns->tx_carrier_errors = 0; + ns->tx_fifo_errors = pstats->tx_underrun; + ns->tx_heartbeat_errors = 0; + ns->tx_window_errors = 0; + return ns; +} + +static u32 get_msglevel(struct net_device *dev) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + + return adapter->msg_enable; +} + +static void set_msglevel(struct net_device *dev, u32 val) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + + adapter->msg_enable = val; +} + +static char stats_strings[][ETH_GSTRING_LEN] = { + "TxOctetsOK ", + "TxFramesOK ", + "TxMulticastFramesOK", + "TxBroadcastFramesOK", + "TxPauseFrames ", + "TxUnderrun ", + "TxExtUnderrun ", + + "TxFrames64 ", + "TxFrames65To127 ", + "TxFrames128To255 ", + "TxFrames256To511 ", + "TxFrames512To1023 ", + "TxFrames1024To1518 ", + "TxFrames1519ToMax ", + + "RxOctetsOK ", + "RxFramesOK ", + "RxMulticastFramesOK", + "RxBroadcastFramesOK", + "RxPauseFrames ", + "RxFCSErrors ", + "RxSymbolErrors ", + "RxShortErrors ", + "RxJabberErrors ", + "RxLengthErrors ", + "RxFIFOoverflow ", + + "RxFrames64 ", + "RxFrames65To127 ", + "RxFrames128To255 ", + "RxFrames256To511 ", + "RxFrames512To1023 ", + "RxFrames1024To1518 ", + "RxFrames1519ToMax ", + + "PhyFIFOErrors ", + "TSO ", + "VLANextractions ", + "VLANinsertions ", + "TxCsumOffload ", + "RxCsumGood ", + "LroAggregated ", + "LroFlushed ", + "LroNoDesc ", + "RxDrops ", + + "CheckTXEnToggled ", + "CheckResets ", + + "LinkFaults ", +}; + +static int get_sset_count(struct net_device *dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(stats_strings); + default: + return -EOPNOTSUPP; + } +} + +#define T3_REGMAP_SIZE (3 * 1024) + +static int get_regs_len(struct net_device *dev) +{ + return T3_REGMAP_SIZE; +} + +static int get_eeprom_len(struct net_device *dev) +{ + return EEPROMSIZE; +} + +static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + u32 fw_vers = 0; + u32 tp_vers = 0; + + spin_lock(&adapter->stats_lock); + t3_get_fw_version(adapter, &fw_vers); + t3_get_tp_version(adapter, &tp_vers); + spin_unlock(&adapter->stats_lock); + + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + strcpy(info->bus_info, pci_name(adapter->pdev)); + if (!fw_vers) + strcpy(info->fw_version, "N/A"); + else { + snprintf(info->fw_version, sizeof(info->fw_version), + "%s %u.%u.%u TP %u.%u.%u", + G_FW_VERSION_TYPE(fw_vers) ? "T" : "N", + G_FW_VERSION_MAJOR(fw_vers), + G_FW_VERSION_MINOR(fw_vers), + G_FW_VERSION_MICRO(fw_vers), + G_TP_VERSION_MAJOR(tp_vers), + G_TP_VERSION_MINOR(tp_vers), + G_TP_VERSION_MICRO(tp_vers)); + } +} + +static void get_strings(struct net_device *dev, u32 stringset, u8 * data) +{ + if (stringset == ETH_SS_STATS) + memcpy(data, stats_strings, sizeof(stats_strings)); +} + +static unsigned long collect_sge_port_stats(struct adapter *adapter, + struct port_info *p, int idx) +{ + int i; + unsigned long tot = 0; + + for (i = p->first_qset; i < p->first_qset + p->nqsets; ++i) + tot += adapter->sge.qs[i].port_stats[idx]; + return tot; +} + +static void get_stats(struct net_device *dev, struct ethtool_stats *stats, + u64 *data) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + const struct mac_stats *s; + + spin_lock(&adapter->stats_lock); + s = t3_mac_update_stats(&pi->mac); + spin_unlock(&adapter->stats_lock); + + *data++ = s->tx_octets; + *data++ = s->tx_frames; + *data++ = s->tx_mcast_frames; + *data++ = s->tx_bcast_frames; + *data++ = s->tx_pause; + *data++ = s->tx_underrun; + *data++ = s->tx_fifo_urun; + + *data++ = s->tx_frames_64; + *data++ = s->tx_frames_65_127; + *data++ = s->tx_frames_128_255; + *data++ = s->tx_frames_256_511; + *data++ = s->tx_frames_512_1023; + *data++ = s->tx_frames_1024_1518; + *data++ = s->tx_frames_1519_max; + + *data++ = s->rx_octets; + *data++ = s->rx_frames; + *data++ = s->rx_mcast_frames; + *data++ = s->rx_bcast_frames; + *data++ = s->rx_pause; + *data++ = s->rx_fcs_errs; + *data++ = s->rx_symbol_errs; + *data++ = s->rx_short; + *data++ = s->rx_jabber; + *data++ = s->rx_too_long; + *data++ = s->rx_fifo_ovfl; + + *data++ = s->rx_frames_64; + *data++ = s->rx_frames_65_127; + *data++ = s->rx_frames_128_255; + *data++ = s->rx_frames_256_511; + *data++ = s->rx_frames_512_1023; + *data++ = s->rx_frames_1024_1518; + *data++ = s->rx_frames_1519_max; + + *data++ = pi->phy.fifo_errors; + + *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TSO); + *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANEX); + *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANINS); + *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TX_CSUM); + *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_RX_CSUM_GOOD); + *data++ = 0; + *data++ = 0; + *data++ = 0; + *data++ = s->rx_cong_drops; + + *data++ = s->num_toggled; + *data++ = s->num_resets; + + *data++ = s->link_faults; +} + +static inline void reg_block_dump(struct adapter *ap, void *buf, + unsigned int start, unsigned int end) +{ + u32 *p = buf + start; + + for (; start <= end; start += sizeof(u32)) + *p++ = t3_read_reg(ap, start); +} + +static void get_regs(struct net_device *dev, struct ethtool_regs *regs, + void *buf) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *ap = pi->adapter; + + /* + * Version scheme: + * bits 0..9: chip version + * bits 10..15: chip revision + * bit 31: set for PCIe cards + */ + regs->version = 3 | (ap->params.rev << 10) | (is_pcie(ap) << 31); + + /* + * We skip the MAC statistics registers because they are clear-on-read. + * Also reading multi-register stats would need to synchronize with the + * periodic mac stats accumulation. Hard to justify the complexity. + */ + memset(buf, 0, T3_REGMAP_SIZE); + reg_block_dump(ap, buf, 0, A_SG_RSPQ_CREDIT_RETURN); + reg_block_dump(ap, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT); + reg_block_dump(ap, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE); + reg_block_dump(ap, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA); + reg_block_dump(ap, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3); + reg_block_dump(ap, buf, A_XGM_SERDES_STATUS0, + XGM_REG(A_XGM_SERDES_STAT3, 1)); + reg_block_dump(ap, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1), + XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1)); +} + +static int restart_autoneg(struct net_device *dev) +{ + struct port_info *p = netdev_priv(dev); + + if (!netif_running(dev)) + return -EAGAIN; + if (p->link_config.autoneg != AUTONEG_ENABLE) + return -EINVAL; + p->phy.ops->autoneg_restart(&p->phy); + return 0; +} + +static int set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + + switch (state) { + case ETHTOOL_ID_ACTIVE: + return 1; /* cycle on/off once per second */ + + case ETHTOOL_ID_OFF: + t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, 0); + break; + + case ETHTOOL_ID_ON: + case ETHTOOL_ID_INACTIVE: + t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, + F_GPIO0_OUT_VAL); + } + + return 0; +} + +static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct port_info *p = netdev_priv(dev); + + cmd->supported = p->link_config.supported; + cmd->advertising = p->link_config.advertising; + + if (netif_carrier_ok(dev)) { + ethtool_cmd_speed_set(cmd, p->link_config.speed); + cmd->duplex = p->link_config.duplex; + } else { + ethtool_cmd_speed_set(cmd, -1); + cmd->duplex = -1; + } + + cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE; + cmd->phy_address = p->phy.mdio.prtad; + cmd->transceiver = XCVR_EXTERNAL; + cmd->autoneg = p->link_config.autoneg; + cmd->maxtxpkt = 0; + cmd->maxrxpkt = 0; + return 0; +} + +static int speed_duplex_to_caps(int speed, int duplex) +{ + int cap = 0; + + switch (speed) { + case SPEED_10: + if (duplex == DUPLEX_FULL) + cap = SUPPORTED_10baseT_Full; + else + cap = SUPPORTED_10baseT_Half; + break; + case SPEED_100: + if (duplex == DUPLEX_FULL) + cap = SUPPORTED_100baseT_Full; + else + cap = SUPPORTED_100baseT_Half; + break; + case SPEED_1000: + if (duplex == DUPLEX_FULL) + cap = SUPPORTED_1000baseT_Full; + else + cap = SUPPORTED_1000baseT_Half; + break; + case SPEED_10000: + if (duplex == DUPLEX_FULL) + cap = SUPPORTED_10000baseT_Full; + } + return cap; +} + +#define ADVERTISED_MASK (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \ + ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \ + ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | \ + ADVERTISED_10000baseT_Full) + +static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct port_info *p = netdev_priv(dev); + struct link_config *lc = &p->link_config; + + if (!(lc->supported & SUPPORTED_Autoneg)) { + /* + * PHY offers a single speed/duplex. See if that's what's + * being requested. + */ + if (cmd->autoneg == AUTONEG_DISABLE) { + u32 speed = ethtool_cmd_speed(cmd); + int cap = speed_duplex_to_caps(speed, cmd->duplex); + if (lc->supported & cap) + return 0; + } + return -EINVAL; + } + + if (cmd->autoneg == AUTONEG_DISABLE) { + u32 speed = ethtool_cmd_speed(cmd); + int cap = speed_duplex_to_caps(speed, cmd->duplex); + + if (!(lc->supported & cap) || (speed == SPEED_1000)) + return -EINVAL; + lc->requested_speed = speed; + lc->requested_duplex = cmd->duplex; + lc->advertising = 0; + } else { + cmd->advertising &= ADVERTISED_MASK; + cmd->advertising &= lc->supported; + if (!cmd->advertising) + return -EINVAL; + lc->requested_speed = SPEED_INVALID; + lc->requested_duplex = DUPLEX_INVALID; + lc->advertising = cmd->advertising | ADVERTISED_Autoneg; + } + lc->autoneg = cmd->autoneg; + if (netif_running(dev)) + t3_link_start(&p->phy, &p->mac, lc); + return 0; +} + +static void get_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *epause) +{ + struct port_info *p = netdev_priv(dev); + + epause->autoneg = (p->link_config.requested_fc & PAUSE_AUTONEG) != 0; + epause->rx_pause = (p->link_config.fc & PAUSE_RX) != 0; + epause->tx_pause = (p->link_config.fc & PAUSE_TX) != 0; +} + +static int set_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *epause) +{ + struct port_info *p = netdev_priv(dev); + struct link_config *lc = &p->link_config; + + if (epause->autoneg == AUTONEG_DISABLE) + lc->requested_fc = 0; + else if (lc->supported & SUPPORTED_Autoneg) + lc->requested_fc = PAUSE_AUTONEG; + else + return -EINVAL; + + if (epause->rx_pause) + lc->requested_fc |= PAUSE_RX; + if (epause->tx_pause) + lc->requested_fc |= PAUSE_TX; + if (lc->autoneg == AUTONEG_ENABLE) { + if (netif_running(dev)) + t3_link_start(&p->phy, &p->mac, lc); + } else { + lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); + if (netif_running(dev)) + t3_mac_set_speed_duplex_fc(&p->mac, -1, -1, lc->fc); + } + return 0; +} + +static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + const struct qset_params *q = &adapter->params.sge.qset[pi->first_qset]; + + e->rx_max_pending = MAX_RX_BUFFERS; + e->rx_mini_max_pending = 0; + e->rx_jumbo_max_pending = MAX_RX_JUMBO_BUFFERS; + e->tx_max_pending = MAX_TXQ_ENTRIES; + + e->rx_pending = q->fl_size; + e->rx_mini_pending = q->rspq_size; + e->rx_jumbo_pending = q->jumbo_size; + e->tx_pending = q->txq_size[0]; +} + +static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + struct qset_params *q; + int i; + + if (e->rx_pending > MAX_RX_BUFFERS || + e->rx_jumbo_pending > MAX_RX_JUMBO_BUFFERS || + e->tx_pending > MAX_TXQ_ENTRIES || + e->rx_mini_pending > MAX_RSPQ_ENTRIES || + e->rx_mini_pending < MIN_RSPQ_ENTRIES || + e->rx_pending < MIN_FL_ENTRIES || + e->rx_jumbo_pending < MIN_FL_ENTRIES || + e->tx_pending < adapter->params.nports * MIN_TXQ_ENTRIES) + return -EINVAL; + + if (adapter->flags & FULL_INIT_DONE) + return -EBUSY; + + q = &adapter->params.sge.qset[pi->first_qset]; + for (i = 0; i < pi->nqsets; ++i, ++q) { + q->rspq_size = e->rx_mini_pending; + q->fl_size = e->rx_pending; + q->jumbo_size = e->rx_jumbo_pending; + q->txq_size[0] = e->tx_pending; + q->txq_size[1] = e->tx_pending; + q->txq_size[2] = e->tx_pending; + } + return 0; +} + +static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + struct qset_params *qsp; + struct sge_qset *qs; + int i; + + if (c->rx_coalesce_usecs * 10 > M_NEWTIMER) + return -EINVAL; + + for (i = 0; i < pi->nqsets; i++) { + qsp = &adapter->params.sge.qset[i]; + qs = &adapter->sge.qs[i]; + qsp->coalesce_usecs = c->rx_coalesce_usecs; + t3_update_qset_coalesce(qs, qsp); + } + + return 0; +} + +static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + struct qset_params *q = adapter->params.sge.qset; + + c->rx_coalesce_usecs = q->coalesce_usecs; + return 0; +} + +static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e, + u8 * data) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + int i, err = 0; + + u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + e->magic = EEPROM_MAGIC; + for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4) + err = t3_seeprom_read(adapter, i, (__le32 *) & buf[i]); + + if (!err) + memcpy(data, buf + e->offset, e->len); + kfree(buf); + return err; +} + +static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, + u8 * data) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + u32 aligned_offset, aligned_len; + __le32 *p; + u8 *buf; + int err; + + if (eeprom->magic != EEPROM_MAGIC) + return -EINVAL; + + aligned_offset = eeprom->offset & ~3; + aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3; + + if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) { + buf = kmalloc(aligned_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + err = t3_seeprom_read(adapter, aligned_offset, (__le32 *) buf); + if (!err && aligned_len > 4) + err = t3_seeprom_read(adapter, + aligned_offset + aligned_len - 4, + (__le32 *) & buf[aligned_len - 4]); + if (err) + goto out; + memcpy(buf + (eeprom->offset & 3), data, eeprom->len); + } else + buf = data; + + err = t3_seeprom_wp(adapter, 0); + if (err) + goto out; + + for (p = (__le32 *) 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) + kfree(buf); + return err; +} + +static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + wol->supported = 0; + wol->wolopts = 0; + memset(&wol->sopass, 0, sizeof(wol->sopass)); +} + +static const struct ethtool_ops cxgb_ethtool_ops = { + .get_settings = get_settings, + .set_settings = set_settings, + .get_drvinfo = get_drvinfo, + .get_msglevel = get_msglevel, + .set_msglevel = set_msglevel, + .get_ringparam = get_sge_param, + .set_ringparam = set_sge_param, + .get_coalesce = get_coalesce, + .set_coalesce = set_coalesce, + .get_eeprom_len = get_eeprom_len, + .get_eeprom = get_eeprom, + .set_eeprom = set_eeprom, + .get_pauseparam = get_pauseparam, + .set_pauseparam = set_pauseparam, + .get_link = ethtool_op_get_link, + .get_strings = get_strings, + .set_phys_id = set_phys_id, + .nway_reset = restart_autoneg, + .get_sset_count = get_sset_count, + .get_ethtool_stats = get_stats, + .get_regs_len = get_regs_len, + .get_regs = get_regs, + .get_wol = get_wol, +}; + +static int in_range(int val, int lo, int hi) +{ + return val < 0 || (val <= hi && val >= lo); +} + +static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + u32 cmd; + int ret; + + if (copy_from_user(&cmd, useraddr, sizeof(cmd))) + return -EFAULT; + + switch (cmd) { + case CHELSIO_SET_QSET_PARAMS:{ + int i; + struct qset_params *q; + struct ch_qset_params t; + int q1 = pi->first_qset; + int nqsets = pi->nqsets; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (copy_from_user(&t, useraddr, sizeof(t))) + return -EFAULT; + if (t.qset_idx >= SGE_QSETS) + 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, + MAX_TXQ_ENTRIES) || + !in_range(t.txq_size[1], MIN_TXQ_ENTRIES, + MAX_TXQ_ENTRIES) || + !in_range(t.txq_size[2], MIN_CTRL_TXQ_ENTRIES, + MAX_CTRL_TXQ_ENTRIES) || + !in_range(t.fl_size[0], MIN_FL_ENTRIES, + MAX_RX_BUFFERS) || + !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; + + if ((adapter->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; + + /* Allow setting of any available qset when offload enabled */ + if (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) { + q1 = 0; + for_each_port(adapter, i) { + pi = adap2pinfo(adapter, i); + nqsets += pi->first_qset + pi->nqsets; + } + } + + if (t.qset_idx < q1) + return -EINVAL; + if (t.qset_idx > q1 + nqsets - 1) + return -EINVAL; + + q = &adapter->params.sge.qset[t.qset_idx]; + + if (t.rspq_size >= 0) + q->rspq_size = t.rspq_size; + if (t.fl_size[0] >= 0) + q->fl_size = t.fl_size[0]; + if (t.fl_size[1] >= 0) + q->jumbo_size = t.fl_size[1]; + if (t.txq_size[0] >= 0) + q->txq_size[0] = t.txq_size[0]; + if (t.txq_size[1] >= 0) + q->txq_size[1] = t.txq_size[1]; + if (t.txq_size[2] >= 0) + q->txq_size[2] = t.txq_size[2]; + if (t.cong_thres >= 0) + q->cong_thres = t.cong_thres; + if (t.intr_lat >= 0) { + struct sge_qset *qs = + &adapter->sge.qs[t.qset_idx]; + + q->coalesce_usecs = t.intr_lat; + t3_update_qset_coalesce(qs, q); + } + if (t.polling >= 0) { + if (adapter->flags & USING_MSIX) + q->polling = t.polling; + else { + /* No polling with INTx for T3A */ + if (adapter->params.rev == 0 && + !(adapter->flags & USING_MSI)) + t.polling = 0; + + for (i = 0; i < SGE_QSETS; i++) { + q = &adapter->params.sge. + qset[i]; + q->polling = t.polling; + } + } + } + + if (t.lro >= 0) { + if (t.lro) + dev->wanted_features |= NETIF_F_GRO; + else + dev->wanted_features &= ~NETIF_F_GRO; + netdev_update_features(dev); + } + + break; + } + case CHELSIO_GET_QSET_PARAMS:{ + struct qset_params *q; + struct ch_qset_params t; + int q1 = pi->first_qset; + int nqsets = pi->nqsets; + int i; + + if (copy_from_user(&t, useraddr, sizeof(t))) + return -EFAULT; + + /* Display qsets for all ports when offload enabled */ + if (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) { + q1 = 0; + for_each_port(adapter, i) { + pi = adap2pinfo(adapter, i); + nqsets = pi->first_qset + pi->nqsets; + } + } + + if (t.qset_idx >= nqsets) + return -EINVAL; + + q = &adapter->params.sge.qset[q1 + t.qset_idx]; + t.rspq_size = q->rspq_size; + t.txq_size[0] = q->txq_size[0]; + t.txq_size[1] = q->txq_size[1]; + t.txq_size[2] = q->txq_size[2]; + t.fl_size[0] = q->fl_size; + t.fl_size[1] = q->jumbo_size; + t.polling = q->polling; + t.lro = !!(dev->features & NETIF_F_GRO); + t.intr_lat = q->coalesce_usecs; + t.cong_thres = q->cong_thres; + t.qnum = q1; + + if (adapter->flags & USING_MSIX) + t.vector = adapter->msix_info[q1 + t.qset_idx + 1].vec; + else + t.vector = adapter->pdev->irq; + + if (copy_to_user(useraddr, &t, sizeof(t))) + return -EFAULT; + break; + } + case CHELSIO_SET_QSET_NUM:{ + struct ch_reg edata; + unsigned int i, first_qset = 0, other_qsets = 0; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (adapter->flags & FULL_INIT_DONE) + return -EBUSY; + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + if (edata.val < 1 || + (edata.val > 1 && !(adapter->flags & USING_MSIX))) + return -EINVAL; + + for_each_port(adapter, i) + if (adapter->port[i] && adapter->port[i] != dev) + other_qsets += adap2pinfo(adapter, i)->nqsets; + + if (edata.val + other_qsets > SGE_QSETS) + return -EINVAL; + + pi->nqsets = edata.val; + + for_each_port(adapter, i) + if (adapter->port[i]) { + pi = adap2pinfo(adapter, i); + pi->first_qset = first_qset; + first_qset += pi->nqsets; + } + break; + } + case CHELSIO_GET_QSET_NUM:{ + struct ch_reg edata; + + memset(&edata, 0, sizeof(struct ch_reg)); + + edata.cmd = CHELSIO_GET_QSET_NUM; + edata.val = pi->nqsets; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + break; + } + case CHELSIO_LOAD_FW:{ + u8 *fw_data; + struct ch_mem_range t; + + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + if (copy_from_user(&t, useraddr, sizeof(t))) + return -EFAULT; + /* Check t.len sanity ? */ + fw_data = memdup_user(useraddr + sizeof(t), t.len); + if (IS_ERR(fw_data)) + return PTR_ERR(fw_data); + + ret = t3_load_fw(adapter, fw_data, t.len); + kfree(fw_data); + if (ret) + return ret; + break; + } + case CHELSIO_SETMTUTAB:{ + struct ch_mtus m; + int i; + + if (!is_offload(adapter)) + return -EOPNOTSUPP; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (offload_running(adapter)) + return -EBUSY; + if (copy_from_user(&m, useraddr, sizeof(m))) + return -EFAULT; + if (m.nmtus != NMTUS) + return -EINVAL; + if (m.mtus[0] < 81) /* accommodate SACK */ + return -EINVAL; + + /* MTUs must be in ascending order */ + for (i = 1; i < NMTUS; ++i) + if (m.mtus[i] < m.mtus[i - 1]) + return -EINVAL; + + memcpy(adapter->params.mtus, m.mtus, + sizeof(adapter->params.mtus)); + break; + } + case CHELSIO_GET_PM:{ + struct tp_params *p = &adapter->params.tp; + struct ch_pm m = {.cmd = CHELSIO_GET_PM }; + + if (!is_offload(adapter)) + return -EOPNOTSUPP; + m.tx_pg_sz = p->tx_pg_size; + m.tx_num_pg = p->tx_num_pgs; + m.rx_pg_sz = p->rx_pg_size; + m.rx_num_pg = p->rx_num_pgs; + m.pm_total = p->pmtx_size + p->chan_rx_size * p->nchan; + if (copy_to_user(useraddr, &m, sizeof(m))) + return -EFAULT; + break; + } + case CHELSIO_SET_PM:{ + struct ch_pm m; + struct tp_params *p = &adapter->params.tp; + + if (!is_offload(adapter)) + return -EOPNOTSUPP; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (adapter->flags & FULL_INIT_DONE) + return -EBUSY; + if (copy_from_user(&m, useraddr, sizeof(m))) + return -EFAULT; + if (!is_power_of_2(m.rx_pg_sz) || + !is_power_of_2(m.tx_pg_sz)) + return -EINVAL; /* not power of 2 */ + if (!(m.rx_pg_sz & 0x14000)) + return -EINVAL; /* not 16KB or 64KB */ + if (!(m.tx_pg_sz & 0x1554000)) + return -EINVAL; + if (m.tx_num_pg == -1) + m.tx_num_pg = p->tx_num_pgs; + if (m.rx_num_pg == -1) + m.rx_num_pg = p->rx_num_pgs; + if (m.tx_num_pg % 24 || m.rx_num_pg % 24) + return -EINVAL; + if (m.rx_num_pg * m.rx_pg_sz > p->chan_rx_size || + m.tx_num_pg * m.tx_pg_sz > p->chan_tx_size) + return -EINVAL; + p->rx_pg_size = m.rx_pg_sz; + p->tx_pg_size = m.tx_pg_sz; + p->rx_num_pgs = m.rx_num_pg; + p->tx_num_pgs = m.tx_num_pg; + break; + } + case CHELSIO_GET_MEM:{ + struct ch_mem_range t; + struct mc7 *mem; + u64 buf[32]; + + if (!is_offload(adapter)) + return -EOPNOTSUPP; + if (!(adapter->flags & FULL_INIT_DONE)) + return -EIO; /* need the memory controllers */ + if (copy_from_user(&t, useraddr, sizeof(t))) + return -EFAULT; + if ((t.addr & 7) || (t.len & 7)) + return -EINVAL; + if (t.mem_id == MEM_CM) + mem = &adapter->cm; + else if (t.mem_id == MEM_PMRX) + mem = &adapter->pmrx; + else if (t.mem_id == MEM_PMTX) + mem = &adapter->pmtx; + else + return -EINVAL; + + /* + * Version scheme: + * bits 0..9: chip version + * bits 10..15: chip revision + */ + t.version = 3 | (adapter->params.rev << 10); + if (copy_to_user(useraddr, &t, sizeof(t))) + return -EFAULT; + + /* + * Read 256 bytes at a time as len can be large and we don't + * want to use huge intermediate buffers. + */ + useraddr += sizeof(t); /* advance to start of buffer */ + while (t.len) { + unsigned int chunk = + min_t(unsigned int, t.len, sizeof(buf)); + + ret = + t3_mc7_bd_read(mem, t.addr / 8, chunk / 8, + buf); + if (ret) + return ret; + if (copy_to_user(useraddr, buf, chunk)) + return -EFAULT; + useraddr += chunk; + t.addr += chunk; + t.len -= chunk; + } + break; + } + case CHELSIO_SET_TRACE_FILTER:{ + struct ch_trace t; + const struct trace_params *tp; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (!offload_running(adapter)) + return -EAGAIN; + if (copy_from_user(&t, useraddr, sizeof(t))) + return -EFAULT; + + tp = (const struct trace_params *)&t.sip; + if (t.config_tx) + t3_config_trace_filter(adapter, tp, 0, + t.invert_match, + t.trace_tx); + if (t.config_rx) + t3_config_trace_filter(adapter, tp, 1, + t.invert_match, + t.trace_rx); + break; + } + default: + return -EOPNOTSUPP; + } + return 0; +} + +static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd) +{ + struct mii_ioctl_data *data = if_mii(req); + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + + switch (cmd) { + case SIOCGMIIREG: + case SIOCSMIIREG: + /* Convert phy_id from older PRTAD/DEVAD format */ + if (is_10G(adapter) && + !mdio_phy_id_is_c45(data->phy_id) && + (data->phy_id & 0x1f00) && + !(data->phy_id & 0xe0e0)) + data->phy_id = mdio_phy_id_c45(data->phy_id >> 8, + data->phy_id & 0x1f); + /* FALLTHRU */ + case SIOCGMIIPHY: + return mdio_mii_ioctl(&pi->phy.mdio, data, cmd); + case SIOCCHIOCTL: + return cxgb_extension_ioctl(dev, req->ifr_data); + default: + return -EOPNOTSUPP; + } +} + +static int cxgb_change_mtu(struct net_device *dev, int new_mtu) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + int ret; + + if (new_mtu < 81) /* accommodate SACK */ + return -EINVAL; + if ((ret = t3_mac_set_mtu(&pi->mac, new_mtu))) + return ret; + dev->mtu = new_mtu; + init_port_mtus(adapter); + if (adapter->params.rev == 0 && offload_running(adapter)) + t3_load_mtus(adapter, adapter->params.mtus, + adapter->params.a_wnd, adapter->params.b_wnd, + adapter->port[0]->mtu); + return 0; +} + +static int cxgb_set_mac_addr(struct net_device *dev, void *p) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EINVAL; + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + t3_mac_set_address(&pi->mac, LAN_MAC_IDX, dev->dev_addr); + if (offload_running(adapter)) + write_smt_entry(adapter, pi->port_id); + return 0; +} + +/** + * t3_synchronize_rx - wait for current Rx processing on a port to complete + * @adap: the adapter + * @p: the port + * + * Ensures that current Rx processing on any of the queues associated with + * the given port completes before returning. We do this by acquiring and + * releasing the locks of the response queues associated with the port. + */ +static void t3_synchronize_rx(struct adapter *adap, const struct port_info *p) +{ + int i; + + for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) { + struct sge_rspq *q = &adap->sge.qs[i].rspq; + + spin_lock_irq(&q->lock); + spin_unlock_irq(&q->lock); + } +} + +static void cxgb_vlan_mode(struct net_device *dev, u32 features) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + + if (adapter->params.rev > 0) { + t3_set_vlan_accel(adapter, 1 << pi->port_id, + features & NETIF_F_HW_VLAN_RX); + } else { + /* single control for all ports */ + unsigned int i, have_vlans = features & NETIF_F_HW_VLAN_RX; + + for_each_port(adapter, i) + have_vlans |= + adapter->port[i]->features & NETIF_F_HW_VLAN_RX; + + t3_set_vlan_accel(adapter, 1, have_vlans); + } + t3_synchronize_rx(adapter, pi); +} + +static u32 cxgb_fix_features(struct net_device *dev, u32 features) +{ + /* + * Since there is no support for separate rx/tx vlan accel + * enable/disable make sure tx flag is always in same state as rx. + */ + if (features & NETIF_F_HW_VLAN_RX) + features |= NETIF_F_HW_VLAN_TX; + else + features &= ~NETIF_F_HW_VLAN_TX; + + return features; +} + +static int cxgb_set_features(struct net_device *dev, u32 features) +{ + u32 changed = dev->features ^ features; + + if (changed & NETIF_F_HW_VLAN_RX) + cxgb_vlan_mode(dev, features); + + return 0; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void cxgb_netpoll(struct net_device *dev) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + int qidx; + + for (qidx = pi->first_qset; qidx < pi->first_qset + pi->nqsets; qidx++) { + struct sge_qset *qs = &adapter->sge.qs[qidx]; + void *source; + + if (adapter->flags & USING_MSIX) + source = qs; + else + source = adapter; + + t3_intr_handler(adapter, qs->rspq.polling) (0, source); + } +} +#endif + +/* + * Periodic accumulation of MAC statistics. + */ +static void mac_stats_update(struct adapter *adapter) +{ + int i; + + for_each_port(adapter, i) { + struct net_device *dev = adapter->port[i]; + struct port_info *p = netdev_priv(dev); + + if (netif_running(dev)) { + spin_lock(&adapter->stats_lock); + t3_mac_update_stats(&p->mac); + spin_unlock(&adapter->stats_lock); + } + } +} + +static void check_link_status(struct adapter *adapter) +{ + int i; + + for_each_port(adapter, i) { + struct net_device *dev = adapter->port[i]; + struct port_info *p = netdev_priv(dev); + int link_fault; + + spin_lock_irq(&adapter->work_lock); + link_fault = p->link_fault; + spin_unlock_irq(&adapter->work_lock); + + if (link_fault) { + t3_link_fault(adapter, i); + continue; + } + + if (!(p->phy.caps & SUPPORTED_IRQ) && netif_running(dev)) { + t3_xgm_intr_disable(adapter, i); + t3_read_reg(adapter, A_XGM_INT_STATUS + p->mac.offset); + + t3_link_changed(adapter, i); + t3_xgm_intr_enable(adapter, i); + } + } +} + +static void check_t3b2_mac(struct adapter *adapter) +{ + int i; + + if (!rtnl_trylock()) /* synchronize with ifdown */ + return; + + for_each_port(adapter, i) { + struct net_device *dev = adapter->port[i]; + struct port_info *p = netdev_priv(dev); + int status; + + if (!netif_running(dev)) + continue; + + status = 0; + if (netif_running(dev) && netif_carrier_ok(dev)) + status = t3b2_mac_watchdog_task(&p->mac); + if (status == 1) + p->mac.stats.num_toggled++; + else if (status == 2) { + struct cmac *mac = &p->mac; + + t3_mac_set_mtu(mac, dev->mtu); + t3_mac_set_address(mac, LAN_MAC_IDX, dev->dev_addr); + cxgb_set_rxmode(dev); + 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_id); + p->mac.stats.num_resets++; + } + } + rtnl_unlock(); +} + + +static void t3_adap_check_task(struct work_struct *work) +{ + struct adapter *adapter = container_of(work, struct adapter, + adap_check_task.work); + const struct adapter_params *p = &adapter->params; + int port; + unsigned int v, status, reset; + + adapter->check_task_cnt++; + + check_link_status(adapter); + + /* Accumulate MAC stats if needed */ + if (!p->linkpoll_period || + (adapter->check_task_cnt * p->linkpoll_period) / 10 >= + p->stats_update_period) { + mac_stats_update(adapter); + adapter->check_task_cnt = 0; + } + + if (p->rev == T3_REV_B2) + check_t3b2_mac(adapter); + + /* + * Scan the XGMAC's to check for various conditions which we want to + * monitor in a periodic polling manner rather than via an interrupt + * condition. This is used for conditions which would otherwise flood + * the system with interrupts and we only really need to know that the + * conditions are "happening" ... For each condition we count the + * detection of the condition and reset it for the next polling loop. + */ + for_each_port(adapter, port) { + struct cmac *mac = &adap2pinfo(adapter, port)->mac; + u32 cause; + + cause = t3_read_reg(adapter, A_XGM_INT_CAUSE + mac->offset); + reset = 0; + if (cause & F_RXFIFO_OVERFLOW) { + mac->stats.rx_fifo_ovfl++; + reset |= F_RXFIFO_OVERFLOW; + } + + t3_write_reg(adapter, A_XGM_INT_CAUSE + mac->offset, reset); + } + + /* + * We do the same as above for FL_EMPTY interrupts. + */ + status = t3_read_reg(adapter, A_SG_INT_CAUSE); + reset = 0; + + if (status & F_FLEMPTY) { + struct sge_qset *qs = &adapter->sge.qs[0]; + int i = 0; + + reset |= F_FLEMPTY; + + v = (t3_read_reg(adapter, A_SG_RSPQ_FL_STATUS) >> S_FL0EMPTY) & + 0xffff; + + while (v) { + qs->fl[i].empty += (v & 1); + if (i) + qs++; + i ^= 1; + v >>= 1; + } + } + + t3_write_reg(adapter, A_SG_INT_CAUSE, reset); + + /* Schedule the next check update if any port is active. */ + spin_lock_irq(&adapter->work_lock); + if (adapter->open_device_map & PORT_MASK) + schedule_chk_task(adapter); + spin_unlock_irq(&adapter->work_lock); +} + +static void db_full_task(struct work_struct *work) +{ + struct adapter *adapter = container_of(work, struct adapter, + db_full_task); + + cxgb3_event_notify(&adapter->tdev, OFFLOAD_DB_FULL, 0); +} + +static void db_empty_task(struct work_struct *work) +{ + struct adapter *adapter = container_of(work, struct adapter, + db_empty_task); + + cxgb3_event_notify(&adapter->tdev, OFFLOAD_DB_EMPTY, 0); +} + +static void db_drop_task(struct work_struct *work) +{ + struct adapter *adapter = container_of(work, struct adapter, + db_drop_task); + unsigned long delay = 1000; + unsigned short r; + + cxgb3_event_notify(&adapter->tdev, OFFLOAD_DB_DROP, 0); + + /* + * Sleep a while before ringing the driver qset dbs. + * The delay is between 1000-2023 usecs. + */ + get_random_bytes(&r, 2); + delay += r & 1023; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(usecs_to_jiffies(delay)); + ring_dbs(adapter); +} + +/* + * Processes external (PHY) interrupts in process context. + */ +static void ext_intr_task(struct work_struct *work) +{ + struct adapter *adapter = container_of(work, struct adapter, + ext_intr_handler_task); + int i; + + /* Disable link fault interrupts */ + for_each_port(adapter, i) { + struct net_device *dev = adapter->port[i]; + struct port_info *p = netdev_priv(dev); + + t3_xgm_intr_disable(adapter, i); + t3_read_reg(adapter, A_XGM_INT_STATUS + p->mac.offset); + } + + /* Re-enable link fault interrupts */ + t3_phy_intr_handler(adapter); + + for_each_port(adapter, i) + t3_xgm_intr_enable(adapter, i); + + /* Now reenable external interrupts */ + spin_lock_irq(&adapter->work_lock); + if (adapter->slow_intr_mask) { + adapter->slow_intr_mask |= F_T3DBG; + t3_write_reg(adapter, A_PL_INT_CAUSE0, F_T3DBG); + t3_write_reg(adapter, A_PL_INT_ENABLE0, + adapter->slow_intr_mask); + } + spin_unlock_irq(&adapter->work_lock); +} + +/* + * Interrupt-context handler for external (PHY) interrupts. + */ +void t3_os_ext_intr_handler(struct adapter *adapter) +{ + /* + * Schedule a task to handle external interrupts as they may be slow + * and we use a mutex to protect MDIO registers. We disable PHY + * interrupts in the meantime and let the task reenable them when + * it's done. + */ + spin_lock(&adapter->work_lock); + if (adapter->slow_intr_mask) { + adapter->slow_intr_mask &= ~F_T3DBG; + t3_write_reg(adapter, A_PL_INT_ENABLE0, + adapter->slow_intr_mask); + queue_work(cxgb3_wq, &adapter->ext_intr_handler_task); + } + spin_unlock(&adapter->work_lock); +} + +void t3_os_link_fault_handler(struct adapter *adapter, int port_id) +{ + struct net_device *netdev = adapter->port[port_id]; + struct port_info *pi = netdev_priv(netdev); + + spin_lock(&adapter->work_lock); + pi->link_fault = 1; + spin_unlock(&adapter->work_lock); +} + +static int t3_adapter_error(struct adapter *adapter, int reset, int on_wq) +{ + int i, ret = 0; + + if (is_offload(adapter) && + test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) { + cxgb3_event_notify(&adapter->tdev, OFFLOAD_STATUS_DOWN, 0); + offload_close(&adapter->tdev); + } + + /* Stop all ports */ + for_each_port(adapter, i) { + struct net_device *netdev = adapter->port[i]; + + if (netif_running(netdev)) + __cxgb_close(netdev, on_wq); + } + + /* Stop SGE timers */ + t3_stop_sge_timers(adapter); + + adapter->flags &= ~FULL_INIT_DONE; + + if (reset) + ret = t3_reset_adapter(adapter); + + pci_disable_device(adapter->pdev); + + return ret; +} + +static int t3_reenable_adapter(struct adapter *adapter) +{ + if (pci_enable_device(adapter->pdev)) { + dev_err(&adapter->pdev->dev, + "Cannot re-enable PCI device after reset.\n"); + goto err; + } + pci_set_master(adapter->pdev); + pci_restore_state(adapter->pdev); + pci_save_state(adapter->pdev); + + /* Free sge resources */ + t3_free_sge_resources(adapter); + + if (t3_replay_prep_adapter(adapter)) + goto err; + + return 0; +err: + return -1; +} + +static void t3_resume_ports(struct adapter *adapter) +{ + int i; + + /* Restart the ports */ + for_each_port(adapter, i) { + struct net_device *netdev = adapter->port[i]; + + if (netif_running(netdev)) { + if (cxgb_open(netdev)) { + dev_err(&adapter->pdev->dev, + "can't bring device back up" + " after reset\n"); + continue; + } + } + } + + if (is_offload(adapter) && !ofld_disable) + cxgb3_event_notify(&adapter->tdev, OFFLOAD_STATUS_UP, 0); +} + +/* + * processes a fatal error. + * Bring the ports down, reset the chip, bring the ports back up. + */ +static void fatal_error_task(struct work_struct *work) +{ + struct adapter *adapter = container_of(work, struct adapter, + fatal_error_handler_task); + int err = 0; + + rtnl_lock(); + err = t3_adapter_error(adapter, 1, 1); + if (!err) + err = t3_reenable_adapter(adapter); + if (!err) + t3_resume_ports(adapter); + + CH_ALERT(adapter, "adapter reset %s\n", err ? "failed" : "succeeded"); + rtnl_unlock(); +} + +void t3_fatal_err(struct adapter *adapter) +{ + unsigned int fw_status[4]; + + if (adapter->flags & FULL_INIT_DONE) { + t3_sge_stop(adapter); + t3_write_reg(adapter, A_XGM_TX_CTRL, 0); + t3_write_reg(adapter, A_XGM_RX_CTRL, 0); + t3_write_reg(adapter, XGM_REG(A_XGM_TX_CTRL, 1), 0); + t3_write_reg(adapter, XGM_REG(A_XGM_RX_CTRL, 1), 0); + + spin_lock(&adapter->work_lock); + t3_intr_disable(adapter); + queue_work(cxgb3_wq, &adapter->fatal_error_handler_task); + spin_unlock(&adapter->work_lock); + } + CH_ALERT(adapter, "encountered fatal error, operation suspended\n"); + if (!t3_cim_ctl_blk_read(adapter, 0xa0, 4, fw_status)) + CH_ALERT(adapter, "FW status: 0x%x, 0x%x, 0x%x, 0x%x\n", + fw_status[0], fw_status[1], + fw_status[2], fw_status[3]); +} + +/** + * t3_io_error_detected - called when PCI error is detected + * @pdev: Pointer to PCI device + * @state: The current pci connection state + * + * This function is called after a PCI bus error affecting + * this device has been detected. + */ +static pci_ers_result_t t3_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct adapter *adapter = pci_get_drvdata(pdev); + + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + + t3_adapter_error(adapter, 0, 0); + + /* Request a slot reset. */ + return PCI_ERS_RESULT_NEED_RESET; +} + +/** + * t3_io_slot_reset - called after the pci bus has been reset. + * @pdev: Pointer to PCI device + * + * Restart the card from scratch, as if from a cold-boot. + */ +static pci_ers_result_t t3_io_slot_reset(struct pci_dev *pdev) +{ + struct adapter *adapter = pci_get_drvdata(pdev); + + if (!t3_reenable_adapter(adapter)) + return PCI_ERS_RESULT_RECOVERED; + + return PCI_ERS_RESULT_DISCONNECT; +} + +/** + * t3_io_resume - called when traffic can start flowing again. + * @pdev: Pointer to PCI device + * + * This callback is called when the error recovery driver tells us that + * its OK to resume normal operation. + */ +static void t3_io_resume(struct pci_dev *pdev) +{ + struct adapter *adapter = pci_get_drvdata(pdev); + + CH_ALERT(adapter, "adapter recovering, PEX ERR 0x%x\n", + t3_read_reg(adapter, A_PCIE_PEX_ERR)); + + t3_resume_ports(adapter); +} + +static struct pci_error_handlers t3_err_handler = { + .error_detected = t3_io_error_detected, + .slot_reset = t3_io_slot_reset, + .resume = t3_io_resume, +}; + +/* + * Set the number of qsets based on the number of CPUs and the number of ports, + * not to exceed the number of available qsets, assuming there are enough qsets + * per port in HW. + */ +static void set_nqsets(struct adapter *adap) +{ + int i, j = 0; + int num_cpus = num_online_cpus(); + int hwports = adap->params.nports; + int nqsets = adap->msix_nvectors - 1; + + if (adap->params.rev > 0 && adap->flags & USING_MSIX) { + if (hwports == 2 && + (hwports * nqsets > SGE_QSETS || + num_cpus >= nqsets / hwports)) + nqsets /= hwports; + if (nqsets > num_cpus) + nqsets = num_cpus; + if (nqsets < 1 || hwports == 4) + nqsets = 1; + } else + nqsets = 1; + + for_each_port(adap, i) { + struct port_info *pi = adap2pinfo(adap, i); + + pi->first_qset = j; + pi->nqsets = nqsets; + j = pi->first_qset + nqsets; + + dev_info(&adap->pdev->dev, + "Port %d using %d queue sets.\n", i, nqsets); + } +} + +static int __devinit cxgb_enable_msix(struct adapter *adap) +{ + struct msix_entry entries[SGE_QSETS + 1]; + int vectors; + int i, err; + + vectors = ARRAY_SIZE(entries); + for (i = 0; i < vectors; ++i) + entries[i].entry = i; + + while ((err = pci_enable_msix(adap->pdev, entries, vectors)) > 0) + vectors = err; + + if (err < 0) + pci_disable_msix(adap->pdev); + + if (!err && vectors < (adap->params.nports + 1)) { + pci_disable_msix(adap->pdev); + err = -1; + } + + if (!err) { + for (i = 0; i < vectors; ++i) + adap->msix_info[i].vec = entries[i].vector; + adap->msix_nvectors = vectors; + } + + return err; +} + +static void __devinit print_port_info(struct adapter *adap, + const struct adapter_info *ai) +{ + static const char *pci_variant[] = { + "PCI", "PCI-X", "PCI-X ECC", "PCI-X 266", "PCI Express" + }; + + int i; + char buf[80]; + + if (is_pcie(adap)) + snprintf(buf, sizeof(buf), "%s x%d", + pci_variant[adap->params.pci.variant], + adap->params.pci.width); + else + snprintf(buf, sizeof(buf), "%s %dMHz/%d-bit", + pci_variant[adap->params.pci.variant], + adap->params.pci.speed, adap->params.pci.width); + + for_each_port(adap, i) { + struct net_device *dev = adap->port[i]; + const struct port_info *pi = netdev_priv(dev); + + if (!test_bit(i, &adap->registered_device_map)) + continue; + printk(KERN_INFO "%s: %s %s %sNIC (rev %d) %s%s\n", + dev->name, ai->desc, pi->phy.desc, + is_offload(adap) ? "R" : "", adap->params.rev, buf, + (adap->flags & USING_MSIX) ? " MSI-X" : + (adap->flags & USING_MSI) ? " MSI" : ""); + if (adap->name == dev->name && adap->params.vpd.mclk) + printk(KERN_INFO + "%s: %uMB CM, %uMB PMTX, %uMB PMRX, S/N: %s\n", + adap->name, t3_mc7_size(&adap->cm) >> 20, + t3_mc7_size(&adap->pmtx) >> 20, + t3_mc7_size(&adap->pmrx) >> 20, + adap->params.vpd.sn); + } +} + +static const struct net_device_ops cxgb_netdev_ops = { + .ndo_open = cxgb_open, + .ndo_stop = cxgb_close, + .ndo_start_xmit = t3_eth_xmit, + .ndo_get_stats = cxgb_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = cxgb_set_rxmode, + .ndo_do_ioctl = cxgb_ioctl, + .ndo_change_mtu = cxgb_change_mtu, + .ndo_set_mac_address = cxgb_set_mac_addr, + .ndo_fix_features = cxgb_fix_features, + .ndo_set_features = cxgb_set_features, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = cxgb_netpoll, +#endif +}; + +static void __devinit cxgb3_init_iscsi_mac(struct net_device *dev) +{ + struct port_info *pi = netdev_priv(dev); + + memcpy(pi->iscsic.mac_addr, dev->dev_addr, ETH_ALEN); + pi->iscsic.mac_addr[3] |= 0x80; +} + +static int __devinit init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + static int version_printed; + + int i, err, pci_using_dac = 0; + resource_size_t mmio_start, mmio_len; + const struct adapter_info *ai; + struct adapter *adapter = NULL; + struct port_info *pi; + + if (!version_printed) { + printk(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION); + ++version_printed; + } + + if (!cxgb3_wq) { + cxgb3_wq = create_singlethread_workqueue(DRV_NAME); + if (!cxgb3_wq) { + printk(KERN_ERR DRV_NAME + ": cannot initialize work queue\n"); + return -ENOMEM; + } + } + + err = pci_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, "cannot enable PCI device\n"); + goto out; + } + + err = pci_request_regions(pdev, DRV_NAME); + if (err) { + /* Just info, some other driver may have claimed the device. */ + dev_info(&pdev->dev, "cannot obtain PCI resources\n"); + goto out_disable_device; + } + + if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { + pci_using_dac = 1; + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + if (err) { + dev_err(&pdev->dev, "unable to obtain 64-bit DMA for " + "coherent allocations\n"); + goto out_release_regions; + } + } else if ((err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) != 0) { + dev_err(&pdev->dev, "no usable DMA configuration\n"); + goto out_release_regions; + } + + pci_set_master(pdev); + pci_save_state(pdev); + + mmio_start = pci_resource_start(pdev, 0); + mmio_len = pci_resource_len(pdev, 0); + ai = t3_get_adapter_info(ent->driver_data); + + adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); + if (!adapter) { + err = -ENOMEM; + goto out_release_regions; + } + + adapter->nofail_skb = + alloc_skb(sizeof(struct cpl_set_tcb_field), GFP_KERNEL); + if (!adapter->nofail_skb) { + dev_err(&pdev->dev, "cannot allocate nofail buffer\n"); + err = -ENOMEM; + goto out_free_adapter; + } + + adapter->regs = ioremap_nocache(mmio_start, mmio_len); + if (!adapter->regs) { + dev_err(&pdev->dev, "cannot map device registers\n"); + err = -ENOMEM; + goto out_free_adapter; + } + + adapter->pdev = pdev; + adapter->name = pci_name(pdev); + adapter->msg_enable = dflt_msg_enable; + adapter->mmio_len = mmio_len; + + mutex_init(&adapter->mdio_lock); + spin_lock_init(&adapter->work_lock); + spin_lock_init(&adapter->stats_lock); + + INIT_LIST_HEAD(&adapter->adapter_list); + INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task); + INIT_WORK(&adapter->fatal_error_handler_task, fatal_error_task); + + INIT_WORK(&adapter->db_full_task, db_full_task); + INIT_WORK(&adapter->db_empty_task, db_empty_task); + INIT_WORK(&adapter->db_drop_task, db_drop_task); + + INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task); + + for (i = 0; i < ai->nports0 + ai->nports1; ++i) { + struct net_device *netdev; + + netdev = alloc_etherdev_mq(sizeof(struct port_info), SGE_QSETS); + if (!netdev) { + err = -ENOMEM; + goto out_free_dev; + } + + SET_NETDEV_DEV(netdev, &pdev->dev); + + adapter->port[i] = netdev; + pi = netdev_priv(netdev); + pi->adapter = adapter; + pi->port_id = i; + netif_carrier_off(netdev); + netdev->irq = pdev->irq; + netdev->mem_start = mmio_start; + netdev->mem_end = mmio_start + mmio_len - 1; + netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_TSO | NETIF_F_RXCSUM | NETIF_F_HW_VLAN_RX; + netdev->features |= netdev->hw_features | NETIF_F_HW_VLAN_TX; + if (pci_using_dac) + netdev->features |= NETIF_F_HIGHDMA; + + netdev->netdev_ops = &cxgb_netdev_ops; + SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops); + } + + pci_set_drvdata(pdev, adapter); + if (t3_prep_adapter(adapter, ai, 1) < 0) { + err = -ENODEV; + goto out_free_dev; + } + + /* + * The card is now ready to go. If any errors occur during device + * registration we do not fail the whole card but rather proceed only + * with the ports we manage to register successfully. However we must + * register at least one net device. + */ + for_each_port(adapter, i) { + err = register_netdev(adapter->port[i]); + if (err) + dev_warn(&pdev->dev, + "cannot register net device %s, skipping\n", + adapter->port[i]->name); + else { + /* + * Change the name we use for messages to the name of + * the first successfully registered interface. + */ + if (!adapter->registered_device_map) + adapter->name = adapter->port[i]->name; + + __set_bit(i, &adapter->registered_device_map); + } + } + if (!adapter->registered_device_map) { + dev_err(&pdev->dev, "could not register any net devices\n"); + goto out_free_dev; + } + + for_each_port(adapter, i) + cxgb3_init_iscsi_mac(adapter->port[i]); + + /* Driver's ready. Reflect it on LEDs */ + t3_led_ready(adapter); + + if (is_offload(adapter)) { + __set_bit(OFFLOAD_DEVMAP_BIT, &adapter->registered_device_map); + cxgb3_adapter_ofld(adapter); + } + + /* See what interrupts we'll be using */ + if (msi > 1 && cxgb_enable_msix(adapter) == 0) + adapter->flags |= USING_MSIX; + else if (msi > 0 && pci_enable_msi(pdev) == 0) + adapter->flags |= USING_MSI; + + set_nqsets(adapter); + + err = sysfs_create_group(&adapter->port[0]->dev.kobj, + &cxgb3_attr_group); + + for_each_port(adapter, i) + cxgb_vlan_mode(adapter->port[i], adapter->port[i]->features); + + print_port_info(adapter, ai); + return 0; + +out_free_dev: + iounmap(adapter->regs); + for (i = ai->nports0 + ai->nports1 - 1; i >= 0; --i) + if (adapter->port[i]) + free_netdev(adapter->port[i]); + +out_free_adapter: + kfree(adapter); + +out_release_regions: + pci_release_regions(pdev); +out_disable_device: + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +out: + return err; +} + +static void __devexit remove_one(struct pci_dev *pdev) +{ + struct adapter *adapter = pci_get_drvdata(pdev); + + if (adapter) { + int i; + + t3_sge_stop(adapter); + sysfs_remove_group(&adapter->port[0]->dev.kobj, + &cxgb3_attr_group); + + if (is_offload(adapter)) { + cxgb3_adapter_unofld(adapter); + if (test_bit(OFFLOAD_DEVMAP_BIT, + &adapter->open_device_map)) + offload_close(&adapter->tdev); + } + + for_each_port(adapter, i) + if (test_bit(i, &adapter->registered_device_map)) + unregister_netdev(adapter->port[i]); + + t3_stop_sge_timers(adapter); + t3_free_sge_resources(adapter); + cxgb_disable_msi(adapter); + + for_each_port(adapter, i) + if (adapter->port[i]) + free_netdev(adapter->port[i]); + + iounmap(adapter->regs); + if (adapter->nofail_skb) + kfree_skb(adapter->nofail_skb); + kfree(adapter); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + } +} + +static struct pci_driver driver = { + .name = DRV_NAME, + .id_table = cxgb3_pci_tbl, + .probe = init_one, + .remove = __devexit_p(remove_one), + .err_handler = &t3_err_handler, +}; + +static int __init cxgb3_init_module(void) +{ + int ret; + + cxgb3_offload_init(); + + ret = pci_register_driver(&driver); + return ret; +} + +static void __exit cxgb3_cleanup_module(void) +{ + pci_unregister_driver(&driver); + if (cxgb3_wq) + destroy_workqueue(cxgb3_wq); +} + +module_init(cxgb3_init_module); +module_exit(cxgb3_cleanup_module); diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c new file mode 100644 index 000000000000..805076c54f1b --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c @@ -0,0 +1,1418 @@ +/* + * Copyright (c) 2006-2008 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "regs.h" +#include "cxgb3_ioctl.h" +#include "cxgb3_ctl_defs.h" +#include "cxgb3_defs.h" +#include "l2t.h" +#include "firmware_exports.h" +#include "cxgb3_offload.h" + +static LIST_HEAD(client_list); +static LIST_HEAD(ofld_dev_list); +static DEFINE_MUTEX(cxgb3_db_lock); + +static DEFINE_RWLOCK(adapter_list_lock); +static LIST_HEAD(adapter_list); + +static const unsigned int MAX_ATIDS = 64 * 1024; +static const unsigned int ATID_BASE = 0x10000; + +static void cxgb_neigh_update(struct neighbour *neigh); +static void cxgb_redirect(struct dst_entry *old, struct dst_entry *new); + +static inline int offload_activated(struct t3cdev *tdev) +{ + const struct adapter *adapter = tdev2adap(tdev); + + return test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map); +} + +/** + * cxgb3_register_client - register an offload client + * @client: the client + * + * Add the client to the client list, + * and call backs the client for each activated offload device + */ +void cxgb3_register_client(struct cxgb3_client *client) +{ + struct t3cdev *tdev; + + mutex_lock(&cxgb3_db_lock); + list_add_tail(&client->client_list, &client_list); + + if (client->add) { + list_for_each_entry(tdev, &ofld_dev_list, ofld_dev_list) { + if (offload_activated(tdev)) + client->add(tdev); + } + } + mutex_unlock(&cxgb3_db_lock); +} + +EXPORT_SYMBOL(cxgb3_register_client); + +/** + * cxgb3_unregister_client - unregister an offload client + * @client: the client + * + * Remove the client to the client list, + * and call backs the client for each activated offload device. + */ +void cxgb3_unregister_client(struct cxgb3_client *client) +{ + struct t3cdev *tdev; + + mutex_lock(&cxgb3_db_lock); + list_del(&client->client_list); + + if (client->remove) { + list_for_each_entry(tdev, &ofld_dev_list, ofld_dev_list) { + if (offload_activated(tdev)) + client->remove(tdev); + } + } + mutex_unlock(&cxgb3_db_lock); +} + +EXPORT_SYMBOL(cxgb3_unregister_client); + +/** + * cxgb3_add_clients - activate registered clients for an offload device + * @tdev: the offload device + * + * Call backs all registered clients once a offload device is activated + */ +void cxgb3_add_clients(struct t3cdev *tdev) +{ + struct cxgb3_client *client; + + mutex_lock(&cxgb3_db_lock); + list_for_each_entry(client, &client_list, client_list) { + if (client->add) + client->add(tdev); + } + mutex_unlock(&cxgb3_db_lock); +} + +/** + * cxgb3_remove_clients - deactivates registered clients + * for an offload device + * @tdev: the offload device + * + * Call backs all registered clients once a offload device is deactivated + */ +void cxgb3_remove_clients(struct t3cdev *tdev) +{ + struct cxgb3_client *client; + + mutex_lock(&cxgb3_db_lock); + list_for_each_entry(client, &client_list, client_list) { + if (client->remove) + client->remove(tdev); + } + mutex_unlock(&cxgb3_db_lock); +} + +void cxgb3_event_notify(struct t3cdev *tdev, u32 event, u32 port) +{ + struct cxgb3_client *client; + + mutex_lock(&cxgb3_db_lock); + list_for_each_entry(client, &client_list, client_list) { + if (client->event_handler) + client->event_handler(tdev, event, port); + } + mutex_unlock(&cxgb3_db_lock); +} + +static struct net_device *get_iff_from_mac(struct adapter *adapter, + const unsigned char *mac, + unsigned int vlan) +{ + int i; + + for_each_port(adapter, i) { + struct net_device *dev = adapter->port[i]; + + if (!memcmp(dev->dev_addr, mac, ETH_ALEN)) { + if (vlan && vlan != VLAN_VID_MASK) { + rcu_read_lock(); + dev = __vlan_find_dev_deep(dev, vlan); + rcu_read_unlock(); + } else if (netif_is_bond_slave(dev)) { + while (dev->master) + dev = dev->master; + } + return dev; + } + } + return NULL; +} + +static int cxgb_ulp_iscsi_ctl(struct adapter *adapter, unsigned int req, + void *data) +{ + int i; + int ret = 0; + unsigned int val = 0; + struct ulp_iscsi_info *uiip = data; + + switch (req) { + case ULP_ISCSI_GET_PARAMS: + uiip->pdev = adapter->pdev; + uiip->llimit = t3_read_reg(adapter, A_ULPRX_ISCSI_LLIMIT); + uiip->ulimit = t3_read_reg(adapter, A_ULPRX_ISCSI_ULIMIT); + uiip->tagmask = t3_read_reg(adapter, A_ULPRX_ISCSI_TAGMASK); + + val = t3_read_reg(adapter, A_ULPRX_ISCSI_PSZ); + for (i = 0; i < 4; i++, val >>= 8) + uiip->pgsz_factor[i] = val & 0xFF; + + val = t3_read_reg(adapter, A_TP_PARA_REG7); + uiip->max_txsz = + uiip->max_rxsz = min((val >> S_PMMAXXFERLEN0)&M_PMMAXXFERLEN0, + (val >> S_PMMAXXFERLEN1)&M_PMMAXXFERLEN1); + /* + * On tx, the iscsi pdu has to be <= tx page size and has to + * fit into the Tx PM FIFO. + */ + val = min(adapter->params.tp.tx_pg_size, + t3_read_reg(adapter, A_PM1_TX_CFG) >> 17); + uiip->max_txsz = min(val, uiip->max_txsz); + + /* set MaxRxData to 16224 */ + val = t3_read_reg(adapter, A_TP_PARA_REG2); + if ((val >> S_MAXRXDATA) != 0x3f60) { + val &= (M_RXCOALESCESIZE << S_RXCOALESCESIZE); + val |= V_MAXRXDATA(0x3f60); + printk(KERN_INFO + "%s, iscsi set MaxRxData to 16224 (0x%x).\n", + adapter->name, val); + t3_write_reg(adapter, A_TP_PARA_REG2, val); + } + + /* + * on rx, the iscsi pdu has to be < rx page size and the + * the max rx data length programmed in TP + */ + val = min(adapter->params.tp.rx_pg_size, + ((t3_read_reg(adapter, A_TP_PARA_REG2)) >> + S_MAXRXDATA) & M_MAXRXDATA); + uiip->max_rxsz = min(val, uiip->max_rxsz); + break; + case ULP_ISCSI_SET_PARAMS: + t3_write_reg(adapter, A_ULPRX_ISCSI_TAGMASK, uiip->tagmask); + /* program the ddp page sizes */ + for (i = 0; i < 4; i++) + val |= (uiip->pgsz_factor[i] & 0xF) << (8 * i); + if (val && (val != t3_read_reg(adapter, A_ULPRX_ISCSI_PSZ))) { + printk(KERN_INFO + "%s, setting iscsi pgsz 0x%x, %u,%u,%u,%u.\n", + adapter->name, val, uiip->pgsz_factor[0], + uiip->pgsz_factor[1], uiip->pgsz_factor[2], + uiip->pgsz_factor[3]); + t3_write_reg(adapter, A_ULPRX_ISCSI_PSZ, val); + } + break; + default: + ret = -EOPNOTSUPP; + } + return ret; +} + +/* Response queue used for RDMA events. */ +#define ASYNC_NOTIF_RSPQ 0 + +static int cxgb_rdma_ctl(struct adapter *adapter, unsigned int req, void *data) +{ + int ret = 0; + + switch (req) { + case RDMA_GET_PARAMS: { + struct rdma_info *rdma = data; + struct pci_dev *pdev = adapter->pdev; + + rdma->udbell_physbase = pci_resource_start(pdev, 2); + rdma->udbell_len = pci_resource_len(pdev, 2); + rdma->tpt_base = + t3_read_reg(adapter, A_ULPTX_TPT_LLIMIT); + rdma->tpt_top = t3_read_reg(adapter, A_ULPTX_TPT_ULIMIT); + rdma->pbl_base = + t3_read_reg(adapter, A_ULPTX_PBL_LLIMIT); + rdma->pbl_top = t3_read_reg(adapter, A_ULPTX_PBL_ULIMIT); + rdma->rqt_base = t3_read_reg(adapter, A_ULPRX_RQ_LLIMIT); + rdma->rqt_top = t3_read_reg(adapter, A_ULPRX_RQ_ULIMIT); + rdma->kdb_addr = adapter->regs + A_SG_KDOORBELL; + rdma->pdev = pdev; + break; + } + case RDMA_CQ_OP:{ + unsigned long flags; + struct rdma_cq_op *rdma = data; + + /* may be called in any context */ + spin_lock_irqsave(&adapter->sge.reg_lock, flags); + ret = t3_sge_cqcntxt_op(adapter, rdma->id, rdma->op, + rdma->credits); + spin_unlock_irqrestore(&adapter->sge.reg_lock, flags); + break; + } + case RDMA_GET_MEM:{ + struct ch_mem_range *t = data; + struct mc7 *mem; + + if ((t->addr & 7) || (t->len & 7)) + return -EINVAL; + if (t->mem_id == MEM_CM) + mem = &adapter->cm; + else if (t->mem_id == MEM_PMRX) + mem = &adapter->pmrx; + else if (t->mem_id == MEM_PMTX) + mem = &adapter->pmtx; + else + return -EINVAL; + + ret = + t3_mc7_bd_read(mem, t->addr / 8, t->len / 8, + (u64 *) t->buf); + if (ret) + return ret; + break; + } + case RDMA_CQ_SETUP:{ + struct rdma_cq_setup *rdma = data; + + spin_lock_irq(&adapter->sge.reg_lock); + ret = + t3_sge_init_cqcntxt(adapter, rdma->id, + rdma->base_addr, rdma->size, + ASYNC_NOTIF_RSPQ, + rdma->ovfl_mode, rdma->credits, + rdma->credit_thres); + spin_unlock_irq(&adapter->sge.reg_lock); + break; + } + case RDMA_CQ_DISABLE: + spin_lock_irq(&adapter->sge.reg_lock); + ret = t3_sge_disable_cqcntxt(adapter, *(unsigned int *)data); + spin_unlock_irq(&adapter->sge.reg_lock); + break; + case RDMA_CTRL_QP_SETUP:{ + struct rdma_ctrlqp_setup *rdma = data; + + spin_lock_irq(&adapter->sge.reg_lock); + ret = t3_sge_init_ecntxt(adapter, FW_RI_SGEEC_START, 0, + SGE_CNTXT_RDMA, + ASYNC_NOTIF_RSPQ, + rdma->base_addr, rdma->size, + FW_RI_TID_START, 1, 0); + spin_unlock_irq(&adapter->sge.reg_lock); + break; + } + case RDMA_GET_MIB: { + spin_lock(&adapter->stats_lock); + t3_tp_get_mib_stats(adapter, (struct tp_mib_stats *)data); + spin_unlock(&adapter->stats_lock); + break; + } + default: + ret = -EOPNOTSUPP; + } + return ret; +} + +static int cxgb_offload_ctl(struct t3cdev *tdev, unsigned int req, void *data) +{ + struct adapter *adapter = tdev2adap(tdev); + struct tid_range *tid; + struct mtutab *mtup; + struct iff_mac *iffmacp; + struct ddp_params *ddpp; + struct adap_ports *ports; + struct ofld_page_info *rx_page_info; + struct tp_params *tp = &adapter->params.tp; + int i; + + switch (req) { + case GET_MAX_OUTSTANDING_WR: + *(unsigned int *)data = FW_WR_NUM; + break; + case GET_WR_LEN: + *(unsigned int *)data = WR_FLITS; + break; + case GET_TX_MAX_CHUNK: + *(unsigned int *)data = 1 << 20; /* 1MB */ + break; + case GET_TID_RANGE: + tid = data; + tid->num = t3_mc5_size(&adapter->mc5) - + adapter->params.mc5.nroutes - + adapter->params.mc5.nfilters - adapter->params.mc5.nservers; + tid->base = 0; + break; + case GET_STID_RANGE: + tid = data; + tid->num = adapter->params.mc5.nservers; + tid->base = t3_mc5_size(&adapter->mc5) - tid->num - + adapter->params.mc5.nfilters - adapter->params.mc5.nroutes; + break; + case GET_L2T_CAPACITY: + *(unsigned int *)data = 2048; + break; + case GET_MTUS: + mtup = data; + mtup->size = NMTUS; + mtup->mtus = adapter->params.mtus; + break; + case GET_IFF_FROM_MAC: + iffmacp = data; + iffmacp->dev = get_iff_from_mac(adapter, iffmacp->mac_addr, + iffmacp->vlan_tag & + VLAN_VID_MASK); + break; + case GET_DDP_PARAMS: + ddpp = data; + ddpp->llimit = t3_read_reg(adapter, A_ULPRX_TDDP_LLIMIT); + ddpp->ulimit = t3_read_reg(adapter, A_ULPRX_TDDP_ULIMIT); + ddpp->tag_mask = t3_read_reg(adapter, A_ULPRX_TDDP_TAGMASK); + break; + case GET_PORTS: + ports = data; + ports->nports = adapter->params.nports; + for_each_port(adapter, i) + ports->lldevs[i] = adapter->port[i]; + break; + case ULP_ISCSI_GET_PARAMS: + case ULP_ISCSI_SET_PARAMS: + if (!offload_running(adapter)) + return -EAGAIN; + return cxgb_ulp_iscsi_ctl(adapter, req, data); + case RDMA_GET_PARAMS: + case RDMA_CQ_OP: + case RDMA_CQ_SETUP: + case RDMA_CQ_DISABLE: + case RDMA_CTRL_QP_SETUP: + case RDMA_GET_MEM: + case RDMA_GET_MIB: + if (!offload_running(adapter)) + return -EAGAIN; + return cxgb_rdma_ctl(adapter, req, data); + case GET_RX_PAGE_INFO: + rx_page_info = data; + rx_page_info->page_size = tp->rx_pg_size; + rx_page_info->num = tp->rx_num_pgs; + break; + case GET_ISCSI_IPV4ADDR: { + struct iscsi_ipv4addr *p = data; + struct port_info *pi = netdev_priv(p->dev); + p->ipv4addr = pi->iscsi_ipv4addr; + break; + } + case GET_EMBEDDED_INFO: { + struct ch_embedded_info *e = data; + + spin_lock(&adapter->stats_lock); + t3_get_fw_version(adapter, &e->fw_vers); + t3_get_tp_version(adapter, &e->tp_vers); + spin_unlock(&adapter->stats_lock); + break; + } + default: + return -EOPNOTSUPP; + } + return 0; +} + +/* + * Dummy handler for Rx offload packets in case we get an offload packet before + * proper processing is setup. This complains and drops the packet as it isn't + * normal to get offload packets at this stage. + */ +static int rx_offload_blackhole(struct t3cdev *dev, struct sk_buff **skbs, + int n) +{ + while (n--) + dev_kfree_skb_any(skbs[n]); + return 0; +} + +static void dummy_neigh_update(struct t3cdev *dev, struct neighbour *neigh) +{ +} + +void cxgb3_set_dummy_ops(struct t3cdev *dev) +{ + dev->recv = rx_offload_blackhole; + dev->neigh_update = dummy_neigh_update; +} + +/* + * Free an active-open TID. + */ +void *cxgb3_free_atid(struct t3cdev *tdev, int atid) +{ + struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; + union active_open_entry *p = atid2entry(t, atid); + void *ctx = p->t3c_tid.ctx; + + spin_lock_bh(&t->atid_lock); + p->next = t->afree; + t->afree = p; + t->atids_in_use--; + spin_unlock_bh(&t->atid_lock); + + return ctx; +} + +EXPORT_SYMBOL(cxgb3_free_atid); + +/* + * Free a server TID and return it to the free pool. + */ +void cxgb3_free_stid(struct t3cdev *tdev, int stid) +{ + struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; + union listen_entry *p = stid2entry(t, stid); + + spin_lock_bh(&t->stid_lock); + p->next = t->sfree; + t->sfree = p; + t->stids_in_use--; + spin_unlock_bh(&t->stid_lock); +} + +EXPORT_SYMBOL(cxgb3_free_stid); + +void cxgb3_insert_tid(struct t3cdev *tdev, struct cxgb3_client *client, + void *ctx, unsigned int tid) +{ + struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; + + t->tid_tab[tid].client = client; + t->tid_tab[tid].ctx = ctx; + atomic_inc(&t->tids_in_use); +} + +EXPORT_SYMBOL(cxgb3_insert_tid); + +/* + * Populate a TID_RELEASE WR. The skb must be already propely sized. + */ +static inline void mk_tid_release(struct sk_buff *skb, unsigned int tid) +{ + struct cpl_tid_release *req; + + skb->priority = CPL_PRIORITY_SETUP; + req = (struct cpl_tid_release *)__skb_put(skb, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, tid)); +} + +static void t3_process_tid_release_list(struct work_struct *work) +{ + struct t3c_data *td = container_of(work, struct t3c_data, + tid_release_task); + struct sk_buff *skb; + struct t3cdev *tdev = td->dev; + + + spin_lock_bh(&td->tid_release_lock); + while (td->tid_release_list) { + struct t3c_tid_entry *p = td->tid_release_list; + + td->tid_release_list = p->ctx; + spin_unlock_bh(&td->tid_release_lock); + + skb = alloc_skb(sizeof(struct cpl_tid_release), + GFP_KERNEL); + if (!skb) + skb = td->nofail_skb; + if (!skb) { + spin_lock_bh(&td->tid_release_lock); + p->ctx = (void *)td->tid_release_list; + td->tid_release_list = (struct t3c_tid_entry *)p; + break; + } + mk_tid_release(skb, p - td->tid_maps.tid_tab); + cxgb3_ofld_send(tdev, skb); + p->ctx = NULL; + if (skb == td->nofail_skb) + td->nofail_skb = + alloc_skb(sizeof(struct cpl_tid_release), + GFP_KERNEL); + spin_lock_bh(&td->tid_release_lock); + } + td->release_list_incomplete = (td->tid_release_list == NULL) ? 0 : 1; + spin_unlock_bh(&td->tid_release_lock); + + if (!td->nofail_skb) + td->nofail_skb = + alloc_skb(sizeof(struct cpl_tid_release), + GFP_KERNEL); +} + +/* use ctx as a next pointer in the tid release list */ +void cxgb3_queue_tid_release(struct t3cdev *tdev, unsigned int tid) +{ + struct t3c_data *td = T3C_DATA(tdev); + struct t3c_tid_entry *p = &td->tid_maps.tid_tab[tid]; + + spin_lock_bh(&td->tid_release_lock); + p->ctx = (void *)td->tid_release_list; + p->client = NULL; + td->tid_release_list = p; + if (!p->ctx || td->release_list_incomplete) + schedule_work(&td->tid_release_task); + spin_unlock_bh(&td->tid_release_lock); +} + +EXPORT_SYMBOL(cxgb3_queue_tid_release); + +/* + * Remove a tid from the TID table. A client may defer processing its last + * CPL message if it is locked at the time it arrives, and while the message + * sits in the client's backlog the TID may be reused for another connection. + * To handle this we atomically switch the TID association if it still points + * to the original client context. + */ +void cxgb3_remove_tid(struct t3cdev *tdev, void *ctx, unsigned int tid) +{ + struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; + + BUG_ON(tid >= t->ntids); + if (tdev->type == T3A) + (void)cmpxchg(&t->tid_tab[tid].ctx, ctx, NULL); + else { + struct sk_buff *skb; + + skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_ATOMIC); + if (likely(skb)) { + mk_tid_release(skb, tid); + cxgb3_ofld_send(tdev, skb); + t->tid_tab[tid].ctx = NULL; + } else + cxgb3_queue_tid_release(tdev, tid); + } + atomic_dec(&t->tids_in_use); +} + +EXPORT_SYMBOL(cxgb3_remove_tid); + +int cxgb3_alloc_atid(struct t3cdev *tdev, struct cxgb3_client *client, + void *ctx) +{ + int atid = -1; + struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; + + spin_lock_bh(&t->atid_lock); + if (t->afree && + t->atids_in_use + atomic_read(&t->tids_in_use) + MC5_MIN_TIDS <= + t->ntids) { + union active_open_entry *p = t->afree; + + atid = (p - t->atid_tab) + t->atid_base; + t->afree = p->next; + p->t3c_tid.ctx = ctx; + p->t3c_tid.client = client; + t->atids_in_use++; + } + spin_unlock_bh(&t->atid_lock); + return atid; +} + +EXPORT_SYMBOL(cxgb3_alloc_atid); + +int cxgb3_alloc_stid(struct t3cdev *tdev, struct cxgb3_client *client, + void *ctx) +{ + int stid = -1; + struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; + + spin_lock_bh(&t->stid_lock); + if (t->sfree) { + union listen_entry *p = t->sfree; + + stid = (p - t->stid_tab) + t->stid_base; + t->sfree = p->next; + p->t3c_tid.ctx = ctx; + p->t3c_tid.client = client; + t->stids_in_use++; + } + spin_unlock_bh(&t->stid_lock); + return stid; +} + +EXPORT_SYMBOL(cxgb3_alloc_stid); + +/* Get the t3cdev associated with a net_device */ +struct t3cdev *dev2t3cdev(struct net_device *dev) +{ + const struct port_info *pi = netdev_priv(dev); + + return (struct t3cdev *)pi->adapter; +} + +EXPORT_SYMBOL(dev2t3cdev); + +static int do_smt_write_rpl(struct t3cdev *dev, struct sk_buff *skb) +{ + struct cpl_smt_write_rpl *rpl = cplhdr(skb); + + if (rpl->status != CPL_ERR_NONE) + printk(KERN_ERR + "Unexpected SMT_WRITE_RPL status %u for entry %u\n", + rpl->status, GET_TID(rpl)); + + return CPL_RET_BUF_DONE; +} + +static int do_l2t_write_rpl(struct t3cdev *dev, struct sk_buff *skb) +{ + struct cpl_l2t_write_rpl *rpl = cplhdr(skb); + + if (rpl->status != CPL_ERR_NONE) + printk(KERN_ERR + "Unexpected L2T_WRITE_RPL status %u for entry %u\n", + rpl->status, GET_TID(rpl)); + + return CPL_RET_BUF_DONE; +} + +static int do_rte_write_rpl(struct t3cdev *dev, struct sk_buff *skb) +{ + struct cpl_rte_write_rpl *rpl = cplhdr(skb); + + if (rpl->status != CPL_ERR_NONE) + printk(KERN_ERR + "Unexpected RTE_WRITE_RPL status %u for entry %u\n", + rpl->status, GET_TID(rpl)); + + return CPL_RET_BUF_DONE; +} + +static int do_act_open_rpl(struct t3cdev *dev, struct sk_buff *skb) +{ + struct cpl_act_open_rpl *rpl = cplhdr(skb); + unsigned int atid = G_TID(ntohl(rpl->atid)); + struct t3c_tid_entry *t3c_tid; + + t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid); + if (t3c_tid && t3c_tid->ctx && t3c_tid->client && + t3c_tid->client->handlers && + t3c_tid->client->handlers[CPL_ACT_OPEN_RPL]) { + return t3c_tid->client->handlers[CPL_ACT_OPEN_RPL] (dev, skb, + t3c_tid-> + ctx); + } else { + printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", + dev->name, CPL_ACT_OPEN_RPL); + return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; + } +} + +static int do_stid_rpl(struct t3cdev *dev, struct sk_buff *skb) +{ + union opcode_tid *p = cplhdr(skb); + unsigned int stid = G_TID(ntohl(p->opcode_tid)); + struct t3c_tid_entry *t3c_tid; + + t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid); + if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && + t3c_tid->client->handlers[p->opcode]) { + return t3c_tid->client->handlers[p->opcode] (dev, skb, + t3c_tid->ctx); + } else { + printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", + dev->name, p->opcode); + return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; + } +} + +static int do_hwtid_rpl(struct t3cdev *dev, struct sk_buff *skb) +{ + union opcode_tid *p = cplhdr(skb); + unsigned int hwtid = G_TID(ntohl(p->opcode_tid)); + struct t3c_tid_entry *t3c_tid; + + t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid); + if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && + t3c_tid->client->handlers[p->opcode]) { + return t3c_tid->client->handlers[p->opcode] + (dev, skb, t3c_tid->ctx); + } else { + printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", + dev->name, p->opcode); + return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; + } +} + +static int do_cr(struct t3cdev *dev, struct sk_buff *skb) +{ + struct cpl_pass_accept_req *req = cplhdr(skb); + unsigned int stid = G_PASS_OPEN_TID(ntohl(req->tos_tid)); + struct tid_info *t = &(T3C_DATA(dev))->tid_maps; + struct t3c_tid_entry *t3c_tid; + unsigned int tid = GET_TID(req); + + if (unlikely(tid >= t->ntids)) { + printk("%s: passive open TID %u too large\n", + dev->name, tid); + t3_fatal_err(tdev2adap(dev)); + return CPL_RET_BUF_DONE; + } + + t3c_tid = lookup_stid(t, stid); + if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && + t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]) { + return t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ] + (dev, skb, t3c_tid->ctx); + } else { + printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", + dev->name, CPL_PASS_ACCEPT_REQ); + return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; + } +} + +/* + * Returns an sk_buff for a reply CPL message of size len. If the input + * sk_buff has no other users it is trimmed and reused, otherwise a new buffer + * is allocated. The input skb must be of size at least len. Note that this + * operation does not destroy the original skb data even if it decides to reuse + * the buffer. + */ +static struct sk_buff *cxgb3_get_cpl_reply_skb(struct sk_buff *skb, size_t len, + gfp_t gfp) +{ + if (likely(!skb_cloned(skb))) { + BUG_ON(skb->len < len); + __skb_trim(skb, len); + skb_get(skb); + } else { + skb = alloc_skb(len, gfp); + if (skb) + __skb_put(skb, len); + } + return skb; +} + +static int do_abort_req_rss(struct t3cdev *dev, struct sk_buff *skb) +{ + union opcode_tid *p = cplhdr(skb); + unsigned int hwtid = G_TID(ntohl(p->opcode_tid)); + struct t3c_tid_entry *t3c_tid; + + t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid); + if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && + t3c_tid->client->handlers[p->opcode]) { + return t3c_tid->client->handlers[p->opcode] + (dev, skb, t3c_tid->ctx); + } else { + struct cpl_abort_req_rss *req = cplhdr(skb); + struct cpl_abort_rpl *rpl; + struct sk_buff *reply_skb; + unsigned int tid = GET_TID(req); + u8 cmd = req->status; + + if (req->status == CPL_ERR_RTX_NEG_ADVICE || + req->status == CPL_ERR_PERSIST_NEG_ADVICE) + goto out; + + reply_skb = cxgb3_get_cpl_reply_skb(skb, + sizeof(struct + cpl_abort_rpl), + GFP_ATOMIC); + + if (!reply_skb) { + printk("do_abort_req_rss: couldn't get skb!\n"); + goto out; + } + reply_skb->priority = CPL_PRIORITY_DATA; + __skb_put(reply_skb, sizeof(struct cpl_abort_rpl)); + rpl = cplhdr(reply_skb); + rpl->wr.wr_hi = + htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL)); + rpl->wr.wr_lo = htonl(V_WR_TID(tid)); + OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, tid)); + rpl->cmd = cmd; + cxgb3_ofld_send(dev, reply_skb); +out: + return CPL_RET_BUF_DONE; + } +} + +static int do_act_establish(struct t3cdev *dev, struct sk_buff *skb) +{ + struct cpl_act_establish *req = cplhdr(skb); + unsigned int atid = G_PASS_OPEN_TID(ntohl(req->tos_tid)); + struct tid_info *t = &(T3C_DATA(dev))->tid_maps; + struct t3c_tid_entry *t3c_tid; + unsigned int tid = GET_TID(req); + + if (unlikely(tid >= t->ntids)) { + printk("%s: active establish TID %u too large\n", + dev->name, tid); + t3_fatal_err(tdev2adap(dev)); + return CPL_RET_BUF_DONE; + } + + t3c_tid = lookup_atid(t, atid); + if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && + t3c_tid->client->handlers[CPL_ACT_ESTABLISH]) { + return t3c_tid->client->handlers[CPL_ACT_ESTABLISH] + (dev, skb, t3c_tid->ctx); + } else { + printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", + dev->name, CPL_ACT_ESTABLISH); + return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; + } +} + +static int do_trace(struct t3cdev *dev, struct sk_buff *skb) +{ + struct cpl_trace_pkt *p = cplhdr(skb); + + skb->protocol = htons(0xffff); + skb->dev = dev->lldev; + skb_pull(skb, sizeof(*p)); + skb_reset_mac_header(skb); + netif_receive_skb(skb); + return 0; +} + +/* + * That skb would better have come from process_responses() where we abuse + * ->priority and ->csum to carry our data. NB: if we get to per-arch + * ->csum, the things might get really interesting here. + */ + +static inline u32 get_hwtid(struct sk_buff *skb) +{ + return ntohl((__force __be32)skb->priority) >> 8 & 0xfffff; +} + +static inline u32 get_opcode(struct sk_buff *skb) +{ + return G_OPCODE(ntohl((__force __be32)skb->csum)); +} + +static int do_term(struct t3cdev *dev, struct sk_buff *skb) +{ + unsigned int hwtid = get_hwtid(skb); + unsigned int opcode = get_opcode(skb); + struct t3c_tid_entry *t3c_tid; + + t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid); + if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && + t3c_tid->client->handlers[opcode]) { + return t3c_tid->client->handlers[opcode] (dev, skb, + t3c_tid->ctx); + } else { + printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", + dev->name, opcode); + return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; + } +} + +static int nb_callback(struct notifier_block *self, unsigned long event, + void *ctx) +{ + switch (event) { + case (NETEVENT_NEIGH_UPDATE):{ + cxgb_neigh_update((struct neighbour *)ctx); + break; + } + case (NETEVENT_REDIRECT):{ + struct netevent_redirect *nr = ctx; + cxgb_redirect(nr->old, nr->new); + cxgb_neigh_update(dst_get_neighbour(nr->new)); + break; + } + default: + break; + } + return 0; +} + +static struct notifier_block nb = { + .notifier_call = nb_callback +}; + +/* + * Process a received packet with an unknown/unexpected CPL opcode. + */ +static int do_bad_cpl(struct t3cdev *dev, struct sk_buff *skb) +{ + printk(KERN_ERR "%s: received bad CPL command 0x%x\n", dev->name, + *skb->data); + return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; +} + +/* + * Handlers for each CPL opcode + */ +static cpl_handler_func cpl_handlers[NUM_CPL_CMDS]; + +/* + * Add a new handler to the CPL dispatch table. A NULL handler may be supplied + * to unregister an existing handler. + */ +void t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h) +{ + if (opcode < NUM_CPL_CMDS) + cpl_handlers[opcode] = h ? h : do_bad_cpl; + else + printk(KERN_ERR "T3C: handler registration for " + "opcode %x failed\n", opcode); +} + +EXPORT_SYMBOL(t3_register_cpl_handler); + +/* + * T3CDEV's receive method. + */ +static int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n) +{ + while (n--) { + struct sk_buff *skb = *skbs++; + unsigned int opcode = get_opcode(skb); + int ret = cpl_handlers[opcode] (dev, skb); + +#if VALIDATE_TID + if (ret & CPL_RET_UNKNOWN_TID) { + union opcode_tid *p = cplhdr(skb); + + printk(KERN_ERR "%s: CPL message (opcode %u) had " + "unknown TID %u\n", dev->name, opcode, + G_TID(ntohl(p->opcode_tid))); + } +#endif + if (ret & CPL_RET_BUF_DONE) + kfree_skb(skb); + } + return 0; +} + +/* + * Sends an sk_buff to a T3C driver after dealing with any active network taps. + */ +int cxgb3_ofld_send(struct t3cdev *dev, struct sk_buff *skb) +{ + int r; + + local_bh_disable(); + r = dev->send(dev, skb); + local_bh_enable(); + return r; +} + +EXPORT_SYMBOL(cxgb3_ofld_send); + +static int is_offloading(struct net_device *dev) +{ + struct adapter *adapter; + int i; + + read_lock_bh(&adapter_list_lock); + list_for_each_entry(adapter, &adapter_list, adapter_list) { + for_each_port(adapter, i) { + if (dev == adapter->port[i]) { + read_unlock_bh(&adapter_list_lock); + return 1; + } + } + } + read_unlock_bh(&adapter_list_lock); + return 0; +} + +static void cxgb_neigh_update(struct neighbour *neigh) +{ + struct net_device *dev = neigh->dev; + + if (dev && (is_offloading(dev))) { + struct t3cdev *tdev = dev2t3cdev(dev); + + BUG_ON(!tdev); + t3_l2t_update(tdev, neigh); + } +} + +static void set_l2t_ix(struct t3cdev *tdev, u32 tid, struct l2t_entry *e) +{ + struct sk_buff *skb; + struct cpl_set_tcb_field *req; + + skb = alloc_skb(sizeof(*req), GFP_ATOMIC); + if (!skb) { + printk(KERN_ERR "%s: cannot allocate skb!\n", __func__); + return; + } + skb->priority = CPL_PRIORITY_CONTROL; + req = (struct cpl_set_tcb_field *)skb_put(skb, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid)); + req->reply = 0; + req->cpu_idx = 0; + req->word = htons(W_TCB_L2T_IX); + req->mask = cpu_to_be64(V_TCB_L2T_IX(M_TCB_L2T_IX)); + req->val = cpu_to_be64(V_TCB_L2T_IX(e->idx)); + tdev->send(tdev, skb); +} + +static void cxgb_redirect(struct dst_entry *old, struct dst_entry *new) +{ + struct net_device *olddev, *newdev; + struct tid_info *ti; + struct t3cdev *tdev; + u32 tid; + int update_tcb; + struct l2t_entry *e; + struct t3c_tid_entry *te; + + olddev = dst_get_neighbour(old)->dev; + newdev = dst_get_neighbour(new)->dev; + if (!is_offloading(olddev)) + return; + if (!is_offloading(newdev)) { + printk(KERN_WARNING "%s: Redirect to non-offload " + "device ignored.\n", __func__); + return; + } + tdev = dev2t3cdev(olddev); + BUG_ON(!tdev); + if (tdev != dev2t3cdev(newdev)) { + printk(KERN_WARNING "%s: Redirect to different " + "offload device ignored.\n", __func__); + return; + } + + /* Add new L2T entry */ + e = t3_l2t_get(tdev, dst_get_neighbour(new), newdev); + if (!e) { + printk(KERN_ERR "%s: couldn't allocate new l2t entry!\n", + __func__); + return; + } + + /* Walk tid table and notify clients of dst change. */ + ti = &(T3C_DATA(tdev))->tid_maps; + for (tid = 0; tid < ti->ntids; tid++) { + te = lookup_tid(ti, tid); + BUG_ON(!te); + if (te && te->ctx && te->client && te->client->redirect) { + update_tcb = te->client->redirect(te->ctx, old, new, e); + if (update_tcb) { + l2t_hold(L2DATA(tdev), e); + set_l2t_ix(tdev, tid, e); + } + } + } + l2t_release(L2DATA(tdev), e); +} + +/* + * Allocate a chunk of memory using kmalloc or, if that fails, vmalloc. + * The allocated memory is cleared. + */ +void *cxgb_alloc_mem(unsigned long size) +{ + void *p = kzalloc(size, GFP_KERNEL); + + if (!p) + p = vzalloc(size); + return p; +} + +/* + * Free memory allocated through t3_alloc_mem(). + */ +void cxgb_free_mem(void *addr) +{ + if (is_vmalloc_addr(addr)) + vfree(addr); + else + kfree(addr); +} + +/* + * Allocate and initialize the TID tables. Returns 0 on success. + */ +static int init_tid_tabs(struct tid_info *t, unsigned int ntids, + unsigned int natids, unsigned int nstids, + unsigned int atid_base, unsigned int stid_base) +{ + unsigned long size = ntids * sizeof(*t->tid_tab) + + natids * sizeof(*t->atid_tab) + nstids * sizeof(*t->stid_tab); + + t->tid_tab = cxgb_alloc_mem(size); + if (!t->tid_tab) + return -ENOMEM; + + t->stid_tab = (union listen_entry *)&t->tid_tab[ntids]; + t->atid_tab = (union active_open_entry *)&t->stid_tab[nstids]; + t->ntids = ntids; + t->nstids = nstids; + t->stid_base = stid_base; + t->sfree = NULL; + t->natids = natids; + t->atid_base = atid_base; + t->afree = NULL; + t->stids_in_use = t->atids_in_use = 0; + atomic_set(&t->tids_in_use, 0); + spin_lock_init(&t->stid_lock); + spin_lock_init(&t->atid_lock); + + /* + * Setup the free lists for stid_tab and atid_tab. + */ + if (nstids) { + while (--nstids) + t->stid_tab[nstids - 1].next = &t->stid_tab[nstids]; + t->sfree = t->stid_tab; + } + if (natids) { + while (--natids) + t->atid_tab[natids - 1].next = &t->atid_tab[natids]; + t->afree = t->atid_tab; + } + return 0; +} + +static void free_tid_maps(struct tid_info *t) +{ + cxgb_free_mem(t->tid_tab); +} + +static inline void add_adapter(struct adapter *adap) +{ + write_lock_bh(&adapter_list_lock); + list_add_tail(&adap->adapter_list, &adapter_list); + write_unlock_bh(&adapter_list_lock); +} + +static inline void remove_adapter(struct adapter *adap) +{ + write_lock_bh(&adapter_list_lock); + list_del(&adap->adapter_list); + write_unlock_bh(&adapter_list_lock); +} + +int cxgb3_offload_activate(struct adapter *adapter) +{ + struct t3cdev *dev = &adapter->tdev; + int natids, err; + struct t3c_data *t; + struct tid_range stid_range, tid_range; + struct mtutab mtutab; + unsigned int l2t_capacity; + + t = kzalloc(sizeof(*t), GFP_KERNEL); + if (!t) + return -ENOMEM; + + err = -EOPNOTSUPP; + if (dev->ctl(dev, GET_TX_MAX_CHUNK, &t->tx_max_chunk) < 0 || + dev->ctl(dev, GET_MAX_OUTSTANDING_WR, &t->max_wrs) < 0 || + dev->ctl(dev, GET_L2T_CAPACITY, &l2t_capacity) < 0 || + dev->ctl(dev, GET_MTUS, &mtutab) < 0 || + dev->ctl(dev, GET_TID_RANGE, &tid_range) < 0 || + dev->ctl(dev, GET_STID_RANGE, &stid_range) < 0) + goto out_free; + + err = -ENOMEM; + L2DATA(dev) = t3_init_l2t(l2t_capacity); + if (!L2DATA(dev)) + goto out_free; + + natids = min(tid_range.num / 2, MAX_ATIDS); + err = init_tid_tabs(&t->tid_maps, tid_range.num, natids, + stid_range.num, ATID_BASE, stid_range.base); + if (err) + goto out_free_l2t; + + t->mtus = mtutab.mtus; + t->nmtus = mtutab.size; + + INIT_WORK(&t->tid_release_task, t3_process_tid_release_list); + spin_lock_init(&t->tid_release_lock); + INIT_LIST_HEAD(&t->list_node); + t->dev = dev; + + T3C_DATA(dev) = t; + dev->recv = process_rx; + dev->neigh_update = t3_l2t_update; + + /* Register netevent handler once */ + if (list_empty(&adapter_list)) + register_netevent_notifier(&nb); + + t->nofail_skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_KERNEL); + t->release_list_incomplete = 0; + + add_adapter(adapter); + return 0; + +out_free_l2t: + t3_free_l2t(L2DATA(dev)); + L2DATA(dev) = NULL; +out_free: + kfree(t); + return err; +} + +void cxgb3_offload_deactivate(struct adapter *adapter) +{ + struct t3cdev *tdev = &adapter->tdev; + struct t3c_data *t = T3C_DATA(tdev); + + remove_adapter(adapter); + if (list_empty(&adapter_list)) + unregister_netevent_notifier(&nb); + + free_tid_maps(&t->tid_maps); + T3C_DATA(tdev) = NULL; + t3_free_l2t(L2DATA(tdev)); + L2DATA(tdev) = NULL; + if (t->nofail_skb) + kfree_skb(t->nofail_skb); + kfree(t); +} + +static inline void register_tdev(struct t3cdev *tdev) +{ + static int unit; + + mutex_lock(&cxgb3_db_lock); + snprintf(tdev->name, sizeof(tdev->name), "ofld_dev%d", unit++); + list_add_tail(&tdev->ofld_dev_list, &ofld_dev_list); + mutex_unlock(&cxgb3_db_lock); +} + +static inline void unregister_tdev(struct t3cdev *tdev) +{ + mutex_lock(&cxgb3_db_lock); + list_del(&tdev->ofld_dev_list); + mutex_unlock(&cxgb3_db_lock); +} + +static inline int adap2type(struct adapter *adapter) +{ + int type = 0; + + switch (adapter->params.rev) { + case T3_REV_A: + type = T3A; + break; + case T3_REV_B: + case T3_REV_B2: + type = T3B; + break; + case T3_REV_C: + type = T3C; + break; + } + return type; +} + +void __devinit cxgb3_adapter_ofld(struct adapter *adapter) +{ + struct t3cdev *tdev = &adapter->tdev; + + INIT_LIST_HEAD(&tdev->ofld_dev_list); + + cxgb3_set_dummy_ops(tdev); + tdev->send = t3_offload_tx; + tdev->ctl = cxgb_offload_ctl; + tdev->type = adap2type(adapter); + + register_tdev(tdev); +} + +void __devexit cxgb3_adapter_unofld(struct adapter *adapter) +{ + struct t3cdev *tdev = &adapter->tdev; + + tdev->recv = NULL; + tdev->neigh_update = NULL; + + unregister_tdev(tdev); +} + +void __init cxgb3_offload_init(void) +{ + int i; + + for (i = 0; i < NUM_CPL_CMDS; ++i) + cpl_handlers[i] = do_bad_cpl; + + t3_register_cpl_handler(CPL_SMT_WRITE_RPL, do_smt_write_rpl); + t3_register_cpl_handler(CPL_L2T_WRITE_RPL, do_l2t_write_rpl); + t3_register_cpl_handler(CPL_RTE_WRITE_RPL, do_rte_write_rpl); + t3_register_cpl_handler(CPL_PASS_OPEN_RPL, do_stid_rpl); + t3_register_cpl_handler(CPL_CLOSE_LISTSRV_RPL, do_stid_rpl); + t3_register_cpl_handler(CPL_PASS_ACCEPT_REQ, do_cr); + t3_register_cpl_handler(CPL_PASS_ESTABLISH, do_hwtid_rpl); + t3_register_cpl_handler(CPL_ABORT_RPL_RSS, do_hwtid_rpl); + t3_register_cpl_handler(CPL_ABORT_RPL, do_hwtid_rpl); + t3_register_cpl_handler(CPL_RX_URG_NOTIFY, do_hwtid_rpl); + t3_register_cpl_handler(CPL_RX_DATA, do_hwtid_rpl); + t3_register_cpl_handler(CPL_TX_DATA_ACK, do_hwtid_rpl); + t3_register_cpl_handler(CPL_TX_DMA_ACK, do_hwtid_rpl); + t3_register_cpl_handler(CPL_ACT_OPEN_RPL, do_act_open_rpl); + t3_register_cpl_handler(CPL_PEER_CLOSE, do_hwtid_rpl); + t3_register_cpl_handler(CPL_CLOSE_CON_RPL, do_hwtid_rpl); + t3_register_cpl_handler(CPL_ABORT_REQ_RSS, do_abort_req_rss); + t3_register_cpl_handler(CPL_ACT_ESTABLISH, do_act_establish); + t3_register_cpl_handler(CPL_SET_TCB_RPL, do_hwtid_rpl); + t3_register_cpl_handler(CPL_GET_TCB_RPL, do_hwtid_rpl); + t3_register_cpl_handler(CPL_RDMA_TERMINATE, do_term); + t3_register_cpl_handler(CPL_RDMA_EC_STATUS, do_hwtid_rpl); + t3_register_cpl_handler(CPL_TRACE_PKT, do_trace); + t3_register_cpl_handler(CPL_RX_DATA_DDP, do_hwtid_rpl); + t3_register_cpl_handler(CPL_RX_DDP_COMPLETE, do_hwtid_rpl); + t3_register_cpl_handler(CPL_ISCSI_HDR, do_hwtid_rpl); +} diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.h b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.h new file mode 100644 index 000000000000..929c298115ca --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.h @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2006-2008 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _CXGB3_OFFLOAD_H +#define _CXGB3_OFFLOAD_H + +#include +#include + +#include "l2t.h" + +#include "t3cdev.h" +#include "t3_cpl.h" + +struct adapter; + +void cxgb3_offload_init(void); + +void cxgb3_adapter_ofld(struct adapter *adapter); +void cxgb3_adapter_unofld(struct adapter *adapter); +int cxgb3_offload_activate(struct adapter *adapter); +void cxgb3_offload_deactivate(struct adapter *adapter); + +void cxgb3_set_dummy_ops(struct t3cdev *dev); + +struct t3cdev *dev2t3cdev(struct net_device *dev); + +/* + * Client registration. Users of T3 driver must register themselves. + * The T3 driver will call the add function of every client for each T3 + * adapter activated, passing up the t3cdev ptr. Each client fills out an + * array of callback functions to process CPL messages. + */ + +void cxgb3_register_client(struct cxgb3_client *client); +void cxgb3_unregister_client(struct cxgb3_client *client); +void cxgb3_add_clients(struct t3cdev *tdev); +void cxgb3_remove_clients(struct t3cdev *tdev); +void cxgb3_event_notify(struct t3cdev *tdev, u32 event, u32 port); + +typedef int (*cxgb3_cpl_handler_func)(struct t3cdev *dev, + struct sk_buff *skb, void *ctx); + +enum { + OFFLOAD_STATUS_UP, + OFFLOAD_STATUS_DOWN, + OFFLOAD_PORT_DOWN, + OFFLOAD_PORT_UP, + OFFLOAD_DB_FULL, + OFFLOAD_DB_EMPTY, + OFFLOAD_DB_DROP +}; + +struct cxgb3_client { + char *name; + void (*add) (struct t3cdev *); + void (*remove) (struct t3cdev *); + cxgb3_cpl_handler_func *handlers; + int (*redirect)(void *ctx, struct dst_entry *old, + struct dst_entry *new, struct l2t_entry *l2t); + struct list_head client_list; + void (*event_handler)(struct t3cdev *tdev, u32 event, u32 port); +}; + +/* + * TID allocation services. + */ +int cxgb3_alloc_atid(struct t3cdev *dev, struct cxgb3_client *client, + void *ctx); +int cxgb3_alloc_stid(struct t3cdev *dev, struct cxgb3_client *client, + void *ctx); +void *cxgb3_free_atid(struct t3cdev *dev, int atid); +void cxgb3_free_stid(struct t3cdev *dev, int stid); +void cxgb3_insert_tid(struct t3cdev *dev, struct cxgb3_client *client, + void *ctx, unsigned int tid); +void cxgb3_queue_tid_release(struct t3cdev *dev, unsigned int tid); +void cxgb3_remove_tid(struct t3cdev *dev, void *ctx, unsigned int tid); + +struct t3c_tid_entry { + struct cxgb3_client *client; + void *ctx; +}; + +/* CPL message priority levels */ +enum { + CPL_PRIORITY_DATA = 0, /* data messages */ + CPL_PRIORITY_SETUP = 1, /* connection setup messages */ + CPL_PRIORITY_TEARDOWN = 0, /* connection teardown messages */ + CPL_PRIORITY_LISTEN = 1, /* listen start/stop messages */ + CPL_PRIORITY_ACK = 1, /* RX ACK messages */ + CPL_PRIORITY_CONTROL = 1 /* offload control messages */ +}; + +/* Flags for return value of CPL message handlers */ +enum { + CPL_RET_BUF_DONE = 1, /* buffer processing done, buffer may be freed */ + CPL_RET_BAD_MSG = 2, /* bad CPL message (e.g., unknown opcode) */ + CPL_RET_UNKNOWN_TID = 4 /* unexpected unknown TID */ +}; + +typedef int (*cpl_handler_func)(struct t3cdev *dev, struct sk_buff *skb); + +/* + * Returns a pointer to the first byte of the CPL header in an sk_buff that + * contains a CPL message. + */ +static inline void *cplhdr(struct sk_buff *skb) +{ + return skb->data; +} + +void t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h); + +union listen_entry { + struct t3c_tid_entry t3c_tid; + union listen_entry *next; +}; + +union active_open_entry { + struct t3c_tid_entry t3c_tid; + union active_open_entry *next; +}; + +/* + * Holds the size, base address, free list start, etc of the TID, server TID, + * and active-open TID tables for a offload device. + * The tables themselves are allocated dynamically. + */ +struct tid_info { + struct t3c_tid_entry *tid_tab; + unsigned int ntids; + atomic_t tids_in_use; + + union listen_entry *stid_tab; + unsigned int nstids; + unsigned int stid_base; + + union active_open_entry *atid_tab; + unsigned int natids; + unsigned int atid_base; + + /* + * The following members are accessed R/W so we put them in their own + * cache lines. + * + * XXX We could combine the atid fields above with the lock here since + * atids are use once (unlike other tids). OTOH the above fields are + * usually in cache due to tid_tab. + */ + spinlock_t atid_lock ____cacheline_aligned_in_smp; + union active_open_entry *afree; + unsigned int atids_in_use; + + spinlock_t stid_lock ____cacheline_aligned; + union listen_entry *sfree; + unsigned int stids_in_use; +}; + +struct t3c_data { + struct list_head list_node; + struct t3cdev *dev; + unsigned int tx_max_chunk; /* max payload for TX_DATA */ + unsigned int max_wrs; /* max in-flight WRs per connection */ + unsigned int nmtus; + const unsigned short *mtus; + struct tid_info tid_maps; + + struct t3c_tid_entry *tid_release_list; + spinlock_t tid_release_lock; + struct work_struct tid_release_task; + + struct sk_buff *nofail_skb; + unsigned int release_list_incomplete; +}; + +/* + * t3cdev -> t3c_data accessor + */ +#define T3C_DATA(dev) (*(struct t3c_data **)&(dev)->l4opt) + +#endif diff --git a/drivers/net/ethernet/chelsio/cxgb3/firmware_exports.h b/drivers/net/ethernet/chelsio/cxgb3/firmware_exports.h new file mode 100644 index 000000000000..0d9b0e6dccff --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb3/firmware_exports.h @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2004-2008 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _FIRMWARE_EXPORTS_H_ +#define _FIRMWARE_EXPORTS_H_ + +/* WR OPCODES supported by the firmware. + */ +#define FW_WROPCODE_FORWARD 0x01 +#define FW_WROPCODE_BYPASS 0x05 + +#define FW_WROPCODE_TUNNEL_TX_PKT 0x03 + +#define FW_WROPOCDE_ULPTX_DATA_SGL 0x00 +#define FW_WROPCODE_ULPTX_MEM_READ 0x02 +#define FW_WROPCODE_ULPTX_PKT 0x04 +#define FW_WROPCODE_ULPTX_INVALIDATE 0x06 + +#define FW_WROPCODE_TUNNEL_RX_PKT 0x07 + +#define FW_WROPCODE_OFLD_GETTCB_RPL 0x08 +#define FW_WROPCODE_OFLD_CLOSE_CON 0x09 +#define FW_WROPCODE_OFLD_TP_ABORT_CON_REQ 0x0A +#define FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL 0x0F +#define FW_WROPCODE_OFLD_HOST_ABORT_CON_REQ 0x0B +#define FW_WROPCODE_OFLD_TP_ABORT_CON_RPL 0x0C +#define FW_WROPCODE_OFLD_TX_DATA 0x0D +#define FW_WROPCODE_OFLD_TX_DATA_ACK 0x0E + +#define FW_WROPCODE_RI_RDMA_INIT 0x10 +#define FW_WROPCODE_RI_RDMA_WRITE 0x11 +#define FW_WROPCODE_RI_RDMA_READ_REQ 0x12 +#define FW_WROPCODE_RI_RDMA_READ_RESP 0x13 +#define FW_WROPCODE_RI_SEND 0x14 +#define FW_WROPCODE_RI_TERMINATE 0x15 +#define FW_WROPCODE_RI_RDMA_READ 0x16 +#define FW_WROPCODE_RI_RECEIVE 0x17 +#define FW_WROPCODE_RI_BIND_MW 0x18 +#define FW_WROPCODE_RI_FASTREGISTER_MR 0x19 +#define FW_WROPCODE_RI_LOCAL_INV 0x1A +#define FW_WROPCODE_RI_MODIFY_QP 0x1B +#define FW_WROPCODE_RI_BYPASS 0x1C + +#define FW_WROPOCDE_RSVD 0x1E + +#define FW_WROPCODE_SGE_EGRESSCONTEXT_RR 0x1F + +#define FW_WROPCODE_MNGT 0x1D +#define FW_MNGTOPCODE_PKTSCHED_SET 0x00 + +/* Maximum size of a WR sent from the host, limited by the SGE. + * + * Note: WR coming from ULP or TP are only limited by CIM. + */ +#define FW_WR_SIZE 128 + +/* Maximum number of outstanding WRs sent from the host. Value must be + * programmed in the CTRL/TUNNEL/QP SGE Egress Context and used by + * offload modules to limit the number of WRs per connection. + */ +#define FW_T3_WR_NUM 16 +#define FW_N3_WR_NUM 7 + +#ifndef N3 +# define FW_WR_NUM FW_T3_WR_NUM +#else +# define FW_WR_NUM FW_N3_WR_NUM +#endif + +/* FW_TUNNEL_NUM corresponds to the number of supported TUNNEL Queues. These + * queues must start at SGE Egress Context FW_TUNNEL_SGEEC_START and must + * start at 'TID' (or 'uP Token') FW_TUNNEL_TID_START. + * + * Ingress Traffic (e.g. DMA completion credit) for TUNNEL Queue[i] is sent + * to RESP Queue[i]. + */ +#define FW_TUNNEL_NUM 8 +#define FW_TUNNEL_SGEEC_START 8 +#define FW_TUNNEL_TID_START 65544 + +/* FW_CTRL_NUM corresponds to the number of supported CTRL Queues. These queues + * must start at SGE Egress Context FW_CTRL_SGEEC_START and must start at 'TID' + * (or 'uP Token') FW_CTRL_TID_START. + * + * Ingress Traffic for CTRL Queue[i] is sent to RESP Queue[i]. + */ +#define FW_CTRL_NUM 8 +#define FW_CTRL_SGEEC_START 65528 +#define FW_CTRL_TID_START 65536 + +/* FW_OFLD_NUM corresponds to the number of supported OFFLOAD Queues. These + * queues must start at SGE Egress Context FW_OFLD_SGEEC_START. + * + * Note: the 'uP Token' in the SGE Egress Context fields is irrelevant for + * OFFLOAD Queues, as the host is responsible for providing the correct TID in + * every WR. + * + * Ingress Trafffic for OFFLOAD Queue[i] is sent to RESP Queue[i]. + */ +#define FW_OFLD_NUM 8 +#define FW_OFLD_SGEEC_START 0 + +/* + * + */ +#define FW_RI_NUM 1 +#define FW_RI_SGEEC_START 65527 +#define FW_RI_TID_START 65552 + +/* + * The RX_PKT_TID + */ +#define FW_RX_PKT_NUM 1 +#define FW_RX_PKT_TID_START 65553 + +/* FW_WRC_NUM corresponds to the number of Work Request Context that supported + * by the firmware. + */ +#define FW_WRC_NUM \ + (65536 + FW_TUNNEL_NUM + FW_CTRL_NUM + FW_RI_NUM + FW_RX_PKT_NUM) + +/* + * FW type and version. + */ +#define S_FW_VERSION_TYPE 28 +#define M_FW_VERSION_TYPE 0xF +#define V_FW_VERSION_TYPE(x) ((x) << S_FW_VERSION_TYPE) +#define G_FW_VERSION_TYPE(x) \ + (((x) >> S_FW_VERSION_TYPE) & M_FW_VERSION_TYPE) + +#define S_FW_VERSION_MAJOR 16 +#define M_FW_VERSION_MAJOR 0xFFF +#define V_FW_VERSION_MAJOR(x) ((x) << S_FW_VERSION_MAJOR) +#define G_FW_VERSION_MAJOR(x) \ + (((x) >> S_FW_VERSION_MAJOR) & M_FW_VERSION_MAJOR) + +#define S_FW_VERSION_MINOR 8 +#define M_FW_VERSION_MINOR 0xFF +#define V_FW_VERSION_MINOR(x) ((x) << S_FW_VERSION_MINOR) +#define G_FW_VERSION_MINOR(x) \ + (((x) >> S_FW_VERSION_MINOR) & M_FW_VERSION_MINOR) + +#define S_FW_VERSION_MICRO 0 +#define M_FW_VERSION_MICRO 0xFF +#define V_FW_VERSION_MICRO(x) ((x) << S_FW_VERSION_MICRO) +#define G_FW_VERSION_MICRO(x) \ + (((x) >> S_FW_VERSION_MICRO) & M_FW_VERSION_MICRO) + +#endif /* _FIRMWARE_EXPORTS_H_ */ diff --git a/drivers/net/ethernet/chelsio/cxgb3/l2t.c b/drivers/net/ethernet/chelsio/cxgb3/l2t.c new file mode 100644 index 000000000000..f452c4003253 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb3/l2t.c @@ -0,0 +1,445 @@ +/* + * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "t3cdev.h" +#include "cxgb3_defs.h" +#include "l2t.h" +#include "t3_cpl.h" +#include "firmware_exports.h" + +#define VLAN_NONE 0xfff + +/* + * Module locking notes: There is a RW lock protecting the L2 table as a + * whole plus a spinlock per L2T entry. Entry lookups and allocations happen + * under the protection of the table lock, individual entry changes happen + * while holding that entry's spinlock. The table lock nests outside the + * entry locks. Allocations of new entries take the table lock as writers so + * no other lookups can happen while allocating new entries. Entry updates + * take the table lock as readers so multiple entries can be updated in + * parallel. An L2T entry can be dropped by decrementing its reference count + * and therefore can happen in parallel with entry allocation but no entry + * can change state or increment its ref count during allocation as both of + * these perform lookups. + */ + +static inline unsigned int vlan_prio(const struct l2t_entry *e) +{ + return e->vlan >> 13; +} + +static inline unsigned int arp_hash(u32 key, int ifindex, + const struct l2t_data *d) +{ + return jhash_2words(key, ifindex, 0) & (d->nentries - 1); +} + +static inline void neigh_replace(struct l2t_entry *e, struct neighbour *n) +{ + neigh_hold(n); + if (e->neigh) + neigh_release(e->neigh); + e->neigh = n; +} + +/* + * Set up an L2T entry and send any packets waiting in the arp queue. The + * supplied skb is used for the CPL_L2T_WRITE_REQ. Must be called with the + * entry locked. + */ +static int setup_l2e_send_pending(struct t3cdev *dev, struct sk_buff *skb, + struct l2t_entry *e) +{ + struct cpl_l2t_write_req *req; + struct sk_buff *tmp; + + if (!skb) { + skb = alloc_skb(sizeof(*req), GFP_ATOMIC); + if (!skb) + return -ENOMEM; + } + + req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, e->idx)); + req->params = htonl(V_L2T_W_IDX(e->idx) | V_L2T_W_IFF(e->smt_idx) | + V_L2T_W_VLAN(e->vlan & VLAN_VID_MASK) | + V_L2T_W_PRIO(vlan_prio(e))); + memcpy(e->dmac, e->neigh->ha, sizeof(e->dmac)); + memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac)); + skb->priority = CPL_PRIORITY_CONTROL; + cxgb3_ofld_send(dev, skb); + + skb_queue_walk_safe(&e->arpq, skb, tmp) { + __skb_unlink(skb, &e->arpq); + cxgb3_ofld_send(dev, skb); + } + e->state = L2T_STATE_VALID; + + return 0; +} + +/* + * Add a packet to the an L2T entry's queue of packets awaiting resolution. + * Must be called with the entry's lock held. + */ +static inline void arpq_enqueue(struct l2t_entry *e, struct sk_buff *skb) +{ + __skb_queue_tail(&e->arpq, skb); +} + +int t3_l2t_send_slow(struct t3cdev *dev, struct sk_buff *skb, + struct l2t_entry *e) +{ +again: + switch (e->state) { + case L2T_STATE_STALE: /* entry is stale, kick off revalidation */ + neigh_event_send(e->neigh, NULL); + spin_lock_bh(&e->lock); + if (e->state == L2T_STATE_STALE) + e->state = L2T_STATE_VALID; + spin_unlock_bh(&e->lock); + case L2T_STATE_VALID: /* fast-path, send the packet on */ + return cxgb3_ofld_send(dev, skb); + case L2T_STATE_RESOLVING: + spin_lock_bh(&e->lock); + if (e->state != L2T_STATE_RESOLVING) { + /* ARP already completed */ + spin_unlock_bh(&e->lock); + goto again; + } + arpq_enqueue(e, skb); + spin_unlock_bh(&e->lock); + + /* + * Only the first packet added to the arpq should kick off + * resolution. However, because the alloc_skb below can fail, + * we allow each packet added to the arpq to retry resolution + * as a way of recovering from transient memory exhaustion. + * A better way would be to use a work request to retry L2T + * entries when there's no memory. + */ + if (!neigh_event_send(e->neigh, NULL)) { + skb = alloc_skb(sizeof(struct cpl_l2t_write_req), + GFP_ATOMIC); + if (!skb) + break; + + spin_lock_bh(&e->lock); + if (!skb_queue_empty(&e->arpq)) + setup_l2e_send_pending(dev, skb, e); + else /* we lost the race */ + __kfree_skb(skb); + spin_unlock_bh(&e->lock); + } + } + return 0; +} + +EXPORT_SYMBOL(t3_l2t_send_slow); + +void t3_l2t_send_event(struct t3cdev *dev, struct l2t_entry *e) +{ +again: + switch (e->state) { + case L2T_STATE_STALE: /* entry is stale, kick off revalidation */ + neigh_event_send(e->neigh, NULL); + spin_lock_bh(&e->lock); + if (e->state == L2T_STATE_STALE) { + e->state = L2T_STATE_VALID; + } + spin_unlock_bh(&e->lock); + return; + case L2T_STATE_VALID: /* fast-path, send the packet on */ + return; + case L2T_STATE_RESOLVING: + spin_lock_bh(&e->lock); + if (e->state != L2T_STATE_RESOLVING) { + /* ARP already completed */ + spin_unlock_bh(&e->lock); + goto again; + } + spin_unlock_bh(&e->lock); + + /* + * Only the first packet added to the arpq should kick off + * resolution. However, because the alloc_skb below can fail, + * we allow each packet added to the arpq to retry resolution + * as a way of recovering from transient memory exhaustion. + * A better way would be to use a work request to retry L2T + * entries when there's no memory. + */ + neigh_event_send(e->neigh, NULL); + } +} + +EXPORT_SYMBOL(t3_l2t_send_event); + +/* + * Allocate a free L2T entry. Must be called with l2t_data.lock held. + */ +static struct l2t_entry *alloc_l2e(struct l2t_data *d) +{ + struct l2t_entry *end, *e, **p; + + if (!atomic_read(&d->nfree)) + return NULL; + + /* there's definitely a free entry */ + for (e = d->rover, end = &d->l2tab[d->nentries]; e != end; ++e) + if (atomic_read(&e->refcnt) == 0) + goto found; + + for (e = &d->l2tab[1]; atomic_read(&e->refcnt); ++e) ; +found: + d->rover = e + 1; + atomic_dec(&d->nfree); + + /* + * The entry we found may be an inactive entry that is + * presently in the hash table. We need to remove it. + */ + if (e->state != L2T_STATE_UNUSED) { + int hash = arp_hash(e->addr, e->ifindex, d); + + for (p = &d->l2tab[hash].first; *p; p = &(*p)->next) + if (*p == e) { + *p = e->next; + break; + } + e->state = L2T_STATE_UNUSED; + } + return e; +} + +/* + * Called when an L2T entry has no more users. The entry is left in the hash + * table since it is likely to be reused but we also bump nfree to indicate + * that the entry can be reallocated for a different neighbor. We also drop + * the existing neighbor reference in case the neighbor is going away and is + * waiting on our reference. + * + * Because entries can be reallocated to other neighbors once their ref count + * drops to 0 we need to take the entry's lock to avoid races with a new + * incarnation. + */ +void t3_l2e_free(struct l2t_data *d, struct l2t_entry *e) +{ + spin_lock_bh(&e->lock); + if (atomic_read(&e->refcnt) == 0) { /* hasn't been recycled */ + if (e->neigh) { + neigh_release(e->neigh); + e->neigh = NULL; + } + } + spin_unlock_bh(&e->lock); + atomic_inc(&d->nfree); +} + +EXPORT_SYMBOL(t3_l2e_free); + +/* + * Update an L2T entry that was previously used for the same next hop as neigh. + * Must be called with softirqs disabled. + */ +static inline void reuse_entry(struct l2t_entry *e, struct neighbour *neigh) +{ + unsigned int nud_state; + + spin_lock(&e->lock); /* avoid race with t3_l2t_free */ + + if (neigh != e->neigh) + neigh_replace(e, neigh); + nud_state = neigh->nud_state; + if (memcmp(e->dmac, neigh->ha, sizeof(e->dmac)) || + !(nud_state & NUD_VALID)) + e->state = L2T_STATE_RESOLVING; + else if (nud_state & NUD_CONNECTED) + e->state = L2T_STATE_VALID; + else + e->state = L2T_STATE_STALE; + spin_unlock(&e->lock); +} + +struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh, + struct net_device *dev) +{ + struct l2t_entry *e; + struct l2t_data *d = L2DATA(cdev); + u32 addr = *(u32 *) neigh->primary_key; + int ifidx = neigh->dev->ifindex; + int hash = arp_hash(addr, ifidx, d); + struct port_info *p = netdev_priv(dev); + int smt_idx = p->port_id; + + write_lock_bh(&d->lock); + for (e = d->l2tab[hash].first; e; e = e->next) + if (e->addr == addr && e->ifindex == ifidx && + e->smt_idx == smt_idx) { + l2t_hold(d, e); + if (atomic_read(&e->refcnt) == 1) + reuse_entry(e, neigh); + goto done; + } + + /* Need to allocate a new entry */ + e = alloc_l2e(d); + if (e) { + spin_lock(&e->lock); /* avoid race with t3_l2t_free */ + e->next = d->l2tab[hash].first; + d->l2tab[hash].first = e; + e->state = L2T_STATE_RESOLVING; + e->addr = addr; + e->ifindex = ifidx; + e->smt_idx = smt_idx; + atomic_set(&e->refcnt, 1); + neigh_replace(e, neigh); + if (neigh->dev->priv_flags & IFF_802_1Q_VLAN) + e->vlan = vlan_dev_vlan_id(neigh->dev); + else + e->vlan = VLAN_NONE; + spin_unlock(&e->lock); + } +done: + write_unlock_bh(&d->lock); + return e; +} + +EXPORT_SYMBOL(t3_l2t_get); + +/* + * Called when address resolution fails for an L2T entry to handle packets + * on the arpq head. If a packet specifies a failure handler it is invoked, + * otherwise the packets is sent to the offload device. + * + * XXX: maybe we should abandon the latter behavior and just require a failure + * handler. + */ +static void handle_failed_resolution(struct t3cdev *dev, struct sk_buff_head *arpq) +{ + struct sk_buff *skb, *tmp; + + skb_queue_walk_safe(arpq, skb, tmp) { + struct l2t_skb_cb *cb = L2T_SKB_CB(skb); + + __skb_unlink(skb, arpq); + if (cb->arp_failure_handler) + cb->arp_failure_handler(dev, skb); + else + cxgb3_ofld_send(dev, skb); + } +} + +/* + * Called when the host's ARP layer makes a change to some entry that is + * loaded into the HW L2 table. + */ +void t3_l2t_update(struct t3cdev *dev, struct neighbour *neigh) +{ + struct sk_buff_head arpq; + struct l2t_entry *e; + struct l2t_data *d = L2DATA(dev); + u32 addr = *(u32 *) neigh->primary_key; + int ifidx = neigh->dev->ifindex; + int hash = arp_hash(addr, ifidx, d); + + read_lock_bh(&d->lock); + for (e = d->l2tab[hash].first; e; e = e->next) + if (e->addr == addr && e->ifindex == ifidx) { + spin_lock(&e->lock); + goto found; + } + read_unlock_bh(&d->lock); + return; + +found: + __skb_queue_head_init(&arpq); + + read_unlock(&d->lock); + if (atomic_read(&e->refcnt)) { + if (neigh != e->neigh) + neigh_replace(e, neigh); + + if (e->state == L2T_STATE_RESOLVING) { + if (neigh->nud_state & NUD_FAILED) { + skb_queue_splice_init(&e->arpq, &arpq); + } else if (neigh->nud_state & (NUD_CONNECTED|NUD_STALE)) + setup_l2e_send_pending(dev, NULL, e); + } else { + e->state = neigh->nud_state & NUD_CONNECTED ? + L2T_STATE_VALID : L2T_STATE_STALE; + if (memcmp(e->dmac, neigh->ha, 6)) + setup_l2e_send_pending(dev, NULL, e); + } + } + spin_unlock_bh(&e->lock); + + if (!skb_queue_empty(&arpq)) + handle_failed_resolution(dev, &arpq); +} + +struct l2t_data *t3_init_l2t(unsigned int l2t_capacity) +{ + struct l2t_data *d; + int i, size = sizeof(*d) + l2t_capacity * sizeof(struct l2t_entry); + + d = cxgb_alloc_mem(size); + if (!d) + return NULL; + + d->nentries = l2t_capacity; + d->rover = &d->l2tab[1]; /* entry 0 is not used */ + atomic_set(&d->nfree, l2t_capacity - 1); + rwlock_init(&d->lock); + + for (i = 0; i < l2t_capacity; ++i) { + d->l2tab[i].idx = i; + d->l2tab[i].state = L2T_STATE_UNUSED; + __skb_queue_head_init(&d->l2tab[i].arpq); + spin_lock_init(&d->l2tab[i].lock); + atomic_set(&d->l2tab[i].refcnt, 0); + } + return d; +} + +void t3_free_l2t(struct l2t_data *d) +{ + cxgb_free_mem(d); +} + diff --git a/drivers/net/ethernet/chelsio/cxgb3/l2t.h b/drivers/net/ethernet/chelsio/cxgb3/l2t.h new file mode 100644 index 000000000000..7a12d52ed4fc --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb3/l2t.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _CHELSIO_L2T_H +#define _CHELSIO_L2T_H + +#include +#include "t3cdev.h" +#include + +enum { + L2T_STATE_VALID, /* entry is up to date */ + L2T_STATE_STALE, /* entry may be used but needs revalidation */ + L2T_STATE_RESOLVING, /* entry needs address resolution */ + L2T_STATE_UNUSED /* entry not in use */ +}; + +struct neighbour; +struct sk_buff; + +/* + * Each L2T entry plays multiple roles. First of all, it keeps state for the + * corresponding entry of the HW L2 table and maintains a queue of offload + * packets awaiting address resolution. Second, it is a node of a hash table + * chain, where the nodes of the chain are linked together through their next + * pointer. Finally, each node is a bucket of a hash table, pointing to the + * first element in its chain through its first pointer. + */ +struct l2t_entry { + u16 state; /* entry state */ + u16 idx; /* entry index */ + u32 addr; /* dest IP address */ + int ifindex; /* neighbor's net_device's ifindex */ + u16 smt_idx; /* SMT index */ + u16 vlan; /* VLAN TCI (id: bits 0-11, prio: 13-15 */ + struct neighbour *neigh; /* associated neighbour */ + struct l2t_entry *first; /* start of hash chain */ + struct l2t_entry *next; /* next l2t_entry on chain */ + struct sk_buff_head arpq; /* queue of packets awaiting resolution */ + spinlock_t lock; + atomic_t refcnt; /* entry reference count */ + u8 dmac[6]; /* neighbour's MAC address */ +}; + +struct l2t_data { + unsigned int nentries; /* number of entries */ + struct l2t_entry *rover; /* starting point for next allocation */ + atomic_t nfree; /* number of free entries */ + rwlock_t lock; + struct l2t_entry l2tab[0]; +}; + +typedef void (*arp_failure_handler_func)(struct t3cdev * dev, + struct sk_buff * skb); + +/* + * Callback stored in an skb to handle address resolution failure. + */ +struct l2t_skb_cb { + arp_failure_handler_func arp_failure_handler; +}; + +#define L2T_SKB_CB(skb) ((struct l2t_skb_cb *)(skb)->cb) + +static inline void set_arp_failure_handler(struct sk_buff *skb, + arp_failure_handler_func hnd) +{ + L2T_SKB_CB(skb)->arp_failure_handler = hnd; +} + +/* + * Getting to the L2 data from an offload device. + */ +#define L2DATA(dev) ((dev)->l2opt) + +#define W_TCB_L2T_IX 0 +#define S_TCB_L2T_IX 7 +#define M_TCB_L2T_IX 0x7ffULL +#define V_TCB_L2T_IX(x) ((x) << S_TCB_L2T_IX) + +void t3_l2e_free(struct l2t_data *d, struct l2t_entry *e); +void t3_l2t_update(struct t3cdev *dev, struct neighbour *neigh); +struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh, + struct net_device *dev); +int t3_l2t_send_slow(struct t3cdev *dev, struct sk_buff *skb, + struct l2t_entry *e); +void t3_l2t_send_event(struct t3cdev *dev, struct l2t_entry *e); +struct l2t_data *t3_init_l2t(unsigned int l2t_capacity); +void t3_free_l2t(struct l2t_data *d); + +int cxgb3_ofld_send(struct t3cdev *dev, struct sk_buff *skb); + +static inline int l2t_send(struct t3cdev *dev, struct sk_buff *skb, + struct l2t_entry *e) +{ + if (likely(e->state == L2T_STATE_VALID)) + return cxgb3_ofld_send(dev, skb); + return t3_l2t_send_slow(dev, skb, e); +} + +static inline void l2t_release(struct l2t_data *d, struct l2t_entry *e) +{ + if (atomic_dec_and_test(&e->refcnt)) + t3_l2e_free(d, e); +} + +static inline void l2t_hold(struct l2t_data *d, struct l2t_entry *e) +{ + if (atomic_add_return(1, &e->refcnt) == 1) /* 0 -> 1 transition */ + atomic_dec(&d->nfree); +} + +#endif diff --git a/drivers/net/ethernet/chelsio/cxgb3/mc5.c b/drivers/net/ethernet/chelsio/cxgb3/mc5.c new file mode 100644 index 000000000000..e13b7fe9d082 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb3/mc5.c @@ -0,0 +1,438 @@ +/* + * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "common.h" +#include "regs.h" + +enum { + IDT75P52100 = 4, + IDT75N43102 = 5 +}; + +/* DBGI command mode */ +enum { + DBGI_MODE_MBUS = 0, + DBGI_MODE_IDT52100 = 5 +}; + +/* IDT 75P52100 commands */ +#define IDT_CMD_READ 0 +#define IDT_CMD_WRITE 1 +#define IDT_CMD_SEARCH 2 +#define IDT_CMD_LEARN 3 + +/* IDT LAR register address and value for 144-bit mode (low 32 bits) */ +#define IDT_LAR_ADR0 0x180006 +#define IDT_LAR_MODE144 0xffff0000 + +/* IDT SCR and SSR addresses (low 32 bits) */ +#define IDT_SCR_ADR0 0x180000 +#define IDT_SSR0_ADR0 0x180002 +#define IDT_SSR1_ADR0 0x180004 + +/* IDT GMR base address (low 32 bits) */ +#define IDT_GMR_BASE_ADR0 0x180020 + +/* IDT data and mask array base addresses (low 32 bits) */ +#define IDT_DATARY_BASE_ADR0 0 +#define IDT_MSKARY_BASE_ADR0 0x80000 + +/* IDT 75N43102 commands */ +#define IDT4_CMD_SEARCH144 3 +#define IDT4_CMD_WRITE 4 +#define IDT4_CMD_READ 5 + +/* IDT 75N43102 SCR address (low 32 bits) */ +#define IDT4_SCR_ADR0 0x3 + +/* IDT 75N43102 GMR base addresses (low 32 bits) */ +#define IDT4_GMR_BASE0 0x10 +#define IDT4_GMR_BASE1 0x20 +#define IDT4_GMR_BASE2 0x30 + +/* IDT 75N43102 data and mask array base addresses (low 32 bits) */ +#define IDT4_DATARY_BASE_ADR0 0x1000000 +#define IDT4_MSKARY_BASE_ADR0 0x2000000 + +#define MAX_WRITE_ATTEMPTS 5 + +#define MAX_ROUTES 2048 + +/* + * Issue a command to the TCAM and wait for its completion. The address and + * any data required by the command must have been setup by the caller. + */ +static int mc5_cmd_write(struct adapter *adapter, u32 cmd) +{ + t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_CMD, cmd); + return t3_wait_op_done(adapter, A_MC5_DB_DBGI_RSP_STATUS, + F_DBGIRSPVALID, 1, MAX_WRITE_ATTEMPTS, 1); +} + +static inline void dbgi_wr_addr3(struct adapter *adapter, u32 v1, u32 v2, + u32 v3) +{ + t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR0, v1); + t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR1, v2); + t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR2, v3); +} + +static inline void dbgi_wr_data3(struct adapter *adapter, u32 v1, u32 v2, + u32 v3) +{ + t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA0, v1); + t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA1, v2); + t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA2, v3); +} + +static inline void dbgi_rd_rsp3(struct adapter *adapter, u32 *v1, u32 *v2, + u32 *v3) +{ + *v1 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA0); + *v2 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA1); + *v3 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA2); +} + +/* + * Write data to the TCAM register at address (0, 0, addr_lo) using the TCAM + * command cmd. The data to be written must have been set up by the caller. + * Returns -1 on failure, 0 on success. + */ +static int mc5_write(struct adapter *adapter, u32 addr_lo, u32 cmd) +{ + t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR0, addr_lo); + if (mc5_cmd_write(adapter, cmd) == 0) + return 0; + CH_ERR(adapter, "MC5 timeout writing to TCAM address 0x%x\n", + addr_lo); + return -1; +} + +static int init_mask_data_array(struct mc5 *mc5, u32 mask_array_base, + u32 data_array_base, u32 write_cmd, + int addr_shift) +{ + unsigned int i; + struct adapter *adap = mc5->adapter; + + /* + * We need the size of the TCAM data and mask arrays in terms of + * 72-bit entries. + */ + unsigned int size72 = mc5->tcam_size; + unsigned int server_base = t3_read_reg(adap, A_MC5_DB_SERVER_INDEX); + + if (mc5->mode == MC5_MODE_144_BIT) { + size72 *= 2; /* 1 144-bit entry is 2 72-bit entries */ + server_base *= 2; + } + + /* Clear the data array */ + dbgi_wr_data3(adap, 0, 0, 0); + for (i = 0; i < size72; i++) + if (mc5_write(adap, data_array_base + (i << addr_shift), + write_cmd)) + 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); + if (mc5_write(adap, mask_array_base + (i << addr_shift), + write_cmd)) + return -1; + } + return 0; +} + +static int init_idt52100(struct mc5 *mc5) +{ + int i; + struct adapter *adap = mc5->adapter; + + t3_write_reg(adap, A_MC5_DB_RSP_LATENCY, + V_RDLAT(0x15) | V_LRNLAT(0x15) | V_SRCHLAT(0x15)); + t3_write_reg(adap, A_MC5_DB_PART_ID_INDEX, 2); + + /* + * Use GMRs 14-15 for ELOOKUP, GMRs 12-13 for SYN lookups, and + * GMRs 8-9 for ACK- and AOPEN searches. + */ + t3_write_reg(adap, A_MC5_DB_POPEN_DATA_WR_CMD, IDT_CMD_WRITE); + t3_write_reg(adap, A_MC5_DB_POPEN_MASK_WR_CMD, IDT_CMD_WRITE); + t3_write_reg(adap, A_MC5_DB_AOPEN_SRCH_CMD, IDT_CMD_SEARCH); + t3_write_reg(adap, A_MC5_DB_AOPEN_LRN_CMD, IDT_CMD_LEARN); + t3_write_reg(adap, A_MC5_DB_SYN_SRCH_CMD, IDT_CMD_SEARCH | 0x6000); + t3_write_reg(adap, A_MC5_DB_SYN_LRN_CMD, IDT_CMD_LEARN); + t3_write_reg(adap, A_MC5_DB_ACK_SRCH_CMD, IDT_CMD_SEARCH); + t3_write_reg(adap, A_MC5_DB_ACK_LRN_CMD, IDT_CMD_LEARN); + t3_write_reg(adap, A_MC5_DB_ILOOKUP_CMD, IDT_CMD_SEARCH); + t3_write_reg(adap, A_MC5_DB_ELOOKUP_CMD, IDT_CMD_SEARCH | 0x7000); + t3_write_reg(adap, A_MC5_DB_DATA_WRITE_CMD, IDT_CMD_WRITE); + t3_write_reg(adap, A_MC5_DB_DATA_READ_CMD, IDT_CMD_READ); + + /* Set DBGI command mode for IDT TCAM. */ + t3_write_reg(adap, A_MC5_DB_DBGI_CONFIG, DBGI_MODE_IDT52100); + + /* Set up LAR */ + dbgi_wr_data3(adap, IDT_LAR_MODE144, 0, 0); + if (mc5_write(adap, IDT_LAR_ADR0, IDT_CMD_WRITE)) + goto err; + + /* Set up SSRs */ + dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0); + if (mc5_write(adap, IDT_SSR0_ADR0, IDT_CMD_WRITE) || + mc5_write(adap, IDT_SSR1_ADR0, IDT_CMD_WRITE)) + goto err; + + /* Set up GMRs */ + for (i = 0; i < 32; ++i) { + if (i >= 12 && i < 15) + dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff); + else if (i == 15) + dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff); + else + dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff); + + if (mc5_write(adap, IDT_GMR_BASE_ADR0 + i, IDT_CMD_WRITE)) + goto err; + } + + /* Set up SCR */ + dbgi_wr_data3(adap, 1, 0, 0); + if (mc5_write(adap, IDT_SCR_ADR0, IDT_CMD_WRITE)) + goto err; + + return init_mask_data_array(mc5, IDT_MSKARY_BASE_ADR0, + IDT_DATARY_BASE_ADR0, IDT_CMD_WRITE, 0); +err: + return -EIO; +} + +static int init_idt43102(struct mc5 *mc5) +{ + int i; + struct adapter *adap = mc5->adapter; + + t3_write_reg(adap, A_MC5_DB_RSP_LATENCY, + adap->params.rev == 0 ? V_RDLAT(0xd) | V_SRCHLAT(0x11) : + V_RDLAT(0xd) | V_SRCHLAT(0x12)); + + /* + * Use GMRs 24-25 for ELOOKUP, GMRs 20-21 for SYN lookups, and no mask + * for ACK- and AOPEN searches. + */ + t3_write_reg(adap, A_MC5_DB_POPEN_DATA_WR_CMD, IDT4_CMD_WRITE); + t3_write_reg(adap, A_MC5_DB_POPEN_MASK_WR_CMD, IDT4_CMD_WRITE); + t3_write_reg(adap, A_MC5_DB_AOPEN_SRCH_CMD, + IDT4_CMD_SEARCH144 | 0x3800); + t3_write_reg(adap, A_MC5_DB_SYN_SRCH_CMD, IDT4_CMD_SEARCH144); + t3_write_reg(adap, A_MC5_DB_ACK_SRCH_CMD, IDT4_CMD_SEARCH144 | 0x3800); + t3_write_reg(adap, A_MC5_DB_ILOOKUP_CMD, IDT4_CMD_SEARCH144 | 0x3800); + t3_write_reg(adap, A_MC5_DB_ELOOKUP_CMD, IDT4_CMD_SEARCH144 | 0x800); + t3_write_reg(adap, A_MC5_DB_DATA_WRITE_CMD, IDT4_CMD_WRITE); + t3_write_reg(adap, A_MC5_DB_DATA_READ_CMD, IDT4_CMD_READ); + + t3_write_reg(adap, A_MC5_DB_PART_ID_INDEX, 3); + + /* Set DBGI command mode for IDT TCAM. */ + t3_write_reg(adap, A_MC5_DB_DBGI_CONFIG, DBGI_MODE_IDT52100); + + /* Set up GMRs */ + dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff); + for (i = 0; i < 7; ++i) + if (mc5_write(adap, IDT4_GMR_BASE0 + i, IDT4_CMD_WRITE)) + goto err; + + for (i = 0; i < 4; ++i) + if (mc5_write(adap, IDT4_GMR_BASE2 + i, IDT4_CMD_WRITE)) + goto err; + + dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff); + if (mc5_write(adap, IDT4_GMR_BASE1, IDT4_CMD_WRITE) || + mc5_write(adap, IDT4_GMR_BASE1 + 1, IDT4_CMD_WRITE) || + mc5_write(adap, IDT4_GMR_BASE1 + 4, IDT4_CMD_WRITE)) + goto err; + + dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff); + if (mc5_write(adap, IDT4_GMR_BASE1 + 5, IDT4_CMD_WRITE)) + goto err; + + /* Set up SCR */ + dbgi_wr_data3(adap, 0xf0000000, 0, 0); + if (mc5_write(adap, IDT4_SCR_ADR0, IDT4_CMD_WRITE)) + goto err; + + return init_mask_data_array(mc5, IDT4_MSKARY_BASE_ADR0, + IDT4_DATARY_BASE_ADR0, IDT4_CMD_WRITE, 1); +err: + return -EIO; +} + +/* 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); +} + +/* 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); +} + +/* + * Initialization that requires the OS and protocol layers to already + * be initialized goes here. + */ +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; + struct adapter *adap = mc5->adapter; + + if (!tcam_size) + return 0; + + if (nroutes > MAX_ROUTES || nroutes + nservers + nfilters > tcam_size) + return -EINVAL; + + /* 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); + 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; + } + + t3_write_reg(adap, A_MC5_DB_ROUTING_TABLE_INDEX, tcam_size - nroutes); + t3_write_reg(adap, A_MC5_DB_FILTER_TABLE, + tcam_size - nroutes - 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); + + mc5_dbgi_mode_enable(mc5); + + switch (mc5->part_type) { + case IDT75P52100: + err = init_idt52100(mc5); + break; + case IDT75N43102: + err = init_idt43102(mc5); + break; + default: + CH_ERR(adap, "Unsupported TCAM type %d\n", mc5->part_type); + err = -EINVAL; + break; + } + + mc5_dbgi_mode_disable(mc5); + return err; +} + + +#define MC5_INT_FATAL (F_PARITYERR | F_REQQPARERR | F_DISPQPARERR) + +/* + * MC5 interrupt handler + */ +void t3_mc5_intr_handler(struct mc5 *mc5) +{ + struct adapter *adap = mc5->adapter; + u32 cause = t3_read_reg(adap, A_MC5_DB_INT_CAUSE); + + if ((cause & F_PARITYERR) && mc5->parity_enabled) { + CH_ALERT(adap, "MC5 parity error\n"); + mc5->stats.parity_err++; + } + + if (cause & F_REQQPARERR) { + CH_ALERT(adap, "MC5 request queue parity error\n"); + mc5->stats.reqq_parity_err++; + } + + if (cause & F_DISPQPARERR) { + CH_ALERT(adap, "MC5 dispatch queue parity error\n"); + mc5->stats.dispq_parity_err++; + } + + if (cause & F_ACTRGNFULL) + mc5->stats.active_rgn_full++; + if (cause & F_NFASRCHFAIL) + mc5->stats.nfa_srch_err++; + if (cause & F_UNKNOWNCMD) + mc5->stats.unknown_cmd++; + if (cause & F_DELACTEMPTY) + mc5->stats.del_act_empty++; + if (cause & MC5_INT_FATAL) + t3_fatal_err(adap); + + t3_write_reg(adap, A_MC5_DB_INT_CAUSE, cause); +} + +void t3_mc5_prep(struct adapter *adapter, struct mc5 *mc5, int mode) +{ +#define K * 1024 + + static unsigned int tcam_part_size[] = { /* in K 72-bit entries */ + 64 K, 128 K, 256 K, 32 K + }; + +#undef K + + u32 cfg = t3_read_reg(adapter, A_MC5_DB_CONFIG); + + mc5->adapter = adapter; + mc5->mode = (unsigned char)mode; + mc5->part_type = (unsigned char)G_TMTYPE(cfg); + if (cfg & F_TMTYPEHI) + mc5->part_type |= 4; + + mc5->tcam_size = tcam_part_size[G_TMPARTSIZE(cfg)]; + if (mode == MC5_MODE_144_BIT) + mc5->tcam_size /= 2; +} diff --git a/drivers/net/ethernet/chelsio/cxgb3/regs.h b/drivers/net/ethernet/chelsio/cxgb3/regs.h new file mode 100644 index 000000000000..6990f6c65221 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb3/regs.h @@ -0,0 +1,2598 @@ +#define A_SG_CONTROL 0x0 + +#define S_CONGMODE 29 +#define V_CONGMODE(x) ((x) << S_CONGMODE) +#define F_CONGMODE V_CONGMODE(1U) + +#define S_TNLFLMODE 28 +#define V_TNLFLMODE(x) ((x) << S_TNLFLMODE) +#define F_TNLFLMODE V_TNLFLMODE(1U) + +#define S_FATLPERREN 27 +#define V_FATLPERREN(x) ((x) << S_FATLPERREN) +#define F_FATLPERREN V_FATLPERREN(1U) + +#define S_DROPPKT 20 +#define V_DROPPKT(x) ((x) << S_DROPPKT) +#define F_DROPPKT V_DROPPKT(1U) + +#define S_EGRGENCTRL 19 +#define V_EGRGENCTRL(x) ((x) << S_EGRGENCTRL) +#define F_EGRGENCTRL V_EGRGENCTRL(1U) + +#define S_USERSPACESIZE 14 +#define M_USERSPACESIZE 0x1f +#define V_USERSPACESIZE(x) ((x) << S_USERSPACESIZE) + +#define S_HOSTPAGESIZE 11 +#define M_HOSTPAGESIZE 0x7 +#define V_HOSTPAGESIZE(x) ((x) << S_HOSTPAGESIZE) + +#define S_FLMODE 9 +#define V_FLMODE(x) ((x) << S_FLMODE) +#define F_FLMODE V_FLMODE(1U) + +#define S_PKTSHIFT 6 +#define M_PKTSHIFT 0x7 +#define V_PKTSHIFT(x) ((x) << S_PKTSHIFT) + +#define S_ONEINTMULTQ 5 +#define V_ONEINTMULTQ(x) ((x) << S_ONEINTMULTQ) +#define F_ONEINTMULTQ V_ONEINTMULTQ(1U) + +#define S_BIGENDIANINGRESS 2 +#define V_BIGENDIANINGRESS(x) ((x) << S_BIGENDIANINGRESS) +#define F_BIGENDIANINGRESS V_BIGENDIANINGRESS(1U) + +#define S_ISCSICOALESCING 1 +#define V_ISCSICOALESCING(x) ((x) << S_ISCSICOALESCING) +#define F_ISCSICOALESCING V_ISCSICOALESCING(1U) + +#define S_GLOBALENABLE 0 +#define V_GLOBALENABLE(x) ((x) << S_GLOBALENABLE) +#define F_GLOBALENABLE V_GLOBALENABLE(1U) + +#define S_AVOIDCQOVFL 24 +#define V_AVOIDCQOVFL(x) ((x) << S_AVOIDCQOVFL) +#define F_AVOIDCQOVFL V_AVOIDCQOVFL(1U) + +#define S_OPTONEINTMULTQ 23 +#define V_OPTONEINTMULTQ(x) ((x) << S_OPTONEINTMULTQ) +#define F_OPTONEINTMULTQ V_OPTONEINTMULTQ(1U) + +#define S_CQCRDTCTRL 22 +#define V_CQCRDTCTRL(x) ((x) << S_CQCRDTCTRL) +#define F_CQCRDTCTRL V_CQCRDTCTRL(1U) + +#define A_SG_KDOORBELL 0x4 + +#define S_SELEGRCNTX 31 +#define V_SELEGRCNTX(x) ((x) << S_SELEGRCNTX) +#define F_SELEGRCNTX V_SELEGRCNTX(1U) + +#define S_EGRCNTX 0 +#define M_EGRCNTX 0xffff +#define V_EGRCNTX(x) ((x) << S_EGRCNTX) + +#define A_SG_GTS 0x8 + +#define S_RSPQ 29 +#define M_RSPQ 0x7 +#define V_RSPQ(x) ((x) << S_RSPQ) +#define G_RSPQ(x) (((x) >> S_RSPQ) & M_RSPQ) + +#define S_NEWTIMER 16 +#define M_NEWTIMER 0x1fff +#define V_NEWTIMER(x) ((x) << S_NEWTIMER) + +#define S_NEWINDEX 0 +#define M_NEWINDEX 0xffff +#define V_NEWINDEX(x) ((x) << S_NEWINDEX) + +#define A_SG_CONTEXT_CMD 0xc + +#define S_CONTEXT_CMD_OPCODE 28 +#define M_CONTEXT_CMD_OPCODE 0xf +#define V_CONTEXT_CMD_OPCODE(x) ((x) << S_CONTEXT_CMD_OPCODE) + +#define S_CONTEXT_CMD_BUSY 27 +#define V_CONTEXT_CMD_BUSY(x) ((x) << S_CONTEXT_CMD_BUSY) +#define F_CONTEXT_CMD_BUSY V_CONTEXT_CMD_BUSY(1U) + +#define S_CQ_CREDIT 20 + +#define M_CQ_CREDIT 0x7f + +#define V_CQ_CREDIT(x) ((x) << S_CQ_CREDIT) + +#define G_CQ_CREDIT(x) (((x) >> S_CQ_CREDIT) & M_CQ_CREDIT) + +#define S_CQ 19 + +#define V_CQ(x) ((x) << S_CQ) +#define F_CQ V_CQ(1U) + +#define S_RESPONSEQ 18 +#define V_RESPONSEQ(x) ((x) << S_RESPONSEQ) +#define F_RESPONSEQ V_RESPONSEQ(1U) + +#define S_EGRESS 17 +#define V_EGRESS(x) ((x) << S_EGRESS) +#define F_EGRESS V_EGRESS(1U) + +#define S_FREELIST 16 +#define V_FREELIST(x) ((x) << S_FREELIST) +#define F_FREELIST V_FREELIST(1U) + +#define S_CONTEXT 0 +#define M_CONTEXT 0xffff +#define V_CONTEXT(x) ((x) << S_CONTEXT) + +#define G_CONTEXT(x) (((x) >> S_CONTEXT) & M_CONTEXT) + +#define A_SG_CONTEXT_DATA0 0x10 + +#define A_SG_CONTEXT_DATA1 0x14 + +#define A_SG_CONTEXT_DATA2 0x18 + +#define A_SG_CONTEXT_DATA3 0x1c + +#define A_SG_CONTEXT_MASK0 0x20 + +#define A_SG_CONTEXT_MASK1 0x24 + +#define A_SG_CONTEXT_MASK2 0x28 + +#define A_SG_CONTEXT_MASK3 0x2c + +#define A_SG_RSPQ_CREDIT_RETURN 0x30 + +#define S_CREDITS 0 +#define M_CREDITS 0xffff +#define V_CREDITS(x) ((x) << S_CREDITS) + +#define A_SG_DATA_INTR 0x34 + +#define S_ERRINTR 31 +#define V_ERRINTR(x) ((x) << S_ERRINTR) +#define F_ERRINTR V_ERRINTR(1U) + +#define A_SG_HI_DRB_HI_THRSH 0x38 + +#define A_SG_HI_DRB_LO_THRSH 0x3c + +#define A_SG_LO_DRB_HI_THRSH 0x40 + +#define A_SG_LO_DRB_LO_THRSH 0x44 + +#define A_SG_RSPQ_FL_STATUS 0x4c + +#define S_RSPQ0DISABLED 8 + +#define S_FL0EMPTY 16 +#define V_FL0EMPTY(x) ((x) << S_FL0EMPTY) +#define F_FL0EMPTY V_FL0EMPTY(1U) + +#define A_SG_EGR_RCQ_DRB_THRSH 0x54 + +#define S_HIRCQDRBTHRSH 16 +#define M_HIRCQDRBTHRSH 0x7ff +#define V_HIRCQDRBTHRSH(x) ((x) << S_HIRCQDRBTHRSH) + +#define S_LORCQDRBTHRSH 0 +#define M_LORCQDRBTHRSH 0x7ff +#define V_LORCQDRBTHRSH(x) ((x) << S_LORCQDRBTHRSH) + +#define A_SG_EGR_CNTX_BADDR 0x58 + +#define A_SG_INT_CAUSE 0x5c + +#define S_HIRCQPARITYERROR 31 +#define V_HIRCQPARITYERROR(x) ((x) << S_HIRCQPARITYERROR) +#define F_HIRCQPARITYERROR V_HIRCQPARITYERROR(1U) + +#define S_LORCQPARITYERROR 30 +#define V_LORCQPARITYERROR(x) ((x) << S_LORCQPARITYERROR) +#define F_LORCQPARITYERROR V_LORCQPARITYERROR(1U) + +#define S_HIDRBPARITYERROR 29 +#define V_HIDRBPARITYERROR(x) ((x) << S_HIDRBPARITYERROR) +#define F_HIDRBPARITYERROR V_HIDRBPARITYERROR(1U) + +#define S_LODRBPARITYERROR 28 +#define V_LODRBPARITYERROR(x) ((x) << S_LODRBPARITYERROR) +#define F_LODRBPARITYERROR V_LODRBPARITYERROR(1U) + +#define S_FLPARITYERROR 22 +#define M_FLPARITYERROR 0x3f +#define V_FLPARITYERROR(x) ((x) << S_FLPARITYERROR) +#define G_FLPARITYERROR(x) (((x) >> S_FLPARITYERROR) & M_FLPARITYERROR) + +#define S_ITPARITYERROR 20 +#define M_ITPARITYERROR 0x3 +#define V_ITPARITYERROR(x) ((x) << S_ITPARITYERROR) +#define G_ITPARITYERROR(x) (((x) >> S_ITPARITYERROR) & M_ITPARITYERROR) + +#define S_IRPARITYERROR 19 +#define V_IRPARITYERROR(x) ((x) << S_IRPARITYERROR) +#define F_IRPARITYERROR V_IRPARITYERROR(1U) + +#define S_RCPARITYERROR 18 +#define V_RCPARITYERROR(x) ((x) << S_RCPARITYERROR) +#define F_RCPARITYERROR V_RCPARITYERROR(1U) + +#define S_OCPARITYERROR 17 +#define V_OCPARITYERROR(x) ((x) << S_OCPARITYERROR) +#define F_OCPARITYERROR V_OCPARITYERROR(1U) + +#define S_CPPARITYERROR 16 +#define V_CPPARITYERROR(x) ((x) << S_CPPARITYERROR) +#define F_CPPARITYERROR V_CPPARITYERROR(1U) + +#define S_R_REQ_FRAMINGERROR 15 +#define V_R_REQ_FRAMINGERROR(x) ((x) << S_R_REQ_FRAMINGERROR) +#define F_R_REQ_FRAMINGERROR V_R_REQ_FRAMINGERROR(1U) + +#define S_UC_REQ_FRAMINGERROR 14 +#define V_UC_REQ_FRAMINGERROR(x) ((x) << S_UC_REQ_FRAMINGERROR) +#define F_UC_REQ_FRAMINGERROR V_UC_REQ_FRAMINGERROR(1U) + +#define S_HICTLDRBDROPERR 13 +#define V_HICTLDRBDROPERR(x) ((x) << S_HICTLDRBDROPERR) +#define F_HICTLDRBDROPERR V_HICTLDRBDROPERR(1U) + +#define S_LOCTLDRBDROPERR 12 +#define V_LOCTLDRBDROPERR(x) ((x) << S_LOCTLDRBDROPERR) +#define F_LOCTLDRBDROPERR V_LOCTLDRBDROPERR(1U) + +#define S_HIPIODRBDROPERR 11 +#define V_HIPIODRBDROPERR(x) ((x) << S_HIPIODRBDROPERR) +#define F_HIPIODRBDROPERR V_HIPIODRBDROPERR(1U) + +#define S_LOPIODRBDROPERR 10 +#define V_LOPIODRBDROPERR(x) ((x) << S_LOPIODRBDROPERR) +#define F_LOPIODRBDROPERR V_LOPIODRBDROPERR(1U) + +#define S_HIPRIORITYDBFULL 7 +#define V_HIPRIORITYDBFULL(x) ((x) << S_HIPRIORITYDBFULL) +#define F_HIPRIORITYDBFULL V_HIPRIORITYDBFULL(1U) + +#define S_HIPRIORITYDBEMPTY 6 +#define V_HIPRIORITYDBEMPTY(x) ((x) << S_HIPRIORITYDBEMPTY) +#define F_HIPRIORITYDBEMPTY V_HIPRIORITYDBEMPTY(1U) + +#define S_LOPRIORITYDBFULL 5 +#define V_LOPRIORITYDBFULL(x) ((x) << S_LOPRIORITYDBFULL) +#define F_LOPRIORITYDBFULL V_LOPRIORITYDBFULL(1U) + +#define S_LOPRIORITYDBEMPTY 4 +#define V_LOPRIORITYDBEMPTY(x) ((x) << S_LOPRIORITYDBEMPTY) +#define F_LOPRIORITYDBEMPTY V_LOPRIORITYDBEMPTY(1U) + +#define S_RSPQDISABLED 3 +#define V_RSPQDISABLED(x) ((x) << S_RSPQDISABLED) +#define F_RSPQDISABLED V_RSPQDISABLED(1U) + +#define S_RSPQCREDITOVERFOW 2 +#define V_RSPQCREDITOVERFOW(x) ((x) << S_RSPQCREDITOVERFOW) +#define F_RSPQCREDITOVERFOW V_RSPQCREDITOVERFOW(1U) + +#define S_FLEMPTY 1 +#define V_FLEMPTY(x) ((x) << S_FLEMPTY) +#define F_FLEMPTY V_FLEMPTY(1U) + +#define A_SG_INT_ENABLE 0x60 + +#define A_SG_CMDQ_CREDIT_TH 0x64 + +#define S_TIMEOUT 8 +#define M_TIMEOUT 0xffffff +#define V_TIMEOUT(x) ((x) << S_TIMEOUT) + +#define S_THRESHOLD 0 +#define M_THRESHOLD 0xff +#define V_THRESHOLD(x) ((x) << S_THRESHOLD) + +#define A_SG_TIMER_TICK 0x68 + +#define A_SG_CQ_CONTEXT_BADDR 0x6c + +#define A_SG_OCO_BASE 0x70 + +#define S_BASE1 16 +#define M_BASE1 0xffff +#define V_BASE1(x) ((x) << S_BASE1) + +#define A_SG_DRB_PRI_THRESH 0x74 + +#define A_PCIX_INT_ENABLE 0x80 + +#define S_MSIXPARERR 22 +#define M_MSIXPARERR 0x7 + +#define V_MSIXPARERR(x) ((x) << S_MSIXPARERR) + +#define S_CFPARERR 18 +#define M_CFPARERR 0xf + +#define V_CFPARERR(x) ((x) << S_CFPARERR) + +#define S_RFPARERR 14 +#define M_RFPARERR 0xf + +#define V_RFPARERR(x) ((x) << S_RFPARERR) + +#define S_WFPARERR 12 +#define M_WFPARERR 0x3 + +#define V_WFPARERR(x) ((x) << S_WFPARERR) + +#define S_PIOPARERR 11 +#define V_PIOPARERR(x) ((x) << S_PIOPARERR) +#define F_PIOPARERR V_PIOPARERR(1U) + +#define S_DETUNCECCERR 10 +#define V_DETUNCECCERR(x) ((x) << S_DETUNCECCERR) +#define F_DETUNCECCERR V_DETUNCECCERR(1U) + +#define S_DETCORECCERR 9 +#define V_DETCORECCERR(x) ((x) << S_DETCORECCERR) +#define F_DETCORECCERR V_DETCORECCERR(1U) + +#define S_RCVSPLCMPERR 8 +#define V_RCVSPLCMPERR(x) ((x) << S_RCVSPLCMPERR) +#define F_RCVSPLCMPERR V_RCVSPLCMPERR(1U) + +#define S_UNXSPLCMP 7 +#define V_UNXSPLCMP(x) ((x) << S_UNXSPLCMP) +#define F_UNXSPLCMP V_UNXSPLCMP(1U) + +#define S_SPLCMPDIS 6 +#define V_SPLCMPDIS(x) ((x) << S_SPLCMPDIS) +#define F_SPLCMPDIS V_SPLCMPDIS(1U) + +#define S_DETPARERR 5 +#define V_DETPARERR(x) ((x) << S_DETPARERR) +#define F_DETPARERR V_DETPARERR(1U) + +#define S_SIGSYSERR 4 +#define V_SIGSYSERR(x) ((x) << S_SIGSYSERR) +#define F_SIGSYSERR V_SIGSYSERR(1U) + +#define S_RCVMSTABT 3 +#define V_RCVMSTABT(x) ((x) << S_RCVMSTABT) +#define F_RCVMSTABT V_RCVMSTABT(1U) + +#define S_RCVTARABT 2 +#define V_RCVTARABT(x) ((x) << S_RCVTARABT) +#define F_RCVTARABT V_RCVTARABT(1U) + +#define S_SIGTARABT 1 +#define V_SIGTARABT(x) ((x) << S_SIGTARABT) +#define F_SIGTARABT V_SIGTARABT(1U) + +#define S_MSTDETPARERR 0 +#define V_MSTDETPARERR(x) ((x) << S_MSTDETPARERR) +#define F_MSTDETPARERR V_MSTDETPARERR(1U) + +#define A_PCIX_INT_CAUSE 0x84 + +#define A_PCIX_CFG 0x88 + +#define S_DMASTOPEN 19 +#define V_DMASTOPEN(x) ((x) << S_DMASTOPEN) +#define F_DMASTOPEN V_DMASTOPEN(1U) + +#define S_CLIDECEN 18 +#define V_CLIDECEN(x) ((x) << S_CLIDECEN) +#define F_CLIDECEN V_CLIDECEN(1U) + +#define A_PCIX_MODE 0x8c + +#define S_PCLKRANGE 6 +#define M_PCLKRANGE 0x3 +#define V_PCLKRANGE(x) ((x) << S_PCLKRANGE) +#define G_PCLKRANGE(x) (((x) >> S_PCLKRANGE) & M_PCLKRANGE) + +#define S_PCIXINITPAT 2 +#define M_PCIXINITPAT 0xf +#define V_PCIXINITPAT(x) ((x) << S_PCIXINITPAT) +#define G_PCIXINITPAT(x) (((x) >> S_PCIXINITPAT) & M_PCIXINITPAT) + +#define S_64BIT 0 +#define V_64BIT(x) ((x) << S_64BIT) +#define F_64BIT V_64BIT(1U) + +#define A_PCIE_INT_ENABLE 0x80 + +#define S_BISTERR 15 +#define M_BISTERR 0xff + +#define V_BISTERR(x) ((x) << S_BISTERR) + +#define S_TXPARERR 18 +#define V_TXPARERR(x) ((x) << S_TXPARERR) +#define F_TXPARERR V_TXPARERR(1U) + +#define S_RXPARERR 17 +#define V_RXPARERR(x) ((x) << S_RXPARERR) +#define F_RXPARERR V_RXPARERR(1U) + +#define S_RETRYLUTPARERR 16 +#define V_RETRYLUTPARERR(x) ((x) << S_RETRYLUTPARERR) +#define F_RETRYLUTPARERR V_RETRYLUTPARERR(1U) + +#define S_RETRYBUFPARERR 15 +#define V_RETRYBUFPARERR(x) ((x) << S_RETRYBUFPARERR) +#define F_RETRYBUFPARERR V_RETRYBUFPARERR(1U) + +#define S_PCIE_MSIXPARERR 12 +#define M_PCIE_MSIXPARERR 0x7 + +#define V_PCIE_MSIXPARERR(x) ((x) << S_PCIE_MSIXPARERR) + +#define S_PCIE_CFPARERR 11 +#define V_PCIE_CFPARERR(x) ((x) << S_PCIE_CFPARERR) +#define F_PCIE_CFPARERR V_PCIE_CFPARERR(1U) + +#define S_PCIE_RFPARERR 10 +#define V_PCIE_RFPARERR(x) ((x) << S_PCIE_RFPARERR) +#define F_PCIE_RFPARERR V_PCIE_RFPARERR(1U) + +#define S_PCIE_WFPARERR 9 +#define V_PCIE_WFPARERR(x) ((x) << S_PCIE_WFPARERR) +#define F_PCIE_WFPARERR V_PCIE_WFPARERR(1U) + +#define S_PCIE_PIOPARERR 8 +#define V_PCIE_PIOPARERR(x) ((x) << S_PCIE_PIOPARERR) +#define F_PCIE_PIOPARERR V_PCIE_PIOPARERR(1U) + +#define S_UNXSPLCPLERRC 7 +#define V_UNXSPLCPLERRC(x) ((x) << S_UNXSPLCPLERRC) +#define F_UNXSPLCPLERRC V_UNXSPLCPLERRC(1U) + +#define S_UNXSPLCPLERRR 6 +#define V_UNXSPLCPLERRR(x) ((x) << S_UNXSPLCPLERRR) +#define F_UNXSPLCPLERRR V_UNXSPLCPLERRR(1U) + +#define S_PEXERR 0 +#define V_PEXERR(x) ((x) << S_PEXERR) +#define F_PEXERR V_PEXERR(1U) + +#define A_PCIE_INT_CAUSE 0x84 + +#define S_PCIE_DMASTOPEN 24 +#define V_PCIE_DMASTOPEN(x) ((x) << S_PCIE_DMASTOPEN) +#define F_PCIE_DMASTOPEN V_PCIE_DMASTOPEN(1U) + +#define A_PCIE_CFG 0x88 + +#define S_ENABLELINKDWNDRST 21 +#define V_ENABLELINKDWNDRST(x) ((x) << S_ENABLELINKDWNDRST) +#define F_ENABLELINKDWNDRST V_ENABLELINKDWNDRST(1U) + +#define S_ENABLELINKDOWNRST 20 +#define V_ENABLELINKDOWNRST(x) ((x) << S_ENABLELINKDOWNRST) +#define F_ENABLELINKDOWNRST V_ENABLELINKDOWNRST(1U) + +#define S_PCIE_CLIDECEN 16 +#define V_PCIE_CLIDECEN(x) ((x) << S_PCIE_CLIDECEN) +#define F_PCIE_CLIDECEN V_PCIE_CLIDECEN(1U) + +#define S_CRSTWRMMODE 0 +#define V_CRSTWRMMODE(x) ((x) << S_CRSTWRMMODE) +#define F_CRSTWRMMODE V_CRSTWRMMODE(1U) + +#define A_PCIE_MODE 0x8c + +#define S_NUMFSTTRNSEQRX 10 +#define M_NUMFSTTRNSEQRX 0xff +#define V_NUMFSTTRNSEQRX(x) ((x) << S_NUMFSTTRNSEQRX) +#define G_NUMFSTTRNSEQRX(x) (((x) >> S_NUMFSTTRNSEQRX) & M_NUMFSTTRNSEQRX) + +#define A_PCIE_PEX_CTRL0 0x98 + +#define S_NUMFSTTRNSEQ 22 +#define M_NUMFSTTRNSEQ 0xff +#define V_NUMFSTTRNSEQ(x) ((x) << S_NUMFSTTRNSEQ) +#define G_NUMFSTTRNSEQ(x) (((x) >> S_NUMFSTTRNSEQ) & M_NUMFSTTRNSEQ) + +#define S_REPLAYLMT 2 +#define M_REPLAYLMT 0xfffff + +#define V_REPLAYLMT(x) ((x) << S_REPLAYLMT) + +#define A_PCIE_PEX_CTRL1 0x9c + +#define S_T3A_ACKLAT 0 +#define M_T3A_ACKLAT 0x7ff + +#define V_T3A_ACKLAT(x) ((x) << S_T3A_ACKLAT) + +#define S_ACKLAT 0 +#define M_ACKLAT 0x1fff + +#define V_ACKLAT(x) ((x) << S_ACKLAT) + +#define A_PCIE_PEX_ERR 0xa4 + +#define A_T3DBG_GPIO_EN 0xd0 + +#define S_GPIO11_OEN 27 +#define V_GPIO11_OEN(x) ((x) << S_GPIO11_OEN) +#define F_GPIO11_OEN V_GPIO11_OEN(1U) + +#define S_GPIO10_OEN 26 +#define V_GPIO10_OEN(x) ((x) << S_GPIO10_OEN) +#define F_GPIO10_OEN V_GPIO10_OEN(1U) + +#define S_GPIO7_OEN 23 +#define V_GPIO7_OEN(x) ((x) << S_GPIO7_OEN) +#define F_GPIO7_OEN V_GPIO7_OEN(1U) + +#define S_GPIO6_OEN 22 +#define V_GPIO6_OEN(x) ((x) << S_GPIO6_OEN) +#define F_GPIO6_OEN V_GPIO6_OEN(1U) + +#define S_GPIO5_OEN 21 +#define V_GPIO5_OEN(x) ((x) << S_GPIO5_OEN) +#define F_GPIO5_OEN V_GPIO5_OEN(1U) + +#define S_GPIO4_OEN 20 +#define V_GPIO4_OEN(x) ((x) << S_GPIO4_OEN) +#define F_GPIO4_OEN V_GPIO4_OEN(1U) + +#define S_GPIO2_OEN 18 +#define V_GPIO2_OEN(x) ((x) << S_GPIO2_OEN) +#define F_GPIO2_OEN V_GPIO2_OEN(1U) + +#define S_GPIO1_OEN 17 +#define V_GPIO1_OEN(x) ((x) << S_GPIO1_OEN) +#define F_GPIO1_OEN V_GPIO1_OEN(1U) + +#define S_GPIO0_OEN 16 +#define V_GPIO0_OEN(x) ((x) << S_GPIO0_OEN) +#define F_GPIO0_OEN V_GPIO0_OEN(1U) + +#define S_GPIO10_OUT_VAL 10 +#define V_GPIO10_OUT_VAL(x) ((x) << S_GPIO10_OUT_VAL) +#define F_GPIO10_OUT_VAL V_GPIO10_OUT_VAL(1U) + +#define S_GPIO7_OUT_VAL 7 +#define V_GPIO7_OUT_VAL(x) ((x) << S_GPIO7_OUT_VAL) +#define F_GPIO7_OUT_VAL V_GPIO7_OUT_VAL(1U) + +#define S_GPIO6_OUT_VAL 6 +#define V_GPIO6_OUT_VAL(x) ((x) << S_GPIO6_OUT_VAL) +#define F_GPIO6_OUT_VAL V_GPIO6_OUT_VAL(1U) + +#define S_GPIO5_OUT_VAL 5 +#define V_GPIO5_OUT_VAL(x) ((x) << S_GPIO5_OUT_VAL) +#define F_GPIO5_OUT_VAL V_GPIO5_OUT_VAL(1U) + +#define S_GPIO4_OUT_VAL 4 +#define V_GPIO4_OUT_VAL(x) ((x) << S_GPIO4_OUT_VAL) +#define F_GPIO4_OUT_VAL V_GPIO4_OUT_VAL(1U) + +#define S_GPIO2_OUT_VAL 2 +#define V_GPIO2_OUT_VAL(x) ((x) << S_GPIO2_OUT_VAL) +#define F_GPIO2_OUT_VAL V_GPIO2_OUT_VAL(1U) + +#define S_GPIO1_OUT_VAL 1 +#define V_GPIO1_OUT_VAL(x) ((x) << S_GPIO1_OUT_VAL) +#define F_GPIO1_OUT_VAL V_GPIO1_OUT_VAL(1U) + +#define S_GPIO0_OUT_VAL 0 +#define V_GPIO0_OUT_VAL(x) ((x) << S_GPIO0_OUT_VAL) +#define F_GPIO0_OUT_VAL V_GPIO0_OUT_VAL(1U) + +#define A_T3DBG_INT_ENABLE 0xd8 + +#define S_GPIO11 11 +#define V_GPIO11(x) ((x) << S_GPIO11) +#define F_GPIO11 V_GPIO11(1U) + +#define S_GPIO10 10 +#define V_GPIO10(x) ((x) << S_GPIO10) +#define F_GPIO10 V_GPIO10(1U) + +#define S_GPIO9 9 +#define V_GPIO9(x) ((x) << S_GPIO9) +#define F_GPIO9 V_GPIO9(1U) + +#define S_GPIO7 7 +#define V_GPIO7(x) ((x) << S_GPIO7) +#define F_GPIO7 V_GPIO7(1U) + +#define S_GPIO6 6 +#define V_GPIO6(x) ((x) << S_GPIO6) +#define F_GPIO6 V_GPIO6(1U) + +#define S_GPIO5 5 +#define V_GPIO5(x) ((x) << S_GPIO5) +#define F_GPIO5 V_GPIO5(1U) + +#define S_GPIO4 4 +#define V_GPIO4(x) ((x) << S_GPIO4) +#define F_GPIO4 V_GPIO4(1U) + +#define S_GPIO3 3 +#define V_GPIO3(x) ((x) << S_GPIO3) +#define F_GPIO3 V_GPIO3(1U) + +#define S_GPIO2 2 +#define V_GPIO2(x) ((x) << S_GPIO2) +#define F_GPIO2 V_GPIO2(1U) + +#define S_GPIO1 1 +#define V_GPIO1(x) ((x) << S_GPIO1) +#define F_GPIO1 V_GPIO1(1U) + +#define S_GPIO0 0 +#define V_GPIO0(x) ((x) << S_GPIO0) +#define F_GPIO0 V_GPIO0(1U) + +#define A_T3DBG_INT_CAUSE 0xdc + +#define A_T3DBG_GPIO_ACT_LOW 0xf0 + +#define MC7_PMRX_BASE_ADDR 0x100 + +#define A_MC7_CFG 0x100 + +#define S_IFEN 13 +#define V_IFEN(x) ((x) << S_IFEN) +#define F_IFEN V_IFEN(1U) + +#define S_TERM150 11 +#define V_TERM150(x) ((x) << S_TERM150) +#define F_TERM150 V_TERM150(1U) + +#define S_SLOW 10 +#define V_SLOW(x) ((x) << S_SLOW) +#define F_SLOW V_SLOW(1U) + +#define S_WIDTH 8 +#define M_WIDTH 0x3 +#define V_WIDTH(x) ((x) << S_WIDTH) +#define G_WIDTH(x) (((x) >> S_WIDTH) & M_WIDTH) + +#define S_BKS 6 +#define V_BKS(x) ((x) << S_BKS) +#define F_BKS V_BKS(1U) + +#define S_ORG 5 +#define V_ORG(x) ((x) << S_ORG) +#define F_ORG V_ORG(1U) + +#define S_DEN 2 +#define M_DEN 0x7 +#define V_DEN(x) ((x) << S_DEN) +#define G_DEN(x) (((x) >> S_DEN) & M_DEN) + +#define S_RDY 1 +#define V_RDY(x) ((x) << S_RDY) +#define F_RDY V_RDY(1U) + +#define S_CLKEN 0 +#define V_CLKEN(x) ((x) << S_CLKEN) +#define F_CLKEN V_CLKEN(1U) + +#define A_MC7_MODE 0x104 + +#define S_BUSY 31 +#define V_BUSY(x) ((x) << S_BUSY) +#define F_BUSY V_BUSY(1U) + +#define S_BUSY 31 +#define V_BUSY(x) ((x) << S_BUSY) +#define F_BUSY V_BUSY(1U) + +#define A_MC7_EXT_MODE1 0x108 + +#define A_MC7_EXT_MODE2 0x10c + +#define A_MC7_EXT_MODE3 0x110 + +#define A_MC7_PRE 0x114 + +#define A_MC7_REF 0x118 + +#define S_PREREFDIV 1 +#define M_PREREFDIV 0x3fff +#define V_PREREFDIV(x) ((x) << S_PREREFDIV) + +#define S_PERREFEN 0 +#define V_PERREFEN(x) ((x) << S_PERREFEN) +#define F_PERREFEN V_PERREFEN(1U) + +#define A_MC7_DLL 0x11c + +#define S_DLLENB 1 +#define V_DLLENB(x) ((x) << S_DLLENB) +#define F_DLLENB V_DLLENB(1U) + +#define S_DLLRST 0 +#define V_DLLRST(x) ((x) << S_DLLRST) +#define F_DLLRST V_DLLRST(1U) + +#define A_MC7_PARM 0x120 + +#define S_ACTTOPREDLY 26 +#define M_ACTTOPREDLY 0xf +#define V_ACTTOPREDLY(x) ((x) << S_ACTTOPREDLY) + +#define S_ACTTORDWRDLY 23 +#define M_ACTTORDWRDLY 0x7 +#define V_ACTTORDWRDLY(x) ((x) << S_ACTTORDWRDLY) + +#define S_PRECYC 20 +#define M_PRECYC 0x7 +#define V_PRECYC(x) ((x) << S_PRECYC) + +#define S_REFCYC 13 +#define M_REFCYC 0x7f +#define V_REFCYC(x) ((x) << S_REFCYC) + +#define S_BKCYC 8 +#define M_BKCYC 0x1f +#define V_BKCYC(x) ((x) << S_BKCYC) + +#define S_WRTORDDLY 4 +#define M_WRTORDDLY 0xf +#define V_WRTORDDLY(x) ((x) << S_WRTORDDLY) + +#define S_RDTOWRDLY 0 +#define M_RDTOWRDLY 0xf +#define V_RDTOWRDLY(x) ((x) << S_RDTOWRDLY) + +#define A_MC7_CAL 0x128 + +#define S_BUSY 31 +#define V_BUSY(x) ((x) << S_BUSY) +#define F_BUSY V_BUSY(1U) + +#define S_BUSY 31 +#define V_BUSY(x) ((x) << S_BUSY) +#define F_BUSY V_BUSY(1U) + +#define S_CAL_FAULT 30 +#define V_CAL_FAULT(x) ((x) << S_CAL_FAULT) +#define F_CAL_FAULT V_CAL_FAULT(1U) + +#define S_SGL_CAL_EN 20 +#define V_SGL_CAL_EN(x) ((x) << S_SGL_CAL_EN) +#define F_SGL_CAL_EN V_SGL_CAL_EN(1U) + +#define A_MC7_ERR_ADDR 0x12c + +#define A_MC7_ECC 0x130 + +#define S_ECCCHKEN 1 +#define V_ECCCHKEN(x) ((x) << S_ECCCHKEN) +#define F_ECCCHKEN V_ECCCHKEN(1U) + +#define S_ECCGENEN 0 +#define V_ECCGENEN(x) ((x) << S_ECCGENEN) +#define F_ECCGENEN V_ECCGENEN(1U) + +#define A_MC7_CE_ADDR 0x134 + +#define A_MC7_CE_DATA0 0x138 + +#define A_MC7_CE_DATA1 0x13c + +#define A_MC7_CE_DATA2 0x140 + +#define S_DATA 0 +#define M_DATA 0xff + +#define G_DATA(x) (((x) >> S_DATA) & M_DATA) + +#define A_MC7_UE_ADDR 0x144 + +#define A_MC7_UE_DATA0 0x148 + +#define A_MC7_UE_DATA1 0x14c + +#define A_MC7_UE_DATA2 0x150 + +#define A_MC7_BD_ADDR 0x154 + +#define S_ADDR 3 + +#define M_ADDR 0x1fffffff + +#define A_MC7_BD_DATA0 0x158 + +#define A_MC7_BD_DATA1 0x15c + +#define A_MC7_BD_OP 0x164 + +#define S_OP 0 + +#define V_OP(x) ((x) << S_OP) +#define F_OP V_OP(1U) + +#define F_OP V_OP(1U) +#define A_SF_OP 0x6dc + +#define A_MC7_BIST_ADDR_BEG 0x168 + +#define A_MC7_BIST_ADDR_END 0x16c + +#define A_MC7_BIST_DATA 0x170 + +#define A_MC7_BIST_OP 0x174 + +#define S_CONT 3 +#define V_CONT(x) ((x) << S_CONT) +#define F_CONT V_CONT(1U) + +#define F_CONT V_CONT(1U) + +#define A_MC7_INT_ENABLE 0x178 + +#define S_AE 17 +#define V_AE(x) ((x) << S_AE) +#define F_AE V_AE(1U) + +#define S_PE 2 +#define M_PE 0x7fff + +#define V_PE(x) ((x) << S_PE) + +#define G_PE(x) (((x) >> S_PE) & M_PE) + +#define S_UE 1 +#define V_UE(x) ((x) << S_UE) +#define F_UE V_UE(1U) + +#define S_CE 0 +#define V_CE(x) ((x) << S_CE) +#define F_CE V_CE(1U) + +#define A_MC7_INT_CAUSE 0x17c + +#define MC7_PMTX_BASE_ADDR 0x180 + +#define MC7_CM_BASE_ADDR 0x200 + +#define A_CIM_BOOT_CFG 0x280 + +#define S_BOOTADDR 2 +#define M_BOOTADDR 0x3fffffff +#define V_BOOTADDR(x) ((x) << S_BOOTADDR) + +#define A_CIM_SDRAM_BASE_ADDR 0x28c + +#define A_CIM_SDRAM_ADDR_SIZE 0x290 + +#define A_CIM_HOST_INT_ENABLE 0x298 + +#define S_DTAGPARERR 28 +#define V_DTAGPARERR(x) ((x) << S_DTAGPARERR) +#define F_DTAGPARERR V_DTAGPARERR(1U) + +#define S_ITAGPARERR 27 +#define V_ITAGPARERR(x) ((x) << S_ITAGPARERR) +#define F_ITAGPARERR V_ITAGPARERR(1U) + +#define S_IBQTPPARERR 26 +#define V_IBQTPPARERR(x) ((x) << S_IBQTPPARERR) +#define F_IBQTPPARERR V_IBQTPPARERR(1U) + +#define S_IBQULPPARERR 25 +#define V_IBQULPPARERR(x) ((x) << S_IBQULPPARERR) +#define F_IBQULPPARERR V_IBQULPPARERR(1U) + +#define S_IBQSGEHIPARERR 24 +#define V_IBQSGEHIPARERR(x) ((x) << S_IBQSGEHIPARERR) +#define F_IBQSGEHIPARERR V_IBQSGEHIPARERR(1U) + +#define S_IBQSGELOPARERR 23 +#define V_IBQSGELOPARERR(x) ((x) << S_IBQSGELOPARERR) +#define F_IBQSGELOPARERR V_IBQSGELOPARERR(1U) + +#define S_OBQULPLOPARERR 22 +#define V_OBQULPLOPARERR(x) ((x) << S_OBQULPLOPARERR) +#define F_OBQULPLOPARERR V_OBQULPLOPARERR(1U) + +#define S_OBQULPHIPARERR 21 +#define V_OBQULPHIPARERR(x) ((x) << S_OBQULPHIPARERR) +#define F_OBQULPHIPARERR V_OBQULPHIPARERR(1U) + +#define S_OBQSGEPARERR 20 +#define V_OBQSGEPARERR(x) ((x) << S_OBQSGEPARERR) +#define F_OBQSGEPARERR V_OBQSGEPARERR(1U) + +#define S_DCACHEPARERR 19 +#define V_DCACHEPARERR(x) ((x) << S_DCACHEPARERR) +#define F_DCACHEPARERR V_DCACHEPARERR(1U) + +#define S_ICACHEPARERR 18 +#define V_ICACHEPARERR(x) ((x) << S_ICACHEPARERR) +#define F_ICACHEPARERR V_ICACHEPARERR(1U) + +#define S_DRAMPARERR 17 +#define V_DRAMPARERR(x) ((x) << S_DRAMPARERR) +#define F_DRAMPARERR V_DRAMPARERR(1U) + +#define A_CIM_HOST_INT_CAUSE 0x29c + +#define S_BLKWRPLINT 12 +#define V_BLKWRPLINT(x) ((x) << S_BLKWRPLINT) +#define F_BLKWRPLINT V_BLKWRPLINT(1U) + +#define S_BLKRDPLINT 11 +#define V_BLKRDPLINT(x) ((x) << S_BLKRDPLINT) +#define F_BLKRDPLINT V_BLKRDPLINT(1U) + +#define S_BLKWRCTLINT 10 +#define V_BLKWRCTLINT(x) ((x) << S_BLKWRCTLINT) +#define F_BLKWRCTLINT V_BLKWRCTLINT(1U) + +#define S_BLKRDCTLINT 9 +#define V_BLKRDCTLINT(x) ((x) << S_BLKRDCTLINT) +#define F_BLKRDCTLINT V_BLKRDCTLINT(1U) + +#define S_BLKWRFLASHINT 8 +#define V_BLKWRFLASHINT(x) ((x) << S_BLKWRFLASHINT) +#define F_BLKWRFLASHINT V_BLKWRFLASHINT(1U) + +#define S_BLKRDFLASHINT 7 +#define V_BLKRDFLASHINT(x) ((x) << S_BLKRDFLASHINT) +#define F_BLKRDFLASHINT V_BLKRDFLASHINT(1U) + +#define S_SGLWRFLASHINT 6 +#define V_SGLWRFLASHINT(x) ((x) << S_SGLWRFLASHINT) +#define F_SGLWRFLASHINT V_SGLWRFLASHINT(1U) + +#define S_WRBLKFLASHINT 5 +#define V_WRBLKFLASHINT(x) ((x) << S_WRBLKFLASHINT) +#define F_WRBLKFLASHINT V_WRBLKFLASHINT(1U) + +#define S_BLKWRBOOTINT 4 +#define V_BLKWRBOOTINT(x) ((x) << S_BLKWRBOOTINT) +#define F_BLKWRBOOTINT V_BLKWRBOOTINT(1U) + +#define S_FLASHRANGEINT 2 +#define V_FLASHRANGEINT(x) ((x) << S_FLASHRANGEINT) +#define F_FLASHRANGEINT V_FLASHRANGEINT(1U) + +#define S_SDRAMRANGEINT 1 +#define V_SDRAMRANGEINT(x) ((x) << S_SDRAMRANGEINT) +#define F_SDRAMRANGEINT V_SDRAMRANGEINT(1U) + +#define S_RSVDSPACEINT 0 +#define V_RSVDSPACEINT(x) ((x) << S_RSVDSPACEINT) +#define F_RSVDSPACEINT V_RSVDSPACEINT(1U) + +#define A_CIM_HOST_ACC_CTRL 0x2b0 + +#define S_HOSTBUSY 17 +#define V_HOSTBUSY(x) ((x) << S_HOSTBUSY) +#define F_HOSTBUSY V_HOSTBUSY(1U) + +#define A_CIM_HOST_ACC_DATA 0x2b4 + +#define A_CIM_IBQ_DBG_CFG 0x2c0 + +#define S_IBQDBGADDR 16 +#define M_IBQDBGADDR 0x1ff +#define V_IBQDBGADDR(x) ((x) << S_IBQDBGADDR) +#define G_IBQDBGADDR(x) (((x) >> S_IBQDBGADDR) & M_IBQDBGADDR) + +#define S_IBQDBGQID 3 +#define M_IBQDBGQID 0x3 +#define V_IBQDBGQID(x) ((x) << S_IBQDBGQID) +#define G_IBQDBGQID(x) (((x) >> S_IBQDBGQID) & M_IBQDBGQID) + +#define S_IBQDBGWR 2 +#define V_IBQDBGWR(x) ((x) << S_IBQDBGWR) +#define F_IBQDBGWR V_IBQDBGWR(1U) + +#define S_IBQDBGBUSY 1 +#define V_IBQDBGBUSY(x) ((x) << S_IBQDBGBUSY) +#define F_IBQDBGBUSY V_IBQDBGBUSY(1U) + +#define S_IBQDBGEN 0 +#define V_IBQDBGEN(x) ((x) << S_IBQDBGEN) +#define F_IBQDBGEN V_IBQDBGEN(1U) + +#define A_CIM_IBQ_DBG_DATA 0x2c8 + +#define A_TP_IN_CONFIG 0x300 + +#define S_RXFBARBPRIO 25 +#define V_RXFBARBPRIO(x) ((x) << S_RXFBARBPRIO) +#define F_RXFBARBPRIO V_RXFBARBPRIO(1U) + +#define S_TXFBARBPRIO 24 +#define V_TXFBARBPRIO(x) ((x) << S_TXFBARBPRIO) +#define F_TXFBARBPRIO V_TXFBARBPRIO(1U) + +#define S_NICMODE 14 +#define V_NICMODE(x) ((x) << S_NICMODE) +#define F_NICMODE V_NICMODE(1U) + +#define F_NICMODE V_NICMODE(1U) + +#define S_IPV6ENABLE 15 +#define V_IPV6ENABLE(x) ((x) << S_IPV6ENABLE) +#define F_IPV6ENABLE V_IPV6ENABLE(1U) + +#define A_TP_OUT_CONFIG 0x304 + +#define S_VLANEXTRACTIONENABLE 12 + +#define A_TP_GLOBAL_CONFIG 0x308 + +#define S_TXPACINGENABLE 24 +#define V_TXPACINGENABLE(x) ((x) << S_TXPACINGENABLE) +#define F_TXPACINGENABLE V_TXPACINGENABLE(1U) + +#define S_PATHMTU 15 +#define V_PATHMTU(x) ((x) << S_PATHMTU) +#define F_PATHMTU V_PATHMTU(1U) + +#define S_IPCHECKSUMOFFLOAD 13 +#define V_IPCHECKSUMOFFLOAD(x) ((x) << S_IPCHECKSUMOFFLOAD) +#define F_IPCHECKSUMOFFLOAD V_IPCHECKSUMOFFLOAD(1U) + +#define S_UDPCHECKSUMOFFLOAD 12 +#define V_UDPCHECKSUMOFFLOAD(x) ((x) << S_UDPCHECKSUMOFFLOAD) +#define F_UDPCHECKSUMOFFLOAD V_UDPCHECKSUMOFFLOAD(1U) + +#define S_TCPCHECKSUMOFFLOAD 11 +#define V_TCPCHECKSUMOFFLOAD(x) ((x) << S_TCPCHECKSUMOFFLOAD) +#define F_TCPCHECKSUMOFFLOAD V_TCPCHECKSUMOFFLOAD(1U) + +#define S_IPTTL 0 +#define M_IPTTL 0xff +#define V_IPTTL(x) ((x) << S_IPTTL) + +#define A_TP_CMM_MM_BASE 0x314 + +#define A_TP_CMM_TIMER_BASE 0x318 + +#define S_CMTIMERMAXNUM 28 +#define M_CMTIMERMAXNUM 0x3 +#define V_CMTIMERMAXNUM(x) ((x) << S_CMTIMERMAXNUM) + +#define A_TP_PMM_SIZE 0x31c + +#define A_TP_PMM_TX_BASE 0x320 + +#define A_TP_PMM_RX_BASE 0x328 + +#define A_TP_PMM_RX_PAGE_SIZE 0x32c + +#define A_TP_PMM_RX_MAX_PAGE 0x330 + +#define A_TP_PMM_TX_PAGE_SIZE 0x334 + +#define A_TP_PMM_TX_MAX_PAGE 0x338 + +#define A_TP_TCP_OPTIONS 0x340 + +#define S_MTUDEFAULT 16 +#define M_MTUDEFAULT 0xffff +#define V_MTUDEFAULT(x) ((x) << S_MTUDEFAULT) + +#define S_MTUENABLE 10 +#define V_MTUENABLE(x) ((x) << S_MTUENABLE) +#define F_MTUENABLE V_MTUENABLE(1U) + +#define S_SACKRX 8 +#define V_SACKRX(x) ((x) << S_SACKRX) +#define F_SACKRX V_SACKRX(1U) + +#define S_SACKMODE 4 + +#define M_SACKMODE 0x3 + +#define V_SACKMODE(x) ((x) << S_SACKMODE) + +#define S_WINDOWSCALEMODE 2 +#define M_WINDOWSCALEMODE 0x3 +#define V_WINDOWSCALEMODE(x) ((x) << S_WINDOWSCALEMODE) + +#define S_TIMESTAMPSMODE 0 + +#define M_TIMESTAMPSMODE 0x3 + +#define V_TIMESTAMPSMODE(x) ((x) << S_TIMESTAMPSMODE) + +#define A_TP_DACK_CONFIG 0x344 + +#define S_AUTOSTATE3 30 +#define M_AUTOSTATE3 0x3 +#define V_AUTOSTATE3(x) ((x) << S_AUTOSTATE3) + +#define S_AUTOSTATE2 28 +#define M_AUTOSTATE2 0x3 +#define V_AUTOSTATE2(x) ((x) << S_AUTOSTATE2) + +#define S_AUTOSTATE1 26 +#define M_AUTOSTATE1 0x3 +#define V_AUTOSTATE1(x) ((x) << S_AUTOSTATE1) + +#define S_BYTETHRESHOLD 5 +#define M_BYTETHRESHOLD 0xfffff +#define V_BYTETHRESHOLD(x) ((x) << S_BYTETHRESHOLD) + +#define S_MSSTHRESHOLD 3 +#define M_MSSTHRESHOLD 0x3 +#define V_MSSTHRESHOLD(x) ((x) << S_MSSTHRESHOLD) + +#define S_AUTOCAREFUL 2 +#define V_AUTOCAREFUL(x) ((x) << S_AUTOCAREFUL) +#define F_AUTOCAREFUL V_AUTOCAREFUL(1U) + +#define S_AUTOENABLE 1 +#define V_AUTOENABLE(x) ((x) << S_AUTOENABLE) +#define F_AUTOENABLE V_AUTOENABLE(1U) + +#define S_DACK_MODE 0 +#define V_DACK_MODE(x) ((x) << S_DACK_MODE) +#define F_DACK_MODE V_DACK_MODE(1U) + +#define A_TP_PC_CONFIG 0x348 + +#define S_TXTOSQUEUEMAPMODE 26 +#define V_TXTOSQUEUEMAPMODE(x) ((x) << S_TXTOSQUEUEMAPMODE) +#define F_TXTOSQUEUEMAPMODE V_TXTOSQUEUEMAPMODE(1U) + +#define S_ENABLEEPCMDAFULL 23 +#define V_ENABLEEPCMDAFULL(x) ((x) << S_ENABLEEPCMDAFULL) +#define F_ENABLEEPCMDAFULL V_ENABLEEPCMDAFULL(1U) + +#define S_MODULATEUNIONMODE 22 +#define V_MODULATEUNIONMODE(x) ((x) << S_MODULATEUNIONMODE) +#define F_MODULATEUNIONMODE V_MODULATEUNIONMODE(1U) + +#define S_TXDEFERENABLE 20 +#define V_TXDEFERENABLE(x) ((x) << S_TXDEFERENABLE) +#define F_TXDEFERENABLE V_TXDEFERENABLE(1U) + +#define S_RXCONGESTIONMODE 19 +#define V_RXCONGESTIONMODE(x) ((x) << S_RXCONGESTIONMODE) +#define F_RXCONGESTIONMODE V_RXCONGESTIONMODE(1U) + +#define S_HEARBEATDACK 16 +#define V_HEARBEATDACK(x) ((x) << S_HEARBEATDACK) +#define F_HEARBEATDACK V_HEARBEATDACK(1U) + +#define S_TXCONGESTIONMODE 15 +#define V_TXCONGESTIONMODE(x) ((x) << S_TXCONGESTIONMODE) +#define F_TXCONGESTIONMODE V_TXCONGESTIONMODE(1U) + +#define S_ENABLEOCSPIFULL 30 +#define V_ENABLEOCSPIFULL(x) ((x) << S_ENABLEOCSPIFULL) +#define F_ENABLEOCSPIFULL V_ENABLEOCSPIFULL(1U) + +#define S_LOCKTID 28 +#define V_LOCKTID(x) ((x) << S_LOCKTID) +#define F_LOCKTID V_LOCKTID(1U) + +#define S_TABLELATENCYDELTA 0 +#define M_TABLELATENCYDELTA 0xf +#define V_TABLELATENCYDELTA(x) ((x) << S_TABLELATENCYDELTA) +#define G_TABLELATENCYDELTA(x) \ + (((x) >> S_TABLELATENCYDELTA) & M_TABLELATENCYDELTA) + +#define A_TP_PC_CONFIG2 0x34c + +#define S_DISBLEDAPARBIT0 15 +#define V_DISBLEDAPARBIT0(x) ((x) << S_DISBLEDAPARBIT0) +#define F_DISBLEDAPARBIT0 V_DISBLEDAPARBIT0(1U) + +#define S_ENABLEARPMISS 13 +#define V_ENABLEARPMISS(x) ((x) << S_ENABLEARPMISS) +#define F_ENABLEARPMISS V_ENABLEARPMISS(1U) + +#define S_ENABLENONOFDTNLSYN 12 +#define V_ENABLENONOFDTNLSYN(x) ((x) << S_ENABLENONOFDTNLSYN) +#define F_ENABLENONOFDTNLSYN V_ENABLENONOFDTNLSYN(1U) + +#define S_ENABLEIPV6RSS 11 +#define V_ENABLEIPV6RSS(x) ((x) << S_ENABLEIPV6RSS) +#define F_ENABLEIPV6RSS V_ENABLEIPV6RSS(1U) + +#define S_CHDRAFULL 4 +#define V_CHDRAFULL(x) ((x) << S_CHDRAFULL) +#define F_CHDRAFULL V_CHDRAFULL(1U) + +#define A_TP_TCP_BACKOFF_REG0 0x350 + +#define A_TP_TCP_BACKOFF_REG1 0x354 + +#define A_TP_TCP_BACKOFF_REG2 0x358 + +#define A_TP_TCP_BACKOFF_REG3 0x35c + +#define A_TP_PARA_REG2 0x368 + +#define S_MAXRXDATA 16 +#define M_MAXRXDATA 0xffff +#define V_MAXRXDATA(x) ((x) << S_MAXRXDATA) + +#define S_RXCOALESCESIZE 0 +#define M_RXCOALESCESIZE 0xffff +#define V_RXCOALESCESIZE(x) ((x) << S_RXCOALESCESIZE) + +#define A_TP_PARA_REG3 0x36c + +#define S_TXDATAACKIDX 16 +#define M_TXDATAACKIDX 0xf + +#define V_TXDATAACKIDX(x) ((x) << S_TXDATAACKIDX) + +#define S_TXPACEAUTOSTRICT 10 +#define V_TXPACEAUTOSTRICT(x) ((x) << S_TXPACEAUTOSTRICT) +#define F_TXPACEAUTOSTRICT V_TXPACEAUTOSTRICT(1U) + +#define S_TXPACEFIXED 9 +#define V_TXPACEFIXED(x) ((x) << S_TXPACEFIXED) +#define F_TXPACEFIXED V_TXPACEFIXED(1U) + +#define S_TXPACEAUTO 8 +#define V_TXPACEAUTO(x) ((x) << S_TXPACEAUTO) +#define F_TXPACEAUTO V_TXPACEAUTO(1U) + +#define S_RXCOALESCEENABLE 1 +#define V_RXCOALESCEENABLE(x) ((x) << S_RXCOALESCEENABLE) +#define F_RXCOALESCEENABLE V_RXCOALESCEENABLE(1U) + +#define S_RXCOALESCEPSHEN 0 +#define V_RXCOALESCEPSHEN(x) ((x) << S_RXCOALESCEPSHEN) +#define F_RXCOALESCEPSHEN V_RXCOALESCEPSHEN(1U) + +#define A_TP_PARA_REG4 0x370 + +#define A_TP_PARA_REG5 0x374 + +#define S_RXDDPOFFINIT 3 +#define V_RXDDPOFFINIT(x) ((x) << S_RXDDPOFFINIT) +#define F_RXDDPOFFINIT V_RXDDPOFFINIT(1U) + +#define A_TP_PARA_REG6 0x378 + +#define S_T3A_ENABLEESND 13 +#define V_T3A_ENABLEESND(x) ((x) << S_T3A_ENABLEESND) +#define F_T3A_ENABLEESND V_T3A_ENABLEESND(1U) + +#define S_ENABLEESND 11 +#define V_ENABLEESND(x) ((x) << S_ENABLEESND) +#define F_ENABLEESND V_ENABLEESND(1U) + +#define A_TP_PARA_REG7 0x37c + +#define S_PMMAXXFERLEN1 16 +#define M_PMMAXXFERLEN1 0xffff +#define V_PMMAXXFERLEN1(x) ((x) << S_PMMAXXFERLEN1) + +#define S_PMMAXXFERLEN0 0 +#define M_PMMAXXFERLEN0 0xffff +#define V_PMMAXXFERLEN0(x) ((x) << S_PMMAXXFERLEN0) + +#define A_TP_TIMER_RESOLUTION 0x390 + +#define S_TIMERRESOLUTION 16 +#define M_TIMERRESOLUTION 0xff +#define V_TIMERRESOLUTION(x) ((x) << S_TIMERRESOLUTION) + +#define S_TIMESTAMPRESOLUTION 8 +#define M_TIMESTAMPRESOLUTION 0xff +#define V_TIMESTAMPRESOLUTION(x) ((x) << S_TIMESTAMPRESOLUTION) + +#define S_DELAYEDACKRESOLUTION 0 +#define M_DELAYEDACKRESOLUTION 0xff +#define V_DELAYEDACKRESOLUTION(x) ((x) << S_DELAYEDACKRESOLUTION) + +#define A_TP_MSL 0x394 + +#define A_TP_RXT_MIN 0x398 + +#define A_TP_RXT_MAX 0x39c + +#define A_TP_PERS_MIN 0x3a0 + +#define A_TP_PERS_MAX 0x3a4 + +#define A_TP_KEEP_IDLE 0x3a8 + +#define A_TP_KEEP_INTVL 0x3ac + +#define A_TP_INIT_SRTT 0x3b0 + +#define A_TP_DACK_TIMER 0x3b4 + +#define A_TP_FINWAIT2_TIMER 0x3b8 + +#define A_TP_SHIFT_CNT 0x3c0 + +#define S_SYNSHIFTMAX 24 + +#define M_SYNSHIFTMAX 0xff + +#define V_SYNSHIFTMAX(x) ((x) << S_SYNSHIFTMAX) + +#define S_RXTSHIFTMAXR1 20 + +#define M_RXTSHIFTMAXR1 0xf + +#define V_RXTSHIFTMAXR1(x) ((x) << S_RXTSHIFTMAXR1) + +#define S_RXTSHIFTMAXR2 16 + +#define M_RXTSHIFTMAXR2 0xf + +#define V_RXTSHIFTMAXR2(x) ((x) << S_RXTSHIFTMAXR2) + +#define S_PERSHIFTBACKOFFMAX 12 +#define M_PERSHIFTBACKOFFMAX 0xf +#define V_PERSHIFTBACKOFFMAX(x) ((x) << S_PERSHIFTBACKOFFMAX) + +#define S_PERSHIFTMAX 8 +#define M_PERSHIFTMAX 0xf +#define V_PERSHIFTMAX(x) ((x) << S_PERSHIFTMAX) + +#define S_KEEPALIVEMAX 0 + +#define M_KEEPALIVEMAX 0xff + +#define V_KEEPALIVEMAX(x) ((x) << S_KEEPALIVEMAX) + +#define A_TP_MTU_PORT_TABLE 0x3d0 + +#define A_TP_CCTRL_TABLE 0x3dc + +#define A_TP_MTU_TABLE 0x3e4 + +#define A_TP_RSS_MAP_TABLE 0x3e8 + +#define A_TP_RSS_LKP_TABLE 0x3ec + +#define A_TP_RSS_CONFIG 0x3f0 + +#define S_TNL4TUPEN 29 +#define V_TNL4TUPEN(x) ((x) << S_TNL4TUPEN) +#define F_TNL4TUPEN V_TNL4TUPEN(1U) + +#define S_TNL2TUPEN 28 +#define V_TNL2TUPEN(x) ((x) << S_TNL2TUPEN) +#define F_TNL2TUPEN V_TNL2TUPEN(1U) + +#define S_TNLPRTEN 26 +#define V_TNLPRTEN(x) ((x) << S_TNLPRTEN) +#define F_TNLPRTEN V_TNLPRTEN(1U) + +#define S_TNLMAPEN 25 +#define V_TNLMAPEN(x) ((x) << S_TNLMAPEN) +#define F_TNLMAPEN V_TNLMAPEN(1U) + +#define S_TNLLKPEN 24 +#define V_TNLLKPEN(x) ((x) << S_TNLLKPEN) +#define F_TNLLKPEN V_TNLLKPEN(1U) + +#define S_RRCPLMAPEN 7 +#define V_RRCPLMAPEN(x) ((x) << S_RRCPLMAPEN) +#define F_RRCPLMAPEN V_RRCPLMAPEN(1U) + +#define S_RRCPLCPUSIZE 4 +#define M_RRCPLCPUSIZE 0x7 +#define V_RRCPLCPUSIZE(x) ((x) << S_RRCPLCPUSIZE) + +#define S_RQFEEDBACKENABLE 3 +#define V_RQFEEDBACKENABLE(x) ((x) << S_RQFEEDBACKENABLE) +#define F_RQFEEDBACKENABLE V_RQFEEDBACKENABLE(1U) + +#define S_HASHTOEPLITZ 2 +#define V_HASHTOEPLITZ(x) ((x) << S_HASHTOEPLITZ) +#define F_HASHTOEPLITZ V_HASHTOEPLITZ(1U) + +#define S_DISABLE 0 + +#define A_TP_TM_PIO_ADDR 0x418 + +#define A_TP_TM_PIO_DATA 0x41c + +#define A_TP_TX_MOD_QUE_TABLE 0x420 + +#define A_TP_TX_RESOURCE_LIMIT 0x424 + +#define A_TP_TX_MOD_QUEUE_REQ_MAP 0x428 + +#define S_TX_MOD_QUEUE_REQ_MAP 0 +#define M_TX_MOD_QUEUE_REQ_MAP 0xff +#define V_TX_MOD_QUEUE_REQ_MAP(x) ((x) << S_TX_MOD_QUEUE_REQ_MAP) + +#define A_TP_TX_MOD_QUEUE_WEIGHT1 0x42c + +#define A_TP_TX_MOD_QUEUE_WEIGHT0 0x430 + +#define A_TP_MOD_CHANNEL_WEIGHT 0x434 + +#define A_TP_MOD_RATE_LIMIT 0x438 + +#define A_TP_PIO_ADDR 0x440 + +#define A_TP_PIO_DATA 0x444 + +#define A_TP_RESET 0x44c + +#define S_FLSTINITENABLE 1 +#define V_FLSTINITENABLE(x) ((x) << S_FLSTINITENABLE) +#define F_FLSTINITENABLE V_FLSTINITENABLE(1U) + +#define S_TPRESET 0 +#define V_TPRESET(x) ((x) << S_TPRESET) +#define F_TPRESET V_TPRESET(1U) + +#define A_TP_CMM_MM_RX_FLST_BASE 0x460 + +#define A_TP_CMM_MM_TX_FLST_BASE 0x464 + +#define A_TP_CMM_MM_PS_FLST_BASE 0x468 + +#define A_TP_MIB_INDEX 0x450 + +#define A_TP_MIB_RDATA 0x454 + +#define A_TP_CMM_MM_MAX_PSTRUCT 0x46c + +#define A_TP_INT_ENABLE 0x470 + +#define S_FLMTXFLSTEMPTY 30 +#define V_FLMTXFLSTEMPTY(x) ((x) << S_FLMTXFLSTEMPTY) +#define F_FLMTXFLSTEMPTY V_FLMTXFLSTEMPTY(1U) + +#define S_FLMRXFLSTEMPTY 29 +#define V_FLMRXFLSTEMPTY(x) ((x) << S_FLMRXFLSTEMPTY) +#define F_FLMRXFLSTEMPTY V_FLMRXFLSTEMPTY(1U) + +#define S_ARPLUTPERR 26 +#define V_ARPLUTPERR(x) ((x) << S_ARPLUTPERR) +#define F_ARPLUTPERR V_ARPLUTPERR(1U) + +#define S_CMCACHEPERR 24 +#define V_CMCACHEPERR(x) ((x) << S_CMCACHEPERR) +#define F_CMCACHEPERR V_CMCACHEPERR(1U) + +#define A_TP_INT_CAUSE 0x474 + +#define A_TP_TX_MOD_Q1_Q0_RATE_LIMIT 0x8 + +#define A_TP_TX_DROP_CFG_CH0 0x12b + +#define A_TP_TX_DROP_MODE 0x12f + +#define A_TP_EGRESS_CONFIG 0x145 + +#define S_REWRITEFORCETOSIZE 0 +#define V_REWRITEFORCETOSIZE(x) ((x) << S_REWRITEFORCETOSIZE) +#define F_REWRITEFORCETOSIZE V_REWRITEFORCETOSIZE(1U) + +#define A_TP_TX_TRC_KEY0 0x20 + +#define A_TP_RX_TRC_KEY0 0x120 + +#define A_TP_TX_DROP_CNT_CH0 0x12d + +#define S_TXDROPCNTCH0RCVD 0 +#define M_TXDROPCNTCH0RCVD 0xffff +#define V_TXDROPCNTCH0RCVD(x) ((x) << S_TXDROPCNTCH0RCVD) +#define G_TXDROPCNTCH0RCVD(x) (((x) >> S_TXDROPCNTCH0RCVD) & \ + M_TXDROPCNTCH0RCVD) + +#define A_TP_PROXY_FLOW_CNTL 0x4b0 + +#define A_TP_EMBED_OP_FIELD0 0x4e8 +#define A_TP_EMBED_OP_FIELD1 0x4ec +#define A_TP_EMBED_OP_FIELD2 0x4f0 +#define A_TP_EMBED_OP_FIELD3 0x4f4 +#define A_TP_EMBED_OP_FIELD4 0x4f8 +#define A_TP_EMBED_OP_FIELD5 0x4fc + +#define A_ULPRX_CTL 0x500 + +#define S_ROUND_ROBIN 4 +#define V_ROUND_ROBIN(x) ((x) << S_ROUND_ROBIN) +#define F_ROUND_ROBIN V_ROUND_ROBIN(1U) + +#define A_ULPRX_INT_ENABLE 0x504 + +#define S_DATASELFRAMEERR0 7 +#define V_DATASELFRAMEERR0(x) ((x) << S_DATASELFRAMEERR0) +#define F_DATASELFRAMEERR0 V_DATASELFRAMEERR0(1U) + +#define S_DATASELFRAMEERR1 6 +#define V_DATASELFRAMEERR1(x) ((x) << S_DATASELFRAMEERR1) +#define F_DATASELFRAMEERR1 V_DATASELFRAMEERR1(1U) + +#define S_PCMDMUXPERR 5 +#define V_PCMDMUXPERR(x) ((x) << S_PCMDMUXPERR) +#define F_PCMDMUXPERR V_PCMDMUXPERR(1U) + +#define S_ARBFPERR 4 +#define V_ARBFPERR(x) ((x) << S_ARBFPERR) +#define F_ARBFPERR V_ARBFPERR(1U) + +#define S_ARBPF0PERR 3 +#define V_ARBPF0PERR(x) ((x) << S_ARBPF0PERR) +#define F_ARBPF0PERR V_ARBPF0PERR(1U) + +#define S_ARBPF1PERR 2 +#define V_ARBPF1PERR(x) ((x) << S_ARBPF1PERR) +#define F_ARBPF1PERR V_ARBPF1PERR(1U) + +#define S_PARERRPCMD 1 +#define V_PARERRPCMD(x) ((x) << S_PARERRPCMD) +#define F_PARERRPCMD V_PARERRPCMD(1U) + +#define S_PARERRDATA 0 +#define V_PARERRDATA(x) ((x) << S_PARERRDATA) +#define F_PARERRDATA V_PARERRDATA(1U) + +#define A_ULPRX_INT_CAUSE 0x508 + +#define A_ULPRX_ISCSI_LLIMIT 0x50c + +#define A_ULPRX_ISCSI_ULIMIT 0x510 + +#define A_ULPRX_ISCSI_TAGMASK 0x514 + +#define A_ULPRX_ISCSI_PSZ 0x518 + +#define A_ULPRX_TDDP_LLIMIT 0x51c + +#define A_ULPRX_TDDP_ULIMIT 0x520 +#define A_ULPRX_TDDP_PSZ 0x528 + +#define S_HPZ0 0 +#define M_HPZ0 0xf +#define V_HPZ0(x) ((x) << S_HPZ0) +#define G_HPZ0(x) (((x) >> S_HPZ0) & M_HPZ0) + +#define A_ULPRX_STAG_LLIMIT 0x52c + +#define A_ULPRX_STAG_ULIMIT 0x530 + +#define A_ULPRX_RQ_LLIMIT 0x534 +#define A_ULPRX_RQ_LLIMIT 0x534 + +#define A_ULPRX_RQ_ULIMIT 0x538 +#define A_ULPRX_RQ_ULIMIT 0x538 + +#define A_ULPRX_PBL_LLIMIT 0x53c + +#define A_ULPRX_PBL_ULIMIT 0x540 +#define A_ULPRX_PBL_ULIMIT 0x540 + +#define A_ULPRX_TDDP_TAGMASK 0x524 + +#define A_ULPRX_RQ_LLIMIT 0x534 +#define A_ULPRX_RQ_LLIMIT 0x534 + +#define A_ULPRX_RQ_ULIMIT 0x538 +#define A_ULPRX_RQ_ULIMIT 0x538 + +#define A_ULPRX_PBL_ULIMIT 0x540 +#define A_ULPRX_PBL_ULIMIT 0x540 + +#define A_ULPTX_CONFIG 0x580 + +#define S_CFG_CQE_SOP_MASK 1 +#define V_CFG_CQE_SOP_MASK(x) ((x) << S_CFG_CQE_SOP_MASK) +#define F_CFG_CQE_SOP_MASK V_CFG_CQE_SOP_MASK(1U) + +#define S_CFG_RR_ARB 0 +#define V_CFG_RR_ARB(x) ((x) << S_CFG_RR_ARB) +#define F_CFG_RR_ARB V_CFG_RR_ARB(1U) + +#define A_ULPTX_INT_ENABLE 0x584 + +#define S_PBL_BOUND_ERR_CH1 1 +#define V_PBL_BOUND_ERR_CH1(x) ((x) << S_PBL_BOUND_ERR_CH1) +#define F_PBL_BOUND_ERR_CH1 V_PBL_BOUND_ERR_CH1(1U) + +#define S_PBL_BOUND_ERR_CH0 0 +#define V_PBL_BOUND_ERR_CH0(x) ((x) << S_PBL_BOUND_ERR_CH0) +#define F_PBL_BOUND_ERR_CH0 V_PBL_BOUND_ERR_CH0(1U) + +#define A_ULPTX_INT_CAUSE 0x588 + +#define A_ULPTX_TPT_LLIMIT 0x58c + +#define A_ULPTX_TPT_ULIMIT 0x590 + +#define A_ULPTX_PBL_LLIMIT 0x594 + +#define A_ULPTX_PBL_ULIMIT 0x598 + +#define A_ULPTX_DMA_WEIGHT 0x5ac + +#define S_D1_WEIGHT 16 +#define M_D1_WEIGHT 0xffff +#define V_D1_WEIGHT(x) ((x) << S_D1_WEIGHT) + +#define S_D0_WEIGHT 0 +#define M_D0_WEIGHT 0xffff +#define V_D0_WEIGHT(x) ((x) << S_D0_WEIGHT) + +#define A_PM1_RX_CFG 0x5c0 +#define A_PM1_RX_MODE 0x5c4 + +#define A_PM1_RX_INT_ENABLE 0x5d8 + +#define S_ZERO_E_CMD_ERROR 18 +#define V_ZERO_E_CMD_ERROR(x) ((x) << S_ZERO_E_CMD_ERROR) +#define F_ZERO_E_CMD_ERROR V_ZERO_E_CMD_ERROR(1U) + +#define S_IESPI0_FIFO2X_RX_FRAMING_ERROR 17 +#define V_IESPI0_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_IESPI0_FIFO2X_RX_FRAMING_ERROR) +#define F_IESPI0_FIFO2X_RX_FRAMING_ERROR V_IESPI0_FIFO2X_RX_FRAMING_ERROR(1U) + +#define S_IESPI1_FIFO2X_RX_FRAMING_ERROR 16 +#define V_IESPI1_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_IESPI1_FIFO2X_RX_FRAMING_ERROR) +#define F_IESPI1_FIFO2X_RX_FRAMING_ERROR V_IESPI1_FIFO2X_RX_FRAMING_ERROR(1U) + +#define S_IESPI0_RX_FRAMING_ERROR 15 +#define V_IESPI0_RX_FRAMING_ERROR(x) ((x) << S_IESPI0_RX_FRAMING_ERROR) +#define F_IESPI0_RX_FRAMING_ERROR V_IESPI0_RX_FRAMING_ERROR(1U) + +#define S_IESPI1_RX_FRAMING_ERROR 14 +#define V_IESPI1_RX_FRAMING_ERROR(x) ((x) << S_IESPI1_RX_FRAMING_ERROR) +#define F_IESPI1_RX_FRAMING_ERROR V_IESPI1_RX_FRAMING_ERROR(1U) + +#define S_IESPI0_TX_FRAMING_ERROR 13 +#define V_IESPI0_TX_FRAMING_ERROR(x) ((x) << S_IESPI0_TX_FRAMING_ERROR) +#define F_IESPI0_TX_FRAMING_ERROR V_IESPI0_TX_FRAMING_ERROR(1U) + +#define S_IESPI1_TX_FRAMING_ERROR 12 +#define V_IESPI1_TX_FRAMING_ERROR(x) ((x) << S_IESPI1_TX_FRAMING_ERROR) +#define F_IESPI1_TX_FRAMING_ERROR V_IESPI1_TX_FRAMING_ERROR(1U) + +#define S_OCSPI0_RX_FRAMING_ERROR 11 +#define V_OCSPI0_RX_FRAMING_ERROR(x) ((x) << S_OCSPI0_RX_FRAMING_ERROR) +#define F_OCSPI0_RX_FRAMING_ERROR V_OCSPI0_RX_FRAMING_ERROR(1U) + +#define S_OCSPI1_RX_FRAMING_ERROR 10 +#define V_OCSPI1_RX_FRAMING_ERROR(x) ((x) << S_OCSPI1_RX_FRAMING_ERROR) +#define F_OCSPI1_RX_FRAMING_ERROR V_OCSPI1_RX_FRAMING_ERROR(1U) + +#define S_OCSPI0_TX_FRAMING_ERROR 9 +#define V_OCSPI0_TX_FRAMING_ERROR(x) ((x) << S_OCSPI0_TX_FRAMING_ERROR) +#define F_OCSPI0_TX_FRAMING_ERROR V_OCSPI0_TX_FRAMING_ERROR(1U) + +#define S_OCSPI1_TX_FRAMING_ERROR 8 +#define V_OCSPI1_TX_FRAMING_ERROR(x) ((x) << S_OCSPI1_TX_FRAMING_ERROR) +#define F_OCSPI1_TX_FRAMING_ERROR V_OCSPI1_TX_FRAMING_ERROR(1U) + +#define S_OCSPI0_OFIFO2X_TX_FRAMING_ERROR 7 +#define V_OCSPI0_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OCSPI0_OFIFO2X_TX_FRAMING_ERROR) +#define F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR V_OCSPI0_OFIFO2X_TX_FRAMING_ERROR(1U) + +#define S_OCSPI1_OFIFO2X_TX_FRAMING_ERROR 6 +#define V_OCSPI1_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OCSPI1_OFIFO2X_TX_FRAMING_ERROR) +#define F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR V_OCSPI1_OFIFO2X_TX_FRAMING_ERROR(1U) + +#define S_IESPI_PAR_ERROR 3 +#define M_IESPI_PAR_ERROR 0x7 + +#define V_IESPI_PAR_ERROR(x) ((x) << S_IESPI_PAR_ERROR) + +#define S_OCSPI_PAR_ERROR 0 +#define M_OCSPI_PAR_ERROR 0x7 + +#define V_OCSPI_PAR_ERROR(x) ((x) << S_OCSPI_PAR_ERROR) + +#define A_PM1_RX_INT_CAUSE 0x5dc + +#define A_PM1_TX_CFG 0x5e0 +#define A_PM1_TX_MODE 0x5e4 + +#define A_PM1_TX_INT_ENABLE 0x5f8 + +#define S_ZERO_C_CMD_ERROR 18 +#define V_ZERO_C_CMD_ERROR(x) ((x) << S_ZERO_C_CMD_ERROR) +#define F_ZERO_C_CMD_ERROR V_ZERO_C_CMD_ERROR(1U) + +#define S_ICSPI0_FIFO2X_RX_FRAMING_ERROR 17 +#define V_ICSPI0_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_ICSPI0_FIFO2X_RX_FRAMING_ERROR) +#define F_ICSPI0_FIFO2X_RX_FRAMING_ERROR V_ICSPI0_FIFO2X_RX_FRAMING_ERROR(1U) + +#define S_ICSPI1_FIFO2X_RX_FRAMING_ERROR 16 +#define V_ICSPI1_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_ICSPI1_FIFO2X_RX_FRAMING_ERROR) +#define F_ICSPI1_FIFO2X_RX_FRAMING_ERROR V_ICSPI1_FIFO2X_RX_FRAMING_ERROR(1U) + +#define S_ICSPI0_RX_FRAMING_ERROR 15 +#define V_ICSPI0_RX_FRAMING_ERROR(x) ((x) << S_ICSPI0_RX_FRAMING_ERROR) +#define F_ICSPI0_RX_FRAMING_ERROR V_ICSPI0_RX_FRAMING_ERROR(1U) + +#define S_ICSPI1_RX_FRAMING_ERROR 14 +#define V_ICSPI1_RX_FRAMING_ERROR(x) ((x) << S_ICSPI1_RX_FRAMING_ERROR) +#define F_ICSPI1_RX_FRAMING_ERROR V_ICSPI1_RX_FRAMING_ERROR(1U) + +#define S_ICSPI0_TX_FRAMING_ERROR 13 +#define V_ICSPI0_TX_FRAMING_ERROR(x) ((x) << S_ICSPI0_TX_FRAMING_ERROR) +#define F_ICSPI0_TX_FRAMING_ERROR V_ICSPI0_TX_FRAMING_ERROR(1U) + +#define S_ICSPI1_TX_FRAMING_ERROR 12 +#define V_ICSPI1_TX_FRAMING_ERROR(x) ((x) << S_ICSPI1_TX_FRAMING_ERROR) +#define F_ICSPI1_TX_FRAMING_ERROR V_ICSPI1_TX_FRAMING_ERROR(1U) + +#define S_OESPI0_RX_FRAMING_ERROR 11 +#define V_OESPI0_RX_FRAMING_ERROR(x) ((x) << S_OESPI0_RX_FRAMING_ERROR) +#define F_OESPI0_RX_FRAMING_ERROR V_OESPI0_RX_FRAMING_ERROR(1U) + +#define S_OESPI1_RX_FRAMING_ERROR 10 +#define V_OESPI1_RX_FRAMING_ERROR(x) ((x) << S_OESPI1_RX_FRAMING_ERROR) +#define F_OESPI1_RX_FRAMING_ERROR V_OESPI1_RX_FRAMING_ERROR(1U) + +#define S_OESPI0_TX_FRAMING_ERROR 9 +#define V_OESPI0_TX_FRAMING_ERROR(x) ((x) << S_OESPI0_TX_FRAMING_ERROR) +#define F_OESPI0_TX_FRAMING_ERROR V_OESPI0_TX_FRAMING_ERROR(1U) + +#define S_OESPI1_TX_FRAMING_ERROR 8 +#define V_OESPI1_TX_FRAMING_ERROR(x) ((x) << S_OESPI1_TX_FRAMING_ERROR) +#define F_OESPI1_TX_FRAMING_ERROR V_OESPI1_TX_FRAMING_ERROR(1U) + +#define S_OESPI0_OFIFO2X_TX_FRAMING_ERROR 7 +#define V_OESPI0_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OESPI0_OFIFO2X_TX_FRAMING_ERROR) +#define F_OESPI0_OFIFO2X_TX_FRAMING_ERROR V_OESPI0_OFIFO2X_TX_FRAMING_ERROR(1U) + +#define S_OESPI1_OFIFO2X_TX_FRAMING_ERROR 6 +#define V_OESPI1_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OESPI1_OFIFO2X_TX_FRAMING_ERROR) +#define F_OESPI1_OFIFO2X_TX_FRAMING_ERROR V_OESPI1_OFIFO2X_TX_FRAMING_ERROR(1U) + +#define S_ICSPI_PAR_ERROR 3 +#define M_ICSPI_PAR_ERROR 0x7 + +#define V_ICSPI_PAR_ERROR(x) ((x) << S_ICSPI_PAR_ERROR) + +#define S_OESPI_PAR_ERROR 0 +#define M_OESPI_PAR_ERROR 0x7 + +#define V_OESPI_PAR_ERROR(x) ((x) << S_OESPI_PAR_ERROR) + +#define A_PM1_TX_INT_CAUSE 0x5fc + +#define A_MPS_CFG 0x600 + +#define S_TPRXPORTEN 4 +#define V_TPRXPORTEN(x) ((x) << S_TPRXPORTEN) +#define F_TPRXPORTEN V_TPRXPORTEN(1U) + +#define S_TPTXPORT1EN 3 +#define V_TPTXPORT1EN(x) ((x) << S_TPTXPORT1EN) +#define F_TPTXPORT1EN V_TPTXPORT1EN(1U) + +#define S_TPTXPORT0EN 2 +#define V_TPTXPORT0EN(x) ((x) << S_TPTXPORT0EN) +#define F_TPTXPORT0EN V_TPTXPORT0EN(1U) + +#define S_PORT1ACTIVE 1 +#define V_PORT1ACTIVE(x) ((x) << S_PORT1ACTIVE) +#define F_PORT1ACTIVE V_PORT1ACTIVE(1U) + +#define S_PORT0ACTIVE 0 +#define V_PORT0ACTIVE(x) ((x) << S_PORT0ACTIVE) +#define F_PORT0ACTIVE V_PORT0ACTIVE(1U) + +#define S_ENFORCEPKT 11 +#define V_ENFORCEPKT(x) ((x) << S_ENFORCEPKT) +#define F_ENFORCEPKT V_ENFORCEPKT(1U) + +#define A_MPS_INT_ENABLE 0x61c + +#define S_MCAPARERRENB 6 +#define M_MCAPARERRENB 0x7 + +#define V_MCAPARERRENB(x) ((x) << S_MCAPARERRENB) + +#define S_RXTPPARERRENB 4 +#define M_RXTPPARERRENB 0x3 + +#define V_RXTPPARERRENB(x) ((x) << S_RXTPPARERRENB) + +#define S_TX1TPPARERRENB 2 +#define M_TX1TPPARERRENB 0x3 + +#define V_TX1TPPARERRENB(x) ((x) << S_TX1TPPARERRENB) + +#define S_TX0TPPARERRENB 0 +#define M_TX0TPPARERRENB 0x3 + +#define V_TX0TPPARERRENB(x) ((x) << S_TX0TPPARERRENB) + +#define A_MPS_INT_CAUSE 0x620 + +#define S_MCAPARERR 6 +#define M_MCAPARERR 0x7 + +#define V_MCAPARERR(x) ((x) << S_MCAPARERR) + +#define S_RXTPPARERR 4 +#define M_RXTPPARERR 0x3 + +#define V_RXTPPARERR(x) ((x) << S_RXTPPARERR) + +#define S_TX1TPPARERR 2 +#define M_TX1TPPARERR 0x3 + +#define V_TX1TPPARERR(x) ((x) << S_TX1TPPARERR) + +#define S_TX0TPPARERR 0 +#define M_TX0TPPARERR 0x3 + +#define V_TX0TPPARERR(x) ((x) << S_TX0TPPARERR) + +#define A_CPL_SWITCH_CNTRL 0x640 + +#define A_CPL_INTR_ENABLE 0x650 + +#define S_CIM_OP_MAP_PERR 5 +#define V_CIM_OP_MAP_PERR(x) ((x) << S_CIM_OP_MAP_PERR) +#define F_CIM_OP_MAP_PERR V_CIM_OP_MAP_PERR(1U) + +#define S_CIM_OVFL_ERROR 4 +#define V_CIM_OVFL_ERROR(x) ((x) << S_CIM_OVFL_ERROR) +#define F_CIM_OVFL_ERROR V_CIM_OVFL_ERROR(1U) + +#define S_TP_FRAMING_ERROR 3 +#define V_TP_FRAMING_ERROR(x) ((x) << S_TP_FRAMING_ERROR) +#define F_TP_FRAMING_ERROR V_TP_FRAMING_ERROR(1U) + +#define S_SGE_FRAMING_ERROR 2 +#define V_SGE_FRAMING_ERROR(x) ((x) << S_SGE_FRAMING_ERROR) +#define F_SGE_FRAMING_ERROR V_SGE_FRAMING_ERROR(1U) + +#define S_CIM_FRAMING_ERROR 1 +#define V_CIM_FRAMING_ERROR(x) ((x) << S_CIM_FRAMING_ERROR) +#define F_CIM_FRAMING_ERROR V_CIM_FRAMING_ERROR(1U) + +#define S_ZERO_SWITCH_ERROR 0 +#define V_ZERO_SWITCH_ERROR(x) ((x) << S_ZERO_SWITCH_ERROR) +#define F_ZERO_SWITCH_ERROR V_ZERO_SWITCH_ERROR(1U) + +#define A_CPL_INTR_CAUSE 0x654 + +#define A_CPL_MAP_TBL_DATA 0x65c + +#define A_SMB_GLOBAL_TIME_CFG 0x660 + +#define A_I2C_CFG 0x6a0 + +#define S_I2C_CLKDIV 0 +#define M_I2C_CLKDIV 0xfff +#define V_I2C_CLKDIV(x) ((x) << S_I2C_CLKDIV) + +#define A_MI1_CFG 0x6b0 + +#define S_CLKDIV 5 +#define M_CLKDIV 0xff +#define V_CLKDIV(x) ((x) << S_CLKDIV) + +#define S_ST 3 + +#define M_ST 0x3 + +#define V_ST(x) ((x) << S_ST) + +#define G_ST(x) (((x) >> S_ST) & M_ST) + +#define S_PREEN 2 +#define V_PREEN(x) ((x) << S_PREEN) +#define F_PREEN V_PREEN(1U) + +#define S_MDIINV 1 +#define V_MDIINV(x) ((x) << S_MDIINV) +#define F_MDIINV V_MDIINV(1U) + +#define S_MDIEN 0 +#define V_MDIEN(x) ((x) << S_MDIEN) +#define F_MDIEN V_MDIEN(1U) + +#define A_MI1_ADDR 0x6b4 + +#define S_PHYADDR 5 +#define M_PHYADDR 0x1f +#define V_PHYADDR(x) ((x) << S_PHYADDR) + +#define S_REGADDR 0 +#define M_REGADDR 0x1f +#define V_REGADDR(x) ((x) << S_REGADDR) + +#define A_MI1_DATA 0x6b8 + +#define A_MI1_OP 0x6bc + +#define S_MDI_OP 0 +#define M_MDI_OP 0x3 +#define V_MDI_OP(x) ((x) << S_MDI_OP) + +#define A_SF_DATA 0x6d8 + +#define A_SF_OP 0x6dc + +#define S_BYTECNT 1 +#define M_BYTECNT 0x3 +#define V_BYTECNT(x) ((x) << S_BYTECNT) + +#define A_PL_INT_ENABLE0 0x6e0 + +#define S_T3DBG 23 +#define V_T3DBG(x) ((x) << S_T3DBG) +#define F_T3DBG V_T3DBG(1U) + +#define S_XGMAC0_1 20 +#define V_XGMAC0_1(x) ((x) << S_XGMAC0_1) +#define F_XGMAC0_1 V_XGMAC0_1(1U) + +#define S_XGMAC0_0 19 +#define V_XGMAC0_0(x) ((x) << S_XGMAC0_0) +#define F_XGMAC0_0 V_XGMAC0_0(1U) + +#define S_MC5A 18 +#define V_MC5A(x) ((x) << S_MC5A) +#define F_MC5A V_MC5A(1U) + +#define S_CPL_SWITCH 12 +#define V_CPL_SWITCH(x) ((x) << S_CPL_SWITCH) +#define F_CPL_SWITCH V_CPL_SWITCH(1U) + +#define S_MPS0 11 +#define V_MPS0(x) ((x) << S_MPS0) +#define F_MPS0 V_MPS0(1U) + +#define S_PM1_TX 10 +#define V_PM1_TX(x) ((x) << S_PM1_TX) +#define F_PM1_TX V_PM1_TX(1U) + +#define S_PM1_RX 9 +#define V_PM1_RX(x) ((x) << S_PM1_RX) +#define F_PM1_RX V_PM1_RX(1U) + +#define S_ULP2_TX 8 +#define V_ULP2_TX(x) ((x) << S_ULP2_TX) +#define F_ULP2_TX V_ULP2_TX(1U) + +#define S_ULP2_RX 7 +#define V_ULP2_RX(x) ((x) << S_ULP2_RX) +#define F_ULP2_RX V_ULP2_RX(1U) + +#define S_TP1 6 +#define V_TP1(x) ((x) << S_TP1) +#define F_TP1 V_TP1(1U) + +#define S_CIM 5 +#define V_CIM(x) ((x) << S_CIM) +#define F_CIM V_CIM(1U) + +#define S_MC7_CM 4 +#define V_MC7_CM(x) ((x) << S_MC7_CM) +#define F_MC7_CM V_MC7_CM(1U) + +#define S_MC7_PMTX 3 +#define V_MC7_PMTX(x) ((x) << S_MC7_PMTX) +#define F_MC7_PMTX V_MC7_PMTX(1U) + +#define S_MC7_PMRX 2 +#define V_MC7_PMRX(x) ((x) << S_MC7_PMRX) +#define F_MC7_PMRX V_MC7_PMRX(1U) + +#define S_PCIM0 1 +#define V_PCIM0(x) ((x) << S_PCIM0) +#define F_PCIM0 V_PCIM0(1U) + +#define S_SGE3 0 +#define V_SGE3(x) ((x) << S_SGE3) +#define F_SGE3 V_SGE3(1U) + +#define A_PL_INT_CAUSE0 0x6e4 + +#define A_PL_RST 0x6f0 + +#define S_FATALPERREN 4 +#define V_FATALPERREN(x) ((x) << S_FATALPERREN) +#define F_FATALPERREN V_FATALPERREN(1U) + +#define S_CRSTWRM 1 +#define V_CRSTWRM(x) ((x) << S_CRSTWRM) +#define F_CRSTWRM V_CRSTWRM(1U) + +#define A_PL_REV 0x6f4 + +#define A_PL_CLI 0x6f8 + +#define A_MC5_DB_CONFIG 0x704 + +#define S_TMTYPEHI 30 +#define V_TMTYPEHI(x) ((x) << S_TMTYPEHI) +#define F_TMTYPEHI V_TMTYPEHI(1U) + +#define S_TMPARTSIZE 28 +#define M_TMPARTSIZE 0x3 +#define V_TMPARTSIZE(x) ((x) << S_TMPARTSIZE) +#define G_TMPARTSIZE(x) (((x) >> S_TMPARTSIZE) & M_TMPARTSIZE) + +#define S_TMTYPE 26 +#define M_TMTYPE 0x3 +#define V_TMTYPE(x) ((x) << S_TMTYPE) +#define G_TMTYPE(x) (((x) >> S_TMTYPE) & M_TMTYPE) + +#define S_COMPEN 17 +#define V_COMPEN(x) ((x) << S_COMPEN) +#define F_COMPEN V_COMPEN(1U) + +#define S_PRTYEN 6 +#define V_PRTYEN(x) ((x) << S_PRTYEN) +#define F_PRTYEN V_PRTYEN(1U) + +#define S_MBUSEN 5 +#define V_MBUSEN(x) ((x) << S_MBUSEN) +#define F_MBUSEN V_MBUSEN(1U) + +#define S_DBGIEN 4 +#define V_DBGIEN(x) ((x) << S_DBGIEN) +#define F_DBGIEN V_DBGIEN(1U) + +#define S_TMRDY 2 +#define V_TMRDY(x) ((x) << S_TMRDY) +#define F_TMRDY V_TMRDY(1U) + +#define S_TMRST 1 +#define V_TMRST(x) ((x) << S_TMRST) +#define F_TMRST V_TMRST(1U) + +#define S_TMMODE 0 +#define V_TMMODE(x) ((x) << S_TMMODE) +#define F_TMMODE V_TMMODE(1U) + +#define F_TMMODE V_TMMODE(1U) + +#define A_MC5_DB_ROUTING_TABLE_INDEX 0x70c + +#define A_MC5_DB_FILTER_TABLE 0x710 + +#define A_MC5_DB_SERVER_INDEX 0x714 + +#define A_MC5_DB_RSP_LATENCY 0x720 + +#define S_RDLAT 16 +#define M_RDLAT 0x1f +#define V_RDLAT(x) ((x) << S_RDLAT) + +#define S_LRNLAT 8 +#define M_LRNLAT 0x1f +#define V_LRNLAT(x) ((x) << S_LRNLAT) + +#define S_SRCHLAT 0 +#define M_SRCHLAT 0x1f +#define V_SRCHLAT(x) ((x) << S_SRCHLAT) + +#define A_MC5_DB_PART_ID_INDEX 0x72c + +#define A_MC5_DB_INT_ENABLE 0x740 + +#define S_DELACTEMPTY 18 +#define V_DELACTEMPTY(x) ((x) << S_DELACTEMPTY) +#define F_DELACTEMPTY V_DELACTEMPTY(1U) + +#define S_DISPQPARERR 17 +#define V_DISPQPARERR(x) ((x) << S_DISPQPARERR) +#define F_DISPQPARERR V_DISPQPARERR(1U) + +#define S_REQQPARERR 16 +#define V_REQQPARERR(x) ((x) << S_REQQPARERR) +#define F_REQQPARERR V_REQQPARERR(1U) + +#define S_UNKNOWNCMD 15 +#define V_UNKNOWNCMD(x) ((x) << S_UNKNOWNCMD) +#define F_UNKNOWNCMD V_UNKNOWNCMD(1U) + +#define S_NFASRCHFAIL 8 +#define V_NFASRCHFAIL(x) ((x) << S_NFASRCHFAIL) +#define F_NFASRCHFAIL V_NFASRCHFAIL(1U) + +#define S_ACTRGNFULL 7 +#define V_ACTRGNFULL(x) ((x) << S_ACTRGNFULL) +#define F_ACTRGNFULL V_ACTRGNFULL(1U) + +#define S_PARITYERR 6 +#define V_PARITYERR(x) ((x) << S_PARITYERR) +#define F_PARITYERR V_PARITYERR(1U) + +#define A_MC5_DB_INT_CAUSE 0x744 + +#define A_MC5_DB_DBGI_CONFIG 0x774 + +#define A_MC5_DB_DBGI_REQ_CMD 0x778 + +#define A_MC5_DB_DBGI_REQ_ADDR0 0x77c + +#define A_MC5_DB_DBGI_REQ_ADDR1 0x780 + +#define A_MC5_DB_DBGI_REQ_ADDR2 0x784 + +#define A_MC5_DB_DBGI_REQ_DATA0 0x788 + +#define A_MC5_DB_DBGI_REQ_DATA1 0x78c + +#define A_MC5_DB_DBGI_REQ_DATA2 0x790 + +#define A_MC5_DB_DBGI_RSP_STATUS 0x7b0 + +#define S_DBGIRSPVALID 0 +#define V_DBGIRSPVALID(x) ((x) << S_DBGIRSPVALID) +#define F_DBGIRSPVALID V_DBGIRSPVALID(1U) + +#define A_MC5_DB_DBGI_RSP_DATA0 0x7b4 + +#define A_MC5_DB_DBGI_RSP_DATA1 0x7b8 + +#define A_MC5_DB_DBGI_RSP_DATA2 0x7bc + +#define A_MC5_DB_POPEN_DATA_WR_CMD 0x7cc + +#define A_MC5_DB_POPEN_MASK_WR_CMD 0x7d0 + +#define A_MC5_DB_AOPEN_SRCH_CMD 0x7d4 + +#define A_MC5_DB_AOPEN_LRN_CMD 0x7d8 + +#define A_MC5_DB_SYN_SRCH_CMD 0x7dc + +#define A_MC5_DB_SYN_LRN_CMD 0x7e0 + +#define A_MC5_DB_ACK_SRCH_CMD 0x7e4 + +#define A_MC5_DB_ACK_LRN_CMD 0x7e8 + +#define A_MC5_DB_ILOOKUP_CMD 0x7ec + +#define A_MC5_DB_ELOOKUP_CMD 0x7f0 + +#define A_MC5_DB_DATA_WRITE_CMD 0x7f4 + +#define A_MC5_DB_DATA_READ_CMD 0x7f8 + +#define XGMAC0_0_BASE_ADDR 0x800 + +#define A_XGM_TX_CTRL 0x800 + +#define S_TXEN 0 +#define V_TXEN(x) ((x) << S_TXEN) +#define F_TXEN V_TXEN(1U) + +#define A_XGM_TX_CFG 0x804 + +#define S_TXPAUSEEN 0 +#define V_TXPAUSEEN(x) ((x) << S_TXPAUSEEN) +#define F_TXPAUSEEN V_TXPAUSEEN(1U) + +#define A_XGM_TX_PAUSE_QUANTA 0x808 + +#define A_XGM_RX_CTRL 0x80c + +#define S_RXEN 0 +#define V_RXEN(x) ((x) << S_RXEN) +#define F_RXEN V_RXEN(1U) + +#define A_XGM_RX_CFG 0x810 + +#define S_DISPAUSEFRAMES 9 +#define V_DISPAUSEFRAMES(x) ((x) << S_DISPAUSEFRAMES) +#define F_DISPAUSEFRAMES V_DISPAUSEFRAMES(1U) + +#define S_EN1536BFRAMES 8 +#define V_EN1536BFRAMES(x) ((x) << S_EN1536BFRAMES) +#define F_EN1536BFRAMES V_EN1536BFRAMES(1U) + +#define S_ENJUMBO 7 +#define V_ENJUMBO(x) ((x) << S_ENJUMBO) +#define F_ENJUMBO V_ENJUMBO(1U) + +#define S_RMFCS 6 +#define V_RMFCS(x) ((x) << S_RMFCS) +#define F_RMFCS V_RMFCS(1U) + +#define S_ENHASHMCAST 2 +#define V_ENHASHMCAST(x) ((x) << S_ENHASHMCAST) +#define F_ENHASHMCAST V_ENHASHMCAST(1U) + +#define S_COPYALLFRAMES 0 +#define V_COPYALLFRAMES(x) ((x) << S_COPYALLFRAMES) +#define F_COPYALLFRAMES V_COPYALLFRAMES(1U) + +#define S_DISBCAST 1 +#define V_DISBCAST(x) ((x) << S_DISBCAST) +#define F_DISBCAST V_DISBCAST(1U) + +#define A_XGM_RX_HASH_LOW 0x814 + +#define A_XGM_RX_HASH_HIGH 0x818 + +#define A_XGM_RX_EXACT_MATCH_LOW_1 0x81c + +#define A_XGM_RX_EXACT_MATCH_HIGH_1 0x820 + +#define A_XGM_RX_EXACT_MATCH_LOW_2 0x824 + +#define A_XGM_RX_EXACT_MATCH_LOW_3 0x82c + +#define A_XGM_RX_EXACT_MATCH_LOW_4 0x834 + +#define A_XGM_RX_EXACT_MATCH_LOW_5 0x83c + +#define A_XGM_RX_EXACT_MATCH_LOW_6 0x844 + +#define A_XGM_RX_EXACT_MATCH_LOW_7 0x84c + +#define A_XGM_RX_EXACT_MATCH_LOW_8 0x854 + +#define A_XGM_INT_STATUS 0x86c + +#define S_LINKFAULTCHANGE 9 +#define V_LINKFAULTCHANGE(x) ((x) << S_LINKFAULTCHANGE) +#define F_LINKFAULTCHANGE V_LINKFAULTCHANGE(1U) + +#define A_XGM_XGM_INT_ENABLE 0x874 +#define A_XGM_XGM_INT_DISABLE 0x878 + +#define A_XGM_STAT_CTRL 0x880 + +#define S_CLRSTATS 2 +#define V_CLRSTATS(x) ((x) << S_CLRSTATS) +#define F_CLRSTATS V_CLRSTATS(1U) + +#define A_XGM_RXFIFO_CFG 0x884 + +#define S_RXFIFO_EMPTY 31 +#define V_RXFIFO_EMPTY(x) ((x) << S_RXFIFO_EMPTY) +#define F_RXFIFO_EMPTY V_RXFIFO_EMPTY(1U) + +#define S_RXFIFOPAUSEHWM 17 +#define M_RXFIFOPAUSEHWM 0xfff + +#define V_RXFIFOPAUSEHWM(x) ((x) << S_RXFIFOPAUSEHWM) + +#define G_RXFIFOPAUSEHWM(x) (((x) >> S_RXFIFOPAUSEHWM) & M_RXFIFOPAUSEHWM) + +#define S_RXFIFOPAUSELWM 5 +#define M_RXFIFOPAUSELWM 0xfff + +#define V_RXFIFOPAUSELWM(x) ((x) << S_RXFIFOPAUSELWM) + +#define G_RXFIFOPAUSELWM(x) (((x) >> S_RXFIFOPAUSELWM) & M_RXFIFOPAUSELWM) + +#define S_RXSTRFRWRD 1 +#define V_RXSTRFRWRD(x) ((x) << S_RXSTRFRWRD) +#define F_RXSTRFRWRD V_RXSTRFRWRD(1U) + +#define S_DISERRFRAMES 0 +#define V_DISERRFRAMES(x) ((x) << S_DISERRFRAMES) +#define F_DISERRFRAMES V_DISERRFRAMES(1U) + +#define A_XGM_TXFIFO_CFG 0x888 + +#define S_UNDERUNFIX 22 +#define V_UNDERUNFIX(x) ((x) << S_UNDERUNFIX) +#define F_UNDERUNFIX V_UNDERUNFIX(1U) + +#define S_TXIPG 13 +#define M_TXIPG 0xff +#define V_TXIPG(x) ((x) << S_TXIPG) +#define G_TXIPG(x) (((x) >> S_TXIPG) & M_TXIPG) + +#define S_TXFIFOTHRESH 4 +#define M_TXFIFOTHRESH 0x1ff + +#define V_TXFIFOTHRESH(x) ((x) << S_TXFIFOTHRESH) + +#define S_ENDROPPKT 21 +#define V_ENDROPPKT(x) ((x) << S_ENDROPPKT) +#define F_ENDROPPKT V_ENDROPPKT(1U) + +#define A_XGM_SERDES_CTRL 0x890 +#define A_XGM_SERDES_CTRL0 0x8e0 + +#define S_SERDESRESET_ 24 +#define V_SERDESRESET_(x) ((x) << S_SERDESRESET_) +#define F_SERDESRESET_ V_SERDESRESET_(1U) + +#define S_RXENABLE 4 +#define V_RXENABLE(x) ((x) << S_RXENABLE) +#define F_RXENABLE V_RXENABLE(1U) + +#define S_TXENABLE 3 +#define V_TXENABLE(x) ((x) << S_TXENABLE) +#define F_TXENABLE V_TXENABLE(1U) + +#define A_XGM_PAUSE_TIMER 0x890 + +#define A_XGM_RGMII_IMP 0x89c + +#define S_XGM_IMPSETUPDATE 6 +#define V_XGM_IMPSETUPDATE(x) ((x) << S_XGM_IMPSETUPDATE) +#define F_XGM_IMPSETUPDATE V_XGM_IMPSETUPDATE(1U) + +#define S_RGMIIIMPPD 3 +#define M_RGMIIIMPPD 0x7 +#define V_RGMIIIMPPD(x) ((x) << S_RGMIIIMPPD) + +#define S_RGMIIIMPPU 0 +#define M_RGMIIIMPPU 0x7 +#define V_RGMIIIMPPU(x) ((x) << S_RGMIIIMPPU) + +#define S_CALRESET 8 +#define V_CALRESET(x) ((x) << S_CALRESET) +#define F_CALRESET V_CALRESET(1U) + +#define S_CALUPDATE 7 +#define V_CALUPDATE(x) ((x) << S_CALUPDATE) +#define F_CALUPDATE V_CALUPDATE(1U) + +#define A_XGM_XAUI_IMP 0x8a0 + +#define S_CALBUSY 31 +#define V_CALBUSY(x) ((x) << S_CALBUSY) +#define F_CALBUSY V_CALBUSY(1U) + +#define S_XGM_CALFAULT 29 +#define V_XGM_CALFAULT(x) ((x) << S_XGM_CALFAULT) +#define F_XGM_CALFAULT V_XGM_CALFAULT(1U) + +#define S_CALIMP 24 +#define M_CALIMP 0x1f +#define V_CALIMP(x) ((x) << S_CALIMP) +#define G_CALIMP(x) (((x) >> S_CALIMP) & M_CALIMP) + +#define S_XAUIIMP 0 +#define M_XAUIIMP 0x7 +#define V_XAUIIMP(x) ((x) << S_XAUIIMP) + +#define A_XGM_RX_MAX_PKT_SIZE 0x8a8 + +#define S_RXMAXFRAMERSIZE 17 +#define M_RXMAXFRAMERSIZE 0x3fff +#define V_RXMAXFRAMERSIZE(x) ((x) << S_RXMAXFRAMERSIZE) +#define G_RXMAXFRAMERSIZE(x) (((x) >> S_RXMAXFRAMERSIZE) & M_RXMAXFRAMERSIZE) + +#define S_RXENFRAMER 14 +#define V_RXENFRAMER(x) ((x) << S_RXENFRAMER) +#define F_RXENFRAMER V_RXENFRAMER(1U) + +#define S_RXMAXPKTSIZE 0 +#define M_RXMAXPKTSIZE 0x3fff +#define V_RXMAXPKTSIZE(x) ((x) << S_RXMAXPKTSIZE) +#define G_RXMAXPKTSIZE(x) (((x) >> S_RXMAXPKTSIZE) & M_RXMAXPKTSIZE) + +#define A_XGM_RESET_CTRL 0x8ac + +#define S_XGMAC_STOP_EN 4 +#define V_XGMAC_STOP_EN(x) ((x) << S_XGMAC_STOP_EN) +#define F_XGMAC_STOP_EN V_XGMAC_STOP_EN(1U) + +#define S_XG2G_RESET_ 3 +#define V_XG2G_RESET_(x) ((x) << S_XG2G_RESET_) +#define F_XG2G_RESET_ V_XG2G_RESET_(1U) + +#define S_RGMII_RESET_ 2 +#define V_RGMII_RESET_(x) ((x) << S_RGMII_RESET_) +#define F_RGMII_RESET_ V_RGMII_RESET_(1U) + +#define S_PCS_RESET_ 1 +#define V_PCS_RESET_(x) ((x) << S_PCS_RESET_) +#define F_PCS_RESET_ V_PCS_RESET_(1U) + +#define S_MAC_RESET_ 0 +#define V_MAC_RESET_(x) ((x) << S_MAC_RESET_) +#define F_MAC_RESET_ V_MAC_RESET_(1U) + +#define A_XGM_PORT_CFG 0x8b8 + +#define S_CLKDIVRESET_ 3 +#define V_CLKDIVRESET_(x) ((x) << S_CLKDIVRESET_) +#define F_CLKDIVRESET_ V_CLKDIVRESET_(1U) + +#define S_PORTSPEED 1 +#define M_PORTSPEED 0x3 + +#define V_PORTSPEED(x) ((x) << S_PORTSPEED) + +#define S_ENRGMII 0 +#define V_ENRGMII(x) ((x) << S_ENRGMII) +#define F_ENRGMII V_ENRGMII(1U) + +#define A_XGM_INT_ENABLE 0x8d4 + +#define S_TXFIFO_PRTY_ERR 17 +#define M_TXFIFO_PRTY_ERR 0x7 + +#define V_TXFIFO_PRTY_ERR(x) ((x) << S_TXFIFO_PRTY_ERR) + +#define S_RXFIFO_PRTY_ERR 14 +#define M_RXFIFO_PRTY_ERR 0x7 + +#define V_RXFIFO_PRTY_ERR(x) ((x) << S_RXFIFO_PRTY_ERR) + +#define S_TXFIFO_UNDERRUN 13 +#define V_TXFIFO_UNDERRUN(x) ((x) << S_TXFIFO_UNDERRUN) +#define F_TXFIFO_UNDERRUN V_TXFIFO_UNDERRUN(1U) + +#define S_RXFIFO_OVERFLOW 12 +#define V_RXFIFO_OVERFLOW(x) ((x) << S_RXFIFO_OVERFLOW) +#define F_RXFIFO_OVERFLOW V_RXFIFO_OVERFLOW(1U) + +#define S_SERDES_LOS 4 +#define M_SERDES_LOS 0xf + +#define V_SERDES_LOS(x) ((x) << S_SERDES_LOS) + +#define S_XAUIPCSCTCERR 3 +#define V_XAUIPCSCTCERR(x) ((x) << S_XAUIPCSCTCERR) +#define F_XAUIPCSCTCERR V_XAUIPCSCTCERR(1U) + +#define S_XAUIPCSALIGNCHANGE 2 +#define V_XAUIPCSALIGNCHANGE(x) ((x) << S_XAUIPCSALIGNCHANGE) +#define F_XAUIPCSALIGNCHANGE V_XAUIPCSALIGNCHANGE(1U) + +#define S_XGM_INT 0 +#define V_XGM_INT(x) ((x) << S_XGM_INT) +#define F_XGM_INT V_XGM_INT(1U) + +#define A_XGM_INT_CAUSE 0x8d8 + +#define A_XGM_XAUI_ACT_CTRL 0x8dc + +#define S_TXACTENABLE 1 +#define V_TXACTENABLE(x) ((x) << S_TXACTENABLE) +#define F_TXACTENABLE V_TXACTENABLE(1U) + +#define A_XGM_SERDES_CTRL0 0x8e0 + +#define S_RESET3 23 +#define V_RESET3(x) ((x) << S_RESET3) +#define F_RESET3 V_RESET3(1U) + +#define S_RESET2 22 +#define V_RESET2(x) ((x) << S_RESET2) +#define F_RESET2 V_RESET2(1U) + +#define S_RESET1 21 +#define V_RESET1(x) ((x) << S_RESET1) +#define F_RESET1 V_RESET1(1U) + +#define S_RESET0 20 +#define V_RESET0(x) ((x) << S_RESET0) +#define F_RESET0 V_RESET0(1U) + +#define S_PWRDN3 19 +#define V_PWRDN3(x) ((x) << S_PWRDN3) +#define F_PWRDN3 V_PWRDN3(1U) + +#define S_PWRDN2 18 +#define V_PWRDN2(x) ((x) << S_PWRDN2) +#define F_PWRDN2 V_PWRDN2(1U) + +#define S_PWRDN1 17 +#define V_PWRDN1(x) ((x) << S_PWRDN1) +#define F_PWRDN1 V_PWRDN1(1U) + +#define S_PWRDN0 16 +#define V_PWRDN0(x) ((x) << S_PWRDN0) +#define F_PWRDN0 V_PWRDN0(1U) + +#define S_RESETPLL23 15 +#define V_RESETPLL23(x) ((x) << S_RESETPLL23) +#define F_RESETPLL23 V_RESETPLL23(1U) + +#define S_RESETPLL01 14 +#define V_RESETPLL01(x) ((x) << S_RESETPLL01) +#define F_RESETPLL01 V_RESETPLL01(1U) + +#define A_XGM_SERDES_STAT0 0x8f0 +#define A_XGM_SERDES_STAT1 0x8f4 +#define A_XGM_SERDES_STAT2 0x8f8 + +#define S_LOWSIG0 0 +#define V_LOWSIG0(x) ((x) << S_LOWSIG0) +#define F_LOWSIG0 V_LOWSIG0(1U) + +#define A_XGM_SERDES_STAT3 0x8fc + +#define A_XGM_STAT_TX_BYTE_LOW 0x900 + +#define A_XGM_STAT_TX_BYTE_HIGH 0x904 + +#define A_XGM_STAT_TX_FRAME_LOW 0x908 + +#define A_XGM_STAT_TX_FRAME_HIGH 0x90c + +#define A_XGM_STAT_TX_BCAST 0x910 + +#define A_XGM_STAT_TX_MCAST 0x914 + +#define A_XGM_STAT_TX_PAUSE 0x918 + +#define A_XGM_STAT_TX_64B_FRAMES 0x91c + +#define A_XGM_STAT_TX_65_127B_FRAMES 0x920 + +#define A_XGM_STAT_TX_128_255B_FRAMES 0x924 + +#define A_XGM_STAT_TX_256_511B_FRAMES 0x928 + +#define A_XGM_STAT_TX_512_1023B_FRAMES 0x92c + +#define A_XGM_STAT_TX_1024_1518B_FRAMES 0x930 + +#define A_XGM_STAT_TX_1519_MAXB_FRAMES 0x934 + +#define A_XGM_STAT_TX_ERR_FRAMES 0x938 + +#define A_XGM_STAT_RX_BYTES_LOW 0x93c + +#define A_XGM_STAT_RX_BYTES_HIGH 0x940 + +#define A_XGM_STAT_RX_FRAMES_LOW 0x944 + +#define A_XGM_STAT_RX_FRAMES_HIGH 0x948 + +#define A_XGM_STAT_RX_BCAST_FRAMES 0x94c + +#define A_XGM_STAT_RX_MCAST_FRAMES 0x950 + +#define A_XGM_STAT_RX_PAUSE_FRAMES 0x954 + +#define A_XGM_STAT_RX_64B_FRAMES 0x958 + +#define A_XGM_STAT_RX_65_127B_FRAMES 0x95c + +#define A_XGM_STAT_RX_128_255B_FRAMES 0x960 + +#define A_XGM_STAT_RX_256_511B_FRAMES 0x964 + +#define A_XGM_STAT_RX_512_1023B_FRAMES 0x968 + +#define A_XGM_STAT_RX_1024_1518B_FRAMES 0x96c + +#define A_XGM_STAT_RX_1519_MAXB_FRAMES 0x970 + +#define A_XGM_STAT_RX_SHORT_FRAMES 0x974 + +#define A_XGM_STAT_RX_OVERSIZE_FRAMES 0x978 + +#define A_XGM_STAT_RX_JABBER_FRAMES 0x97c + +#define A_XGM_STAT_RX_CRC_ERR_FRAMES 0x980 + +#define A_XGM_STAT_RX_LENGTH_ERR_FRAMES 0x984 + +#define A_XGM_STAT_RX_SYM_CODE_ERR_FRAMES 0x988 + +#define A_XGM_SERDES_STATUS0 0x98c + +#define A_XGM_SERDES_STATUS1 0x990 + +#define S_CMULOCK 31 +#define V_CMULOCK(x) ((x) << S_CMULOCK) +#define F_CMULOCK V_CMULOCK(1U) + +#define A_XGM_RX_MAX_PKT_SIZE_ERR_CNT 0x9a4 + +#define A_XGM_TX_SPI4_SOP_EOP_CNT 0x9a8 + +#define S_TXSPI4SOPCNT 16 +#define M_TXSPI4SOPCNT 0xffff +#define V_TXSPI4SOPCNT(x) ((x) << S_TXSPI4SOPCNT) +#define G_TXSPI4SOPCNT(x) (((x) >> S_TXSPI4SOPCNT) & M_TXSPI4SOPCNT) + +#define A_XGM_RX_SPI4_SOP_EOP_CNT 0x9ac + +#define XGMAC0_1_BASE_ADDR 0xa00 diff --git a/drivers/net/ethernet/chelsio/cxgb3/sge.c b/drivers/net/ethernet/chelsio/cxgb3/sge.c new file mode 100644 index 000000000000..d6fa1777a343 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb3/sge.c @@ -0,0 +1,3303 @@ +/* + * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "regs.h" +#include "sge_defs.h" +#include "t3_cpl.h" +#include "firmware_exports.h" +#include "cxgb3_offload.h" + +#define USE_GTS 0 + +#define SGE_RX_SM_BUF_SIZE 1536 + +#define SGE_RX_COPY_THRES 256 +#define SGE_RX_PULL_LEN 128 + +#define SGE_PG_RSVD SMP_CACHE_BYTES +/* + * Page chunk size for FL0 buffers if FL0 is to be populated with page chunks. + * It must be a divisor of PAGE_SIZE. If set to 0 FL0 will use sk_buffs + * directly. + */ +#define FL0_PG_CHUNK_SIZE 2048 +#define FL0_PG_ORDER 0 +#define FL0_PG_ALLOC_SIZE (PAGE_SIZE << FL0_PG_ORDER) +#define FL1_PG_CHUNK_SIZE (PAGE_SIZE > 8192 ? 16384 : 8192) +#define FL1_PG_ORDER (PAGE_SIZE > 8192 ? 0 : 1) +#define FL1_PG_ALLOC_SIZE (PAGE_SIZE << FL1_PG_ORDER) + +#define SGE_RX_DROP_THRES 16 +#define RX_RECLAIM_PERIOD (HZ/4) + +/* + * Max number of Rx buffers we replenish at a time. + */ +#define MAX_RX_REFILL 16U +/* + * Period of the Tx buffer reclaim timer. This timer does not need to run + * frequently as Tx buffers are usually reclaimed by new Tx packets. + */ +#define TX_RECLAIM_PERIOD (HZ / 4) +#define TX_RECLAIM_TIMER_CHUNK 64U +#define TX_RECLAIM_CHUNK 16U + +/* WR size in bytes */ +#define WR_LEN (WR_FLITS * 8) + +/* + * Types of Tx queues in each queue set. Order here matters, do not change. + */ +enum { TXQ_ETH, TXQ_OFLD, TXQ_CTRL }; + +/* Values for sge_txq.flags */ +enum { + TXQ_RUNNING = 1 << 0, /* fetch engine is running */ + TXQ_LAST_PKT_DB = 1 << 1, /* last packet rang the doorbell */ +}; + +struct tx_desc { + __be64 flit[TX_DESC_FLITS]; +}; + +struct rx_desc { + __be32 addr_lo; + __be32 len_gen; + __be32 gen2; + __be32 addr_hi; +}; + +struct tx_sw_desc { /* SW state per Tx descriptor */ + struct sk_buff *skb; + u8 eop; /* set if last descriptor for packet */ + u8 addr_idx; /* buffer index of first SGL entry in descriptor */ + u8 fragidx; /* first page fragment associated with descriptor */ + s8 sflit; /* start flit of first SGL entry in descriptor */ +}; + +struct rx_sw_desc { /* SW state per Rx descriptor */ + union { + struct sk_buff *skb; + struct fl_pg_chunk pg_chunk; + }; + DEFINE_DMA_UNMAP_ADDR(dma_addr); +}; + +struct rsp_desc { /* response queue descriptor */ + struct rss_header rss_hdr; + __be32 flags; + __be32 len_cq; + u8 imm_data[47]; + u8 intr_gen; +}; + +/* + * Holds unmapping information for Tx packets that need deferred unmapping. + * This structure lives at skb->head and must be allocated by callers. + */ +struct deferred_unmap_info { + struct pci_dev *pdev; + dma_addr_t addr[MAX_SKB_FRAGS + 1]; +}; + +/* + * Maps a number of flits to the number of Tx descriptors that can hold them. + * The formula is + * + * desc = 1 + (flits - 2) / (WR_FLITS - 1). + * + * HW allows up to 4 descriptors to be combined into a WR. + */ +static u8 flit_desc_map[] = { + 0, +#if SGE_NUM_GENBITS == 1 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 +#elif SGE_NUM_GENBITS == 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, +#else +# error "SGE_NUM_GENBITS must be 1 or 2" +#endif +}; + +static inline struct sge_qset *fl_to_qset(const struct sge_fl *q, int qidx) +{ + return container_of(q, struct sge_qset, fl[qidx]); +} + +static inline struct sge_qset *rspq_to_qset(const struct sge_rspq *q) +{ + return container_of(q, struct sge_qset, rspq); +} + +static inline struct sge_qset *txq_to_qset(const struct sge_txq *q, int qidx) +{ + return container_of(q, struct sge_qset, txq[qidx]); +} + +/** + * refill_rspq - replenish an SGE response queue + * @adapter: the adapter + * @q: the response queue to replenish + * @credits: how many new responses to make available + * + * Replenishes a response queue by making the supplied number of responses + * available to HW. + */ +static inline void refill_rspq(struct adapter *adapter, + const struct sge_rspq *q, unsigned int credits) +{ + rmb(); + t3_write_reg(adapter, A_SG_RSPQ_CREDIT_RETURN, + V_RSPQ(q->cntxt_id) | V_CREDITS(credits)); +} + +/** + * need_skb_unmap - does the platform need unmapping of sk_buffs? + * + * Returns true if the platform needs sk_buff unmapping. The compiler + * optimizes away unnecessary code if this returns true. + */ +static inline int need_skb_unmap(void) +{ +#ifdef CONFIG_NEED_DMA_MAP_STATE + return 1; +#else + return 0; +#endif +} + +/** + * unmap_skb - unmap a packet main body and its page fragments + * @skb: the packet + * @q: the Tx queue containing Tx descriptors for the packet + * @cidx: index of Tx descriptor + * @pdev: the PCI device + * + * Unmap the main body of an sk_buff and its page fragments, if any. + * Because of the fairly complicated structure of our SGLs and the desire + * to conserve space for metadata, the information necessary to unmap an + * sk_buff is spread across the sk_buff itself (buffer lengths), the HW Tx + * descriptors (the physical addresses of the various data buffers), and + * the SW descriptor state (assorted indices). The send functions + * initialize the indices for the first packet descriptor so we can unmap + * the buffers held in the first Tx descriptor here, and we have enough + * information at this point to set the state for the next Tx descriptor. + * + * Note that it is possible to clean up the first descriptor of a packet + * before the send routines have written the next descriptors, but this + * race does not cause any problem. We just end up writing the unmapping + * info for the descriptor first. + */ +static inline void unmap_skb(struct sk_buff *skb, struct sge_txq *q, + unsigned int cidx, struct pci_dev *pdev) +{ + const struct sg_ent *sgp; + struct tx_sw_desc *d = &q->sdesc[cidx]; + int nfrags, frag_idx, curflit, j = d->addr_idx; + + sgp = (struct sg_ent *)&q->desc[cidx].flit[d->sflit]; + frag_idx = d->fragidx; + + if (frag_idx == 0 && skb_headlen(skb)) { + pci_unmap_single(pdev, be64_to_cpu(sgp->addr[0]), + skb_headlen(skb), PCI_DMA_TODEVICE); + j = 1; + } + + curflit = d->sflit + 1 + j; + nfrags = skb_shinfo(skb)->nr_frags; + + while (frag_idx < nfrags && curflit < WR_FLITS) { + pci_unmap_page(pdev, be64_to_cpu(sgp->addr[j]), + skb_shinfo(skb)->frags[frag_idx].size, + PCI_DMA_TODEVICE); + j ^= 1; + if (j == 0) { + sgp++; + curflit++; + } + curflit++; + frag_idx++; + } + + if (frag_idx < nfrags) { /* SGL continues into next Tx descriptor */ + d = cidx + 1 == q->size ? q->sdesc : d + 1; + d->fragidx = frag_idx; + d->addr_idx = j; + d->sflit = curflit - WR_FLITS - j; /* sflit can be -1 */ + } +} + +/** + * free_tx_desc - reclaims Tx descriptors and their buffers + * @adapter: the adapter + * @q: the Tx queue to reclaim descriptors from + * @n: the number of descriptors to reclaim + * + * Reclaims Tx descriptors from an SGE Tx queue and frees the associated + * Tx buffers. Called with the Tx queue lock held. + */ +static void free_tx_desc(struct adapter *adapter, struct sge_txq *q, + unsigned int n) +{ + struct tx_sw_desc *d; + struct pci_dev *pdev = adapter->pdev; + unsigned int cidx = q->cidx; + + const int need_unmap = need_skb_unmap() && + q->cntxt_id >= FW_TUNNEL_SGEEC_START; + + d = &q->sdesc[cidx]; + while (n--) { + if (d->skb) { /* an SGL is present */ + if (need_unmap) + unmap_skb(d->skb, q, cidx, pdev); + if (d->eop) { + kfree_skb(d->skb); + d->skb = NULL; + } + } + ++d; + if (++cidx == q->size) { + cidx = 0; + d = q->sdesc; + } + } + q->cidx = cidx; +} + +/** + * reclaim_completed_tx - reclaims completed Tx descriptors + * @adapter: the adapter + * @q: the Tx queue to reclaim completed descriptors from + * @chunk: maximum number of descriptors to reclaim + * + * Reclaims Tx descriptors that the SGE has indicated it has processed, + * and frees the associated buffers if possible. Called with the Tx + * queue's lock held. + */ +static inline unsigned int reclaim_completed_tx(struct adapter *adapter, + struct sge_txq *q, + unsigned int chunk) +{ + unsigned int reclaim = q->processed - q->cleaned; + + reclaim = min(chunk, reclaim); + if (reclaim) { + free_tx_desc(adapter, q, reclaim); + q->cleaned += reclaim; + q->in_use -= reclaim; + } + return q->processed - q->cleaned; +} + +/** + * should_restart_tx - are there enough resources to restart a Tx queue? + * @q: the Tx queue + * + * Checks if there are enough descriptors to restart a suspended Tx queue. + */ +static inline int should_restart_tx(const struct sge_txq *q) +{ + unsigned int r = q->processed - q->cleaned; + + return q->in_use - r < (q->size >> 1); +} + +static void clear_rx_desc(struct pci_dev *pdev, const struct sge_fl *q, + struct rx_sw_desc *d) +{ + if (q->use_pages && d->pg_chunk.page) { + (*d->pg_chunk.p_cnt)--; + if (!*d->pg_chunk.p_cnt) + pci_unmap_page(pdev, + d->pg_chunk.mapping, + q->alloc_size, PCI_DMA_FROMDEVICE); + + put_page(d->pg_chunk.page); + d->pg_chunk.page = NULL; + } else { + pci_unmap_single(pdev, dma_unmap_addr(d, dma_addr), + q->buf_size, PCI_DMA_FROMDEVICE); + kfree_skb(d->skb); + d->skb = NULL; + } +} + +/** + * free_rx_bufs - free the Rx buffers on an SGE free list + * @pdev: the PCI device associated with the adapter + * @rxq: the SGE free list to clean up + * + * Release the buffers on an SGE free-buffer Rx queue. HW fetching from + * this queue should be stopped before calling this function. + */ +static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q) +{ + unsigned int cidx = q->cidx; + + while (q->credits--) { + struct rx_sw_desc *d = &q->sdesc[cidx]; + + + clear_rx_desc(pdev, q, d); + if (++cidx == q->size) + cidx = 0; + } + + if (q->pg_chunk.page) { + __free_pages(q->pg_chunk.page, q->order); + q->pg_chunk.page = NULL; + } +} + +/** + * add_one_rx_buf - add a packet buffer to a free-buffer list + * @va: buffer start VA + * @len: the buffer length + * @d: the HW Rx descriptor to write + * @sd: the SW Rx descriptor to write + * @gen: the generation bit value + * @pdev: the PCI device associated with the adapter + * + * Add a buffer of the given length to the supplied HW and SW Rx + * descriptors. + */ +static inline int add_one_rx_buf(void *va, unsigned int len, + struct rx_desc *d, struct rx_sw_desc *sd, + unsigned int gen, struct pci_dev *pdev) +{ + dma_addr_t mapping; + + mapping = pci_map_single(pdev, va, len, PCI_DMA_FROMDEVICE); + if (unlikely(pci_dma_mapping_error(pdev, mapping))) + return -ENOMEM; + + dma_unmap_addr_set(sd, dma_addr, mapping); + + d->addr_lo = cpu_to_be32(mapping); + d->addr_hi = cpu_to_be32((u64) mapping >> 32); + wmb(); + d->len_gen = cpu_to_be32(V_FLD_GEN1(gen)); + d->gen2 = cpu_to_be32(V_FLD_GEN2(gen)); + return 0; +} + +static inline int add_one_rx_chunk(dma_addr_t mapping, struct rx_desc *d, + unsigned int gen) +{ + d->addr_lo = cpu_to_be32(mapping); + d->addr_hi = cpu_to_be32((u64) mapping >> 32); + wmb(); + d->len_gen = cpu_to_be32(V_FLD_GEN1(gen)); + d->gen2 = cpu_to_be32(V_FLD_GEN2(gen)); + return 0; +} + +static int alloc_pg_chunk(struct adapter *adapter, struct sge_fl *q, + struct rx_sw_desc *sd, gfp_t gfp, + unsigned int order) +{ + if (!q->pg_chunk.page) { + dma_addr_t mapping; + + q->pg_chunk.page = alloc_pages(gfp, order); + if (unlikely(!q->pg_chunk.page)) + return -ENOMEM; + q->pg_chunk.va = page_address(q->pg_chunk.page); + q->pg_chunk.p_cnt = q->pg_chunk.va + (PAGE_SIZE << order) - + SGE_PG_RSVD; + q->pg_chunk.offset = 0; + mapping = pci_map_page(adapter->pdev, q->pg_chunk.page, + 0, q->alloc_size, PCI_DMA_FROMDEVICE); + q->pg_chunk.mapping = mapping; + } + sd->pg_chunk = q->pg_chunk; + + prefetch(sd->pg_chunk.p_cnt); + + q->pg_chunk.offset += q->buf_size; + if (q->pg_chunk.offset == (PAGE_SIZE << order)) + q->pg_chunk.page = NULL; + else { + q->pg_chunk.va += q->buf_size; + get_page(q->pg_chunk.page); + } + + if (sd->pg_chunk.offset == 0) + *sd->pg_chunk.p_cnt = 1; + else + *sd->pg_chunk.p_cnt += 1; + + return 0; +} + +static inline void ring_fl_db(struct adapter *adap, struct sge_fl *q) +{ + if (q->pend_cred >= q->credits / 4) { + q->pend_cred = 0; + wmb(); + t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id)); + } +} + +/** + * refill_fl - refill an SGE free-buffer list + * @adapter: the adapter + * @q: the free-list to refill + * @n: the number of new buffers to allocate + * @gfp: the gfp flags for allocating new buffers + * + * (Re)populate an SGE free-buffer list with up to @n new packet buffers, + * allocated with the supplied gfp flags. The caller must assure that + * @n does not exceed the queue's capacity. + */ +static int refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp) +{ + struct rx_sw_desc *sd = &q->sdesc[q->pidx]; + struct rx_desc *d = &q->desc[q->pidx]; + unsigned int count = 0; + + while (n--) { + dma_addr_t mapping; + int err; + + if (q->use_pages) { + if (unlikely(alloc_pg_chunk(adap, q, sd, gfp, + q->order))) { +nomem: q->alloc_failed++; + break; + } + mapping = sd->pg_chunk.mapping + sd->pg_chunk.offset; + dma_unmap_addr_set(sd, dma_addr, mapping); + + add_one_rx_chunk(mapping, d, q->gen); + pci_dma_sync_single_for_device(adap->pdev, mapping, + q->buf_size - SGE_PG_RSVD, + PCI_DMA_FROMDEVICE); + } else { + void *buf_start; + + struct sk_buff *skb = alloc_skb(q->buf_size, gfp); + if (!skb) + goto nomem; + + sd->skb = skb; + buf_start = skb->data; + err = add_one_rx_buf(buf_start, q->buf_size, d, sd, + q->gen, adap->pdev); + if (unlikely(err)) { + clear_rx_desc(adap->pdev, q, sd); + break; + } + } + + d++; + sd++; + if (++q->pidx == q->size) { + q->pidx = 0; + q->gen ^= 1; + sd = q->sdesc; + d = q->desc; + } + count++; + } + + q->credits += count; + q->pend_cred += count; + ring_fl_db(adap, q); + + return count; +} + +static inline void __refill_fl(struct adapter *adap, struct sge_fl *fl) +{ + refill_fl(adap, fl, min(MAX_RX_REFILL, fl->size - fl->credits), + GFP_ATOMIC | __GFP_COMP); +} + +/** + * recycle_rx_buf - recycle a receive buffer + * @adapter: the adapter + * @q: the SGE free list + * @idx: index of buffer to recycle + * + * Recycles the specified buffer on the given free list by adding it at + * the next available slot on the list. + */ +static void recycle_rx_buf(struct adapter *adap, struct sge_fl *q, + unsigned int idx) +{ + struct rx_desc *from = &q->desc[idx]; + struct rx_desc *to = &q->desc[q->pidx]; + + q->sdesc[q->pidx] = q->sdesc[idx]; + to->addr_lo = from->addr_lo; /* already big endian */ + to->addr_hi = from->addr_hi; /* likewise */ + wmb(); + to->len_gen = cpu_to_be32(V_FLD_GEN1(q->gen)); + to->gen2 = cpu_to_be32(V_FLD_GEN2(q->gen)); + + if (++q->pidx == q->size) { + q->pidx = 0; + q->gen ^= 1; + } + + q->credits++; + q->pend_cred++; + ring_fl_db(adap, q); +} + +/** + * alloc_ring - allocate resources for an SGE descriptor ring + * @pdev: the PCI device + * @nelem: the number of descriptors + * @elem_size: the size of each descriptor + * @sw_size: the size of the SW state associated with each ring element + * @phys: the physical address of the allocated ring + * @metadata: address of the array holding the SW state for the ring + * + * Allocates resources for an SGE descriptor ring, such as Tx queues, + * free buffer lists, or response queues. Each SGE ring requires + * space for its HW descriptors plus, optionally, space for the SW state + * associated with each HW entry (the metadata). The function returns + * three values: the virtual address for the HW ring (the return value + * of the function), the physical address of the HW ring, and the address + * of the SW ring. + */ +static void *alloc_ring(struct pci_dev *pdev, size_t nelem, size_t elem_size, + size_t sw_size, dma_addr_t * phys, void *metadata) +{ + size_t len = nelem * elem_size; + void *s = NULL; + void *p = dma_alloc_coherent(&pdev->dev, len, phys, GFP_KERNEL); + + if (!p) + return NULL; + if (sw_size && metadata) { + s = kcalloc(nelem, sw_size, GFP_KERNEL); + + if (!s) { + dma_free_coherent(&pdev->dev, len, p, *phys); + return NULL; + } + *(void **)metadata = s; + } + memset(p, 0, len); + return p; +} + +/** + * t3_reset_qset - reset a sge qset + * @q: the queue set + * + * Reset the qset structure. + * the NAPI structure is preserved in the event of + * the qset's reincarnation, for example during EEH recovery. + */ +static void t3_reset_qset(struct sge_qset *q) +{ + if (q->adap && + !(q->adap->flags & NAPI_INIT)) { + memset(q, 0, sizeof(*q)); + return; + } + + q->adap = NULL; + memset(&q->rspq, 0, sizeof(q->rspq)); + memset(q->fl, 0, sizeof(struct sge_fl) * SGE_RXQ_PER_SET); + memset(q->txq, 0, sizeof(struct sge_txq) * SGE_TXQ_PER_SET); + q->txq_stopped = 0; + q->tx_reclaim_timer.function = NULL; /* for t3_stop_sge_timers() */ + q->rx_reclaim_timer.function = NULL; + q->nomem = 0; + napi_free_frags(&q->napi); +} + + +/** + * free_qset - free the resources of an SGE queue set + * @adapter: the adapter owning the queue set + * @q: the queue set + * + * Release the HW and SW resources associated with an SGE queue set, such + * as HW contexts, packet buffers, and descriptor rings. Traffic to the + * queue set must be quiesced prior to calling this. + */ +static void t3_free_qset(struct adapter *adapter, struct sge_qset *q) +{ + int i; + struct pci_dev *pdev = adapter->pdev; + + for (i = 0; i < SGE_RXQ_PER_SET; ++i) + if (q->fl[i].desc) { + spin_lock_irq(&adapter->sge.reg_lock); + t3_sge_disable_fl(adapter, q->fl[i].cntxt_id); + spin_unlock_irq(&adapter->sge.reg_lock); + free_rx_bufs(pdev, &q->fl[i]); + kfree(q->fl[i].sdesc); + dma_free_coherent(&pdev->dev, + q->fl[i].size * + sizeof(struct rx_desc), q->fl[i].desc, + q->fl[i].phys_addr); + } + + for (i = 0; i < SGE_TXQ_PER_SET; ++i) + if (q->txq[i].desc) { + spin_lock_irq(&adapter->sge.reg_lock); + t3_sge_enable_ecntxt(adapter, q->txq[i].cntxt_id, 0); + spin_unlock_irq(&adapter->sge.reg_lock); + if (q->txq[i].sdesc) { + free_tx_desc(adapter, &q->txq[i], + q->txq[i].in_use); + kfree(q->txq[i].sdesc); + } + dma_free_coherent(&pdev->dev, + q->txq[i].size * + sizeof(struct tx_desc), + q->txq[i].desc, q->txq[i].phys_addr); + __skb_queue_purge(&q->txq[i].sendq); + } + + if (q->rspq.desc) { + spin_lock_irq(&adapter->sge.reg_lock); + t3_sge_disable_rspcntxt(adapter, q->rspq.cntxt_id); + spin_unlock_irq(&adapter->sge.reg_lock); + dma_free_coherent(&pdev->dev, + q->rspq.size * sizeof(struct rsp_desc), + q->rspq.desc, q->rspq.phys_addr); + } + + t3_reset_qset(q); +} + +/** + * init_qset_cntxt - initialize an SGE queue set context info + * @qs: the queue set + * @id: the queue set id + * + * Initializes the TIDs and context ids for the queues of a queue set. + */ +static void init_qset_cntxt(struct sge_qset *qs, unsigned int id) +{ + qs->rspq.cntxt_id = id; + qs->fl[0].cntxt_id = 2 * id; + qs->fl[1].cntxt_id = 2 * id + 1; + qs->txq[TXQ_ETH].cntxt_id = FW_TUNNEL_SGEEC_START + id; + qs->txq[TXQ_ETH].token = FW_TUNNEL_TID_START + id; + qs->txq[TXQ_OFLD].cntxt_id = FW_OFLD_SGEEC_START + id; + qs->txq[TXQ_CTRL].cntxt_id = FW_CTRL_SGEEC_START + id; + qs->txq[TXQ_CTRL].token = FW_CTRL_TID_START + id; +} + +/** + * sgl_len - calculates the size of an SGL of the given capacity + * @n: the number of SGL entries + * + * Calculates the number of flits needed for a scatter/gather list that + * can hold the given number of entries. + */ +static inline unsigned int sgl_len(unsigned int n) +{ + /* alternatively: 3 * (n / 2) + 2 * (n & 1) */ + return (3 * n) / 2 + (n & 1); +} + +/** + * flits_to_desc - returns the num of Tx descriptors for the given flits + * @n: the number of flits + * + * Calculates the number of Tx descriptors needed for the supplied number + * of flits. + */ +static inline unsigned int flits_to_desc(unsigned int n) +{ + BUG_ON(n >= ARRAY_SIZE(flit_desc_map)); + return flit_desc_map[n]; +} + +/** + * get_packet - return the next ingress packet buffer from a free list + * @adap: the adapter that received the packet + * @fl: the SGE free list holding the packet + * @len: the packet length including any SGE padding + * @drop_thres: # of remaining buffers before we start dropping packets + * + * Get the next packet from a free list and complete setup of the + * sk_buff. If the packet is small we make a copy and recycle the + * original buffer, otherwise we use the original buffer itself. If a + * positive drop threshold is supplied packets are dropped and their + * buffers recycled if (a) the number of remaining buffers is under the + * threshold and the packet is too big to copy, or (b) the packet should + * be copied but there is no memory for the copy. + */ +static struct sk_buff *get_packet(struct adapter *adap, struct sge_fl *fl, + unsigned int len, unsigned int drop_thres) +{ + struct sk_buff *skb = NULL; + struct rx_sw_desc *sd = &fl->sdesc[fl->cidx]; + + prefetch(sd->skb->data); + fl->credits--; + + if (len <= SGE_RX_COPY_THRES) { + skb = alloc_skb(len, GFP_ATOMIC); + if (likely(skb != NULL)) { + __skb_put(skb, len); + pci_dma_sync_single_for_cpu(adap->pdev, + dma_unmap_addr(sd, dma_addr), len, + PCI_DMA_FROMDEVICE); + memcpy(skb->data, sd->skb->data, len); + pci_dma_sync_single_for_device(adap->pdev, + dma_unmap_addr(sd, dma_addr), len, + PCI_DMA_FROMDEVICE); + } else if (!drop_thres) + goto use_orig_buf; +recycle: + recycle_rx_buf(adap, fl, fl->cidx); + return skb; + } + + if (unlikely(fl->credits < drop_thres) && + refill_fl(adap, fl, min(MAX_RX_REFILL, fl->size - fl->credits - 1), + GFP_ATOMIC | __GFP_COMP) == 0) + goto recycle; + +use_orig_buf: + pci_unmap_single(adap->pdev, dma_unmap_addr(sd, dma_addr), + fl->buf_size, PCI_DMA_FROMDEVICE); + skb = sd->skb; + skb_put(skb, len); + __refill_fl(adap, fl); + return skb; +} + +/** + * get_packet_pg - return the next ingress packet buffer from a free list + * @adap: the adapter that received the packet + * @fl: the SGE free list holding the packet + * @len: the packet length including any SGE padding + * @drop_thres: # of remaining buffers before we start dropping packets + * + * Get the next packet from a free list populated with page chunks. + * If the packet is small we make a copy and recycle the original buffer, + * otherwise we attach the original buffer as a page fragment to a fresh + * sk_buff. If a positive drop threshold is supplied packets are dropped + * and their buffers recycled if (a) the number of remaining buffers is + * under the threshold and the packet is too big to copy, or (b) there's + * no system memory. + * + * Note: this function is similar to @get_packet but deals with Rx buffers + * that are page chunks rather than sk_buffs. + */ +static struct sk_buff *get_packet_pg(struct adapter *adap, struct sge_fl *fl, + struct sge_rspq *q, unsigned int len, + unsigned int drop_thres) +{ + struct sk_buff *newskb, *skb; + struct rx_sw_desc *sd = &fl->sdesc[fl->cidx]; + + dma_addr_t dma_addr = dma_unmap_addr(sd, dma_addr); + + newskb = skb = q->pg_skb; + if (!skb && (len <= SGE_RX_COPY_THRES)) { + newskb = alloc_skb(len, GFP_ATOMIC); + if (likely(newskb != NULL)) { + __skb_put(newskb, len); + pci_dma_sync_single_for_cpu(adap->pdev, dma_addr, len, + PCI_DMA_FROMDEVICE); + memcpy(newskb->data, sd->pg_chunk.va, len); + pci_dma_sync_single_for_device(adap->pdev, dma_addr, + len, + PCI_DMA_FROMDEVICE); + } else if (!drop_thres) + return NULL; +recycle: + fl->credits--; + recycle_rx_buf(adap, fl, fl->cidx); + q->rx_recycle_buf++; + return newskb; + } + + if (unlikely(q->rx_recycle_buf || (!skb && fl->credits <= drop_thres))) + goto recycle; + + prefetch(sd->pg_chunk.p_cnt); + + if (!skb) + newskb = alloc_skb(SGE_RX_PULL_LEN, GFP_ATOMIC); + + if (unlikely(!newskb)) { + if (!drop_thres) + return NULL; + goto recycle; + } + + pci_dma_sync_single_for_cpu(adap->pdev, dma_addr, len, + PCI_DMA_FROMDEVICE); + (*sd->pg_chunk.p_cnt)--; + if (!*sd->pg_chunk.p_cnt && sd->pg_chunk.page != fl->pg_chunk.page) + pci_unmap_page(adap->pdev, + sd->pg_chunk.mapping, + fl->alloc_size, + PCI_DMA_FROMDEVICE); + if (!skb) { + __skb_put(newskb, SGE_RX_PULL_LEN); + memcpy(newskb->data, sd->pg_chunk.va, SGE_RX_PULL_LEN); + skb_fill_page_desc(newskb, 0, sd->pg_chunk.page, + sd->pg_chunk.offset + SGE_RX_PULL_LEN, + len - SGE_RX_PULL_LEN); + newskb->len = len; + newskb->data_len = len - SGE_RX_PULL_LEN; + newskb->truesize += newskb->data_len; + } else { + skb_fill_page_desc(newskb, skb_shinfo(newskb)->nr_frags, + sd->pg_chunk.page, + sd->pg_chunk.offset, len); + newskb->len += len; + newskb->data_len += len; + newskb->truesize += len; + } + + fl->credits--; + /* + * We do not refill FLs here, we let the caller do it to overlap a + * prefetch. + */ + return newskb; +} + +/** + * get_imm_packet - return the next ingress packet buffer from a response + * @resp: the response descriptor containing the packet data + * + * Return a packet containing the immediate data of the given response. + */ +static inline struct sk_buff *get_imm_packet(const struct rsp_desc *resp) +{ + struct sk_buff *skb = alloc_skb(IMMED_PKT_SIZE, GFP_ATOMIC); + + if (skb) { + __skb_put(skb, IMMED_PKT_SIZE); + skb_copy_to_linear_data(skb, resp->imm_data, IMMED_PKT_SIZE); + } + return skb; +} + +/** + * calc_tx_descs - calculate the number of Tx descriptors for a packet + * @skb: the packet + * + * Returns the number of Tx descriptors needed for the given Ethernet + * packet. Ethernet packets require addition of WR and CPL headers. + */ +static inline unsigned int calc_tx_descs(const struct sk_buff *skb) +{ + unsigned int flits; + + if (skb->len <= WR_LEN - sizeof(struct cpl_tx_pkt)) + return 1; + + flits = sgl_len(skb_shinfo(skb)->nr_frags + 1) + 2; + if (skb_shinfo(skb)->gso_size) + flits++; + return flits_to_desc(flits); +} + +/** + * make_sgl - populate a scatter/gather list for a packet + * @skb: the packet + * @sgp: the SGL to populate + * @start: start address of skb main body data to include in the SGL + * @len: length of skb main body data to include in the SGL + * @pdev: the PCI device + * + * Generates a scatter/gather list for the buffers that make up a packet + * and returns the SGL size in 8-byte words. The caller must size the SGL + * appropriately. + */ +static inline unsigned int make_sgl(const struct sk_buff *skb, + struct sg_ent *sgp, unsigned char *start, + unsigned int len, struct pci_dev *pdev) +{ + dma_addr_t mapping; + unsigned int i, j = 0, nfrags; + + if (len) { + mapping = pci_map_single(pdev, start, len, PCI_DMA_TODEVICE); + sgp->len[0] = cpu_to_be32(len); + sgp->addr[0] = cpu_to_be64(mapping); + j = 1; + } + + nfrags = skb_shinfo(skb)->nr_frags; + for (i = 0; i < nfrags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + mapping = pci_map_page(pdev, frag->page, frag->page_offset, + frag->size, PCI_DMA_TODEVICE); + sgp->len[j] = cpu_to_be32(frag->size); + sgp->addr[j] = cpu_to_be64(mapping); + j ^= 1; + if (j == 0) + ++sgp; + } + if (j) + sgp->len[j] = 0; + return ((nfrags + (len != 0)) * 3) / 2 + j; +} + +/** + * check_ring_tx_db - check and potentially ring a Tx queue's doorbell + * @adap: the adapter + * @q: the Tx queue + * + * Ring the doorbel if a Tx queue is asleep. There is a natural race, + * where the HW is going to sleep just after we checked, however, + * then the interrupt handler will detect the outstanding TX packet + * and ring the doorbell for us. + * + * When GTS is disabled we unconditionally ring the doorbell. + */ +static inline void check_ring_tx_db(struct adapter *adap, struct sge_txq *q) +{ +#if USE_GTS + clear_bit(TXQ_LAST_PKT_DB, &q->flags); + if (test_and_set_bit(TXQ_RUNNING, &q->flags) == 0) { + set_bit(TXQ_LAST_PKT_DB, &q->flags); + t3_write_reg(adap, A_SG_KDOORBELL, + F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); + } +#else + wmb(); /* write descriptors before telling HW */ + t3_write_reg(adap, A_SG_KDOORBELL, + F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); +#endif +} + +static inline void wr_gen2(struct tx_desc *d, unsigned int gen) +{ +#if SGE_NUM_GENBITS == 2 + d->flit[TX_DESC_FLITS - 1] = cpu_to_be64(gen); +#endif +} + +/** + * write_wr_hdr_sgl - write a WR header and, optionally, SGL + * @ndesc: number of Tx descriptors spanned by the SGL + * @skb: the packet corresponding to the WR + * @d: first Tx descriptor to be written + * @pidx: index of above descriptors + * @q: the SGE Tx queue + * @sgl: the SGL + * @flits: number of flits to the start of the SGL in the first descriptor + * @sgl_flits: the SGL size in flits + * @gen: the Tx descriptor generation + * @wr_hi: top 32 bits of WR header based on WR type (big endian) + * @wr_lo: low 32 bits of WR header based on WR type (big endian) + * + * Write a work request header and an associated SGL. If the SGL is + * small enough to fit into one Tx descriptor it has already been written + * and we just need to write the WR header. Otherwise we distribute the + * SGL across the number of descriptors it spans. + */ +static void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb, + struct tx_desc *d, unsigned int pidx, + const struct sge_txq *q, + const struct sg_ent *sgl, + unsigned int flits, unsigned int sgl_flits, + unsigned int gen, __be32 wr_hi, + __be32 wr_lo) +{ + struct work_request_hdr *wrp = (struct work_request_hdr *)d; + struct tx_sw_desc *sd = &q->sdesc[pidx]; + + sd->skb = skb; + if (need_skb_unmap()) { + sd->fragidx = 0; + sd->addr_idx = 0; + sd->sflit = flits; + } + + if (likely(ndesc == 1)) { + sd->eop = 1; + wrp->wr_hi = htonl(F_WR_SOP | F_WR_EOP | V_WR_DATATYPE(1) | + V_WR_SGLSFLT(flits)) | wr_hi; + wmb(); + wrp->wr_lo = htonl(V_WR_LEN(flits + sgl_flits) | + V_WR_GEN(gen)) | wr_lo; + wr_gen2(d, gen); + } else { + unsigned int ogen = gen; + const u64 *fp = (const u64 *)sgl; + struct work_request_hdr *wp = wrp; + + wrp->wr_hi = htonl(F_WR_SOP | V_WR_DATATYPE(1) | + V_WR_SGLSFLT(flits)) | wr_hi; + + while (sgl_flits) { + unsigned int avail = WR_FLITS - flits; + + if (avail > sgl_flits) + avail = sgl_flits; + memcpy(&d->flit[flits], fp, avail * sizeof(*fp)); + sgl_flits -= avail; + ndesc--; + if (!sgl_flits) + break; + + fp += avail; + d++; + sd->eop = 0; + sd++; + if (++pidx == q->size) { + pidx = 0; + gen ^= 1; + d = q->desc; + sd = q->sdesc; + } + + sd->skb = skb; + wrp = (struct work_request_hdr *)d; + wrp->wr_hi = htonl(V_WR_DATATYPE(1) | + V_WR_SGLSFLT(1)) | wr_hi; + wrp->wr_lo = htonl(V_WR_LEN(min(WR_FLITS, + sgl_flits + 1)) | + V_WR_GEN(gen)) | wr_lo; + wr_gen2(d, gen); + flits = 1; + } + sd->eop = 1; + wrp->wr_hi |= htonl(F_WR_EOP); + wmb(); + wp->wr_lo = htonl(V_WR_LEN(WR_FLITS) | V_WR_GEN(ogen)) | wr_lo; + wr_gen2((struct tx_desc *)wp, ogen); + WARN_ON(ndesc != 0); + } +} + +/** + * write_tx_pkt_wr - write a TX_PKT work request + * @adap: the adapter + * @skb: the packet to send + * @pi: the egress interface + * @pidx: index of the first Tx descriptor to write + * @gen: the generation value to use + * @q: the Tx queue + * @ndesc: number of descriptors the packet will occupy + * @compl: the value of the COMPL bit to use + * + * Generate a TX_PKT work request to send the supplied packet. + */ +static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb, + const struct port_info *pi, + unsigned int pidx, unsigned int gen, + struct sge_txq *q, unsigned int ndesc, + unsigned int compl) +{ + unsigned int flits, sgl_flits, cntrl, tso_info; + struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1]; + struct tx_desc *d = &q->desc[pidx]; + struct cpl_tx_pkt *cpl = (struct cpl_tx_pkt *)d; + + cpl->len = htonl(skb->len); + cntrl = V_TXPKT_INTF(pi->port_id); + + if (vlan_tx_tag_present(skb)) + cntrl |= F_TXPKT_VLAN_VLD | V_TXPKT_VLAN(vlan_tx_tag_get(skb)); + + tso_info = V_LSO_MSS(skb_shinfo(skb)->gso_size); + if (tso_info) { + int eth_type; + struct cpl_tx_pkt_lso *hdr = (struct cpl_tx_pkt_lso *)cpl; + + d->flit[2] = 0; + cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT_LSO); + hdr->cntrl = htonl(cntrl); + eth_type = skb_network_offset(skb) == ETH_HLEN ? + CPL_ETH_II : CPL_ETH_II_VLAN; + tso_info |= V_LSO_ETH_TYPE(eth_type) | + V_LSO_IPHDR_WORDS(ip_hdr(skb)->ihl) | + V_LSO_TCPHDR_WORDS(tcp_hdr(skb)->doff); + hdr->lso_info = htonl(tso_info); + flits = 3; + } else { + cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT); + cntrl |= F_TXPKT_IPCSUM_DIS; /* SW calculates IP csum */ + cntrl |= V_TXPKT_L4CSUM_DIS(skb->ip_summed != CHECKSUM_PARTIAL); + cpl->cntrl = htonl(cntrl); + + if (skb->len <= WR_LEN - sizeof(*cpl)) { + q->sdesc[pidx].skb = NULL; + if (!skb->data_len) + skb_copy_from_linear_data(skb, &d->flit[2], + skb->len); + else + skb_copy_bits(skb, 0, &d->flit[2], skb->len); + + flits = (skb->len + 7) / 8 + 2; + cpl->wr.wr_hi = htonl(V_WR_BCNTLFLT(skb->len & 7) | + V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) + | F_WR_SOP | F_WR_EOP | compl); + wmb(); + cpl->wr.wr_lo = htonl(V_WR_LEN(flits) | V_WR_GEN(gen) | + V_WR_TID(q->token)); + wr_gen2(d, gen); + kfree_skb(skb); + return; + } + + flits = 2; + } + + sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl; + sgl_flits = make_sgl(skb, sgp, skb->data, skb_headlen(skb), adap->pdev); + + write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, gen, + htonl(V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) | compl), + htonl(V_WR_TID(q->token))); +} + +static inline void t3_stop_tx_queue(struct netdev_queue *txq, + struct sge_qset *qs, struct sge_txq *q) +{ + netif_tx_stop_queue(txq); + set_bit(TXQ_ETH, &qs->txq_stopped); + q->stops++; +} + +/** + * eth_xmit - add a packet to the Ethernet Tx queue + * @skb: the packet + * @dev: the egress net device + * + * Add a packet to an SGE Tx queue. Runs with softirqs disabled. + */ +netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) +{ + int qidx; + unsigned int ndesc, pidx, credits, gen, compl; + const struct port_info *pi = netdev_priv(dev); + struct adapter *adap = pi->adapter; + struct netdev_queue *txq; + struct sge_qset *qs; + struct sge_txq *q; + + /* + * The chip min packet length is 9 octets but play safe and reject + * anything shorter than an Ethernet header. + */ + if (unlikely(skb->len < ETH_HLEN)) { + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + + qidx = skb_get_queue_mapping(skb); + qs = &pi->qs[qidx]; + q = &qs->txq[TXQ_ETH]; + txq = netdev_get_tx_queue(dev, qidx); + + reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK); + + credits = q->size - q->in_use; + ndesc = calc_tx_descs(skb); + + if (unlikely(credits < ndesc)) { + t3_stop_tx_queue(txq, qs, q); + dev_err(&adap->pdev->dev, + "%s: Tx ring %u full while queue awake!\n", + dev->name, q->cntxt_id & 7); + return NETDEV_TX_BUSY; + } + + q->in_use += ndesc; + if (unlikely(credits - ndesc < q->stop_thres)) { + t3_stop_tx_queue(txq, qs, q); + + if (should_restart_tx(q) && + test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) { + q->restarts++; + netif_tx_start_queue(txq); + } + } + + gen = q->gen; + q->unacked += ndesc; + compl = (q->unacked & 8) << (S_WR_COMPL - 3); + q->unacked &= 7; + pidx = q->pidx; + q->pidx += ndesc; + if (q->pidx >= q->size) { + q->pidx -= q->size; + q->gen ^= 1; + } + + /* update port statistics */ + if (skb->ip_summed == CHECKSUM_COMPLETE) + qs->port_stats[SGE_PSTAT_TX_CSUM]++; + if (skb_shinfo(skb)->gso_size) + qs->port_stats[SGE_PSTAT_TSO]++; + if (vlan_tx_tag_present(skb)) + qs->port_stats[SGE_PSTAT_VLANINS]++; + + /* + * We do not use Tx completion interrupts to free DMAd Tx packets. + * This is good for performance but means that we rely on new Tx + * packets arriving to run the destructors of completed packets, + * which open up space in their sockets' send queues. Sometimes + * we do not get such new packets causing Tx to stall. A single + * UDP transmitter is a good example of this situation. We have + * a clean up timer that periodically reclaims completed packets + * but it doesn't run often enough (nor do we want it to) to prevent + * lengthy stalls. A solution to this problem is to run the + * destructor early, after the packet is queued but before it's DMAd. + * A cons is that we lie to socket memory accounting, but the amount + * of extra memory is reasonable (limited by the number of Tx + * descriptors), the packets do actually get freed quickly by new + * packets almost always, and for protocols like TCP that wait for + * acks to really free up the data the extra memory is even less. + * On the positive side we run the destructors on the sending CPU + * rather than on a potentially different completing CPU, usually a + * good thing. We also run them without holding our Tx queue lock, + * unlike what reclaim_completed_tx() would otherwise do. + * + * Run the destructor before telling the DMA engine about the packet + * to make sure it doesn't complete and get freed prematurely. + */ + if (likely(!skb_shared(skb))) + skb_orphan(skb); + + write_tx_pkt_wr(adap, skb, pi, pidx, gen, q, ndesc, compl); + check_ring_tx_db(adap, q); + return NETDEV_TX_OK; +} + +/** + * write_imm - write a packet into a Tx descriptor as immediate data + * @d: the Tx descriptor to write + * @skb: the packet + * @len: the length of packet data to write as immediate data + * @gen: the generation bit value to write + * + * Writes a packet as immediate data into a Tx descriptor. The packet + * contains a work request at its beginning. We must write the packet + * carefully so the SGE doesn't read it accidentally before it's written + * in its entirety. + */ +static inline void write_imm(struct tx_desc *d, struct sk_buff *skb, + unsigned int len, unsigned int gen) +{ + struct work_request_hdr *from = (struct work_request_hdr *)skb->data; + struct work_request_hdr *to = (struct work_request_hdr *)d; + + if (likely(!skb->data_len)) + memcpy(&to[1], &from[1], len - sizeof(*from)); + else + skb_copy_bits(skb, sizeof(*from), &to[1], len - sizeof(*from)); + + to->wr_hi = from->wr_hi | htonl(F_WR_SOP | F_WR_EOP | + V_WR_BCNTLFLT(len & 7)); + wmb(); + to->wr_lo = from->wr_lo | htonl(V_WR_GEN(gen) | + V_WR_LEN((len + 7) / 8)); + wr_gen2(d, gen); + kfree_skb(skb); +} + +/** + * check_desc_avail - check descriptor availability on a send queue + * @adap: the adapter + * @q: the send queue + * @skb: the packet needing the descriptors + * @ndesc: the number of Tx descriptors needed + * @qid: the Tx queue number in its queue set (TXQ_OFLD or TXQ_CTRL) + * + * Checks if the requested number of Tx descriptors is available on an + * SGE send queue. If the queue is already suspended or not enough + * descriptors are available the packet is queued for later transmission. + * Must be called with the Tx queue locked. + * + * Returns 0 if enough descriptors are available, 1 if there aren't + * enough descriptors and the packet has been queued, and 2 if the caller + * needs to retry because there weren't enough descriptors at the + * beginning of the call but some freed up in the mean time. + */ +static inline int check_desc_avail(struct adapter *adap, struct sge_txq *q, + struct sk_buff *skb, unsigned int ndesc, + unsigned int qid) +{ + if (unlikely(!skb_queue_empty(&q->sendq))) { + addq_exit:__skb_queue_tail(&q->sendq, skb); + return 1; + } + if (unlikely(q->size - q->in_use < ndesc)) { + struct sge_qset *qs = txq_to_qset(q, qid); + + set_bit(qid, &qs->txq_stopped); + smp_mb__after_clear_bit(); + + if (should_restart_tx(q) && + test_and_clear_bit(qid, &qs->txq_stopped)) + return 2; + + q->stops++; + goto addq_exit; + } + return 0; +} + +/** + * reclaim_completed_tx_imm - reclaim completed control-queue Tx descs + * @q: the SGE control Tx queue + * + * This is a variant of reclaim_completed_tx() that is used for Tx queues + * that send only immediate data (presently just the control queues) and + * thus do not have any sk_buffs to release. + */ +static inline void reclaim_completed_tx_imm(struct sge_txq *q) +{ + unsigned int reclaim = q->processed - q->cleaned; + + q->in_use -= reclaim; + q->cleaned += reclaim; +} + +static inline int immediate(const struct sk_buff *skb) +{ + return skb->len <= WR_LEN; +} + +/** + * ctrl_xmit - send a packet through an SGE control Tx queue + * @adap: the adapter + * @q: the control queue + * @skb: the packet + * + * Send a packet through an SGE control Tx queue. Packets sent through + * a control queue must fit entirely as immediate data in a single Tx + * descriptor and have no page fragments. + */ +static int ctrl_xmit(struct adapter *adap, struct sge_txq *q, + struct sk_buff *skb) +{ + int ret; + struct work_request_hdr *wrp = (struct work_request_hdr *)skb->data; + + if (unlikely(!immediate(skb))) { + WARN_ON(1); + dev_kfree_skb(skb); + return NET_XMIT_SUCCESS; + } + + wrp->wr_hi |= htonl(F_WR_SOP | F_WR_EOP); + wrp->wr_lo = htonl(V_WR_TID(q->token)); + + spin_lock(&q->lock); + again:reclaim_completed_tx_imm(q); + + ret = check_desc_avail(adap, q, skb, 1, TXQ_CTRL); + if (unlikely(ret)) { + if (ret == 1) { + spin_unlock(&q->lock); + return NET_XMIT_CN; + } + goto again; + } + + write_imm(&q->desc[q->pidx], skb, skb->len, q->gen); + + q->in_use++; + if (++q->pidx >= q->size) { + q->pidx = 0; + q->gen ^= 1; + } + spin_unlock(&q->lock); + wmb(); + t3_write_reg(adap, A_SG_KDOORBELL, + F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); + return NET_XMIT_SUCCESS; +} + +/** + * restart_ctrlq - restart a suspended control queue + * @qs: the queue set cotaining the control queue + * + * Resumes transmission on a suspended Tx control queue. + */ +static void restart_ctrlq(unsigned long data) +{ + struct sk_buff *skb; + struct sge_qset *qs = (struct sge_qset *)data; + struct sge_txq *q = &qs->txq[TXQ_CTRL]; + + spin_lock(&q->lock); + again:reclaim_completed_tx_imm(q); + + while (q->in_use < q->size && + (skb = __skb_dequeue(&q->sendq)) != NULL) { + + write_imm(&q->desc[q->pidx], skb, skb->len, q->gen); + + if (++q->pidx >= q->size) { + q->pidx = 0; + q->gen ^= 1; + } + q->in_use++; + } + + if (!skb_queue_empty(&q->sendq)) { + set_bit(TXQ_CTRL, &qs->txq_stopped); + smp_mb__after_clear_bit(); + + if (should_restart_tx(q) && + test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped)) + goto again; + q->stops++; + } + + spin_unlock(&q->lock); + wmb(); + t3_write_reg(qs->adap, A_SG_KDOORBELL, + F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); +} + +/* + * Send a management message through control queue 0 + */ +int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb) +{ + int ret; + local_bh_disable(); + ret = ctrl_xmit(adap, &adap->sge.qs[0].txq[TXQ_CTRL], skb); + local_bh_enable(); + + return ret; +} + +/** + * deferred_unmap_destructor - unmap a packet when it is freed + * @skb: the packet + * + * This is the packet destructor used for Tx packets that need to remain + * mapped until they are freed rather than until their Tx descriptors are + * freed. + */ +static void deferred_unmap_destructor(struct sk_buff *skb) +{ + int i; + const dma_addr_t *p; + const struct skb_shared_info *si; + const struct deferred_unmap_info *dui; + + dui = (struct deferred_unmap_info *)skb->head; + p = dui->addr; + + if (skb->tail - skb->transport_header) + pci_unmap_single(dui->pdev, *p++, + skb->tail - skb->transport_header, + PCI_DMA_TODEVICE); + + si = skb_shinfo(skb); + for (i = 0; i < si->nr_frags; i++) + pci_unmap_page(dui->pdev, *p++, si->frags[i].size, + PCI_DMA_TODEVICE); +} + +static void setup_deferred_unmapping(struct sk_buff *skb, struct pci_dev *pdev, + const struct sg_ent *sgl, int sgl_flits) +{ + dma_addr_t *p; + struct deferred_unmap_info *dui; + + dui = (struct deferred_unmap_info *)skb->head; + dui->pdev = pdev; + for (p = dui->addr; sgl_flits >= 3; sgl++, sgl_flits -= 3) { + *p++ = be64_to_cpu(sgl->addr[0]); + *p++ = be64_to_cpu(sgl->addr[1]); + } + if (sgl_flits) + *p = be64_to_cpu(sgl->addr[0]); +} + +/** + * write_ofld_wr - write an offload work request + * @adap: the adapter + * @skb: the packet to send + * @q: the Tx queue + * @pidx: index of the first Tx descriptor to write + * @gen: the generation value to use + * @ndesc: number of descriptors the packet will occupy + * + * Write an offload work request to send the supplied packet. The packet + * data already carry the work request with most fields populated. + */ +static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb, + struct sge_txq *q, unsigned int pidx, + unsigned int gen, unsigned int ndesc) +{ + unsigned int sgl_flits, flits; + struct work_request_hdr *from; + struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1]; + struct tx_desc *d = &q->desc[pidx]; + + if (immediate(skb)) { + q->sdesc[pidx].skb = NULL; + write_imm(d, skb, skb->len, gen); + return; + } + + /* Only TX_DATA builds SGLs */ + + from = (struct work_request_hdr *)skb->data; + memcpy(&d->flit[1], &from[1], + skb_transport_offset(skb) - sizeof(*from)); + + flits = skb_transport_offset(skb) / 8; + sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl; + sgl_flits = make_sgl(skb, sgp, skb_transport_header(skb), + skb->tail - skb->transport_header, + adap->pdev); + if (need_skb_unmap()) { + setup_deferred_unmapping(skb, adap->pdev, sgp, sgl_flits); + skb->destructor = deferred_unmap_destructor; + } + + write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, + gen, from->wr_hi, from->wr_lo); +} + +/** + * calc_tx_descs_ofld - calculate # of Tx descriptors for an offload packet + * @skb: the packet + * + * Returns the number of Tx descriptors needed for the given offload + * packet. These packets are already fully constructed. + */ +static inline unsigned int calc_tx_descs_ofld(const struct sk_buff *skb) +{ + unsigned int flits, cnt; + + if (skb->len <= WR_LEN) + return 1; /* packet fits as immediate data */ + + flits = skb_transport_offset(skb) / 8; /* headers */ + cnt = skb_shinfo(skb)->nr_frags; + if (skb->tail != skb->transport_header) + cnt++; + return flits_to_desc(flits + sgl_len(cnt)); +} + +/** + * ofld_xmit - send a packet through an offload queue + * @adap: the adapter + * @q: the Tx offload queue + * @skb: the packet + * + * Send an offload packet through an SGE offload queue. + */ +static int ofld_xmit(struct adapter *adap, struct sge_txq *q, + struct sk_buff *skb) +{ + int ret; + unsigned int ndesc = calc_tx_descs_ofld(skb), pidx, gen; + + spin_lock(&q->lock); +again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK); + + ret = check_desc_avail(adap, q, skb, ndesc, TXQ_OFLD); + if (unlikely(ret)) { + if (ret == 1) { + skb->priority = ndesc; /* save for restart */ + spin_unlock(&q->lock); + return NET_XMIT_CN; + } + goto again; + } + + gen = q->gen; + q->in_use += ndesc; + pidx = q->pidx; + q->pidx += ndesc; + if (q->pidx >= q->size) { + q->pidx -= q->size; + q->gen ^= 1; + } + spin_unlock(&q->lock); + + write_ofld_wr(adap, skb, q, pidx, gen, ndesc); + check_ring_tx_db(adap, q); + return NET_XMIT_SUCCESS; +} + +/** + * restart_offloadq - restart a suspended offload queue + * @qs: the queue set cotaining the offload queue + * + * Resumes transmission on a suspended Tx offload queue. + */ +static void restart_offloadq(unsigned long data) +{ + struct sk_buff *skb; + struct sge_qset *qs = (struct sge_qset *)data; + struct sge_txq *q = &qs->txq[TXQ_OFLD]; + const struct port_info *pi = netdev_priv(qs->netdev); + struct adapter *adap = pi->adapter; + + spin_lock(&q->lock); +again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK); + + while ((skb = skb_peek(&q->sendq)) != NULL) { + unsigned int gen, pidx; + unsigned int ndesc = skb->priority; + + if (unlikely(q->size - q->in_use < ndesc)) { + set_bit(TXQ_OFLD, &qs->txq_stopped); + smp_mb__after_clear_bit(); + + if (should_restart_tx(q) && + test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped)) + goto again; + q->stops++; + break; + } + + gen = q->gen; + q->in_use += ndesc; + pidx = q->pidx; + q->pidx += ndesc; + if (q->pidx >= q->size) { + q->pidx -= q->size; + q->gen ^= 1; + } + __skb_unlink(skb, &q->sendq); + spin_unlock(&q->lock); + + write_ofld_wr(adap, skb, q, pidx, gen, ndesc); + spin_lock(&q->lock); + } + spin_unlock(&q->lock); + +#if USE_GTS + set_bit(TXQ_RUNNING, &q->flags); + set_bit(TXQ_LAST_PKT_DB, &q->flags); +#endif + wmb(); + t3_write_reg(adap, A_SG_KDOORBELL, + F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); +} + +/** + * queue_set - return the queue set a packet should use + * @skb: the packet + * + * Maps a packet to the SGE queue set it should use. The desired queue + * set is carried in bits 1-3 in the packet's priority. + */ +static inline int queue_set(const struct sk_buff *skb) +{ + return skb->priority >> 1; +} + +/** + * is_ctrl_pkt - return whether an offload packet is a control packet + * @skb: the packet + * + * Determines whether an offload packet should use an OFLD or a CTRL + * Tx queue. This is indicated by bit 0 in the packet's priority. + */ +static inline int is_ctrl_pkt(const struct sk_buff *skb) +{ + return skb->priority & 1; +} + +/** + * t3_offload_tx - send an offload packet + * @tdev: the offload device to send to + * @skb: the packet + * + * Sends an offload packet. We use the packet priority to select the + * appropriate Tx queue as follows: bit 0 indicates whether the packet + * should be sent as regular or control, bits 1-3 select the queue set. + */ +int t3_offload_tx(struct t3cdev *tdev, struct sk_buff *skb) +{ + struct adapter *adap = tdev2adap(tdev); + struct sge_qset *qs = &adap->sge.qs[queue_set(skb)]; + + if (unlikely(is_ctrl_pkt(skb))) + return ctrl_xmit(adap, &qs->txq[TXQ_CTRL], skb); + + return ofld_xmit(adap, &qs->txq[TXQ_OFLD], skb); +} + +/** + * offload_enqueue - add an offload packet to an SGE offload receive queue + * @q: the SGE response queue + * @skb: the packet + * + * Add a new offload packet to an SGE response queue's offload packet + * queue. If the packet is the first on the queue it schedules the RX + * softirq to process the queue. + */ +static inline void offload_enqueue(struct sge_rspq *q, struct sk_buff *skb) +{ + int was_empty = skb_queue_empty(&q->rx_queue); + + __skb_queue_tail(&q->rx_queue, skb); + + if (was_empty) { + struct sge_qset *qs = rspq_to_qset(q); + + napi_schedule(&qs->napi); + } +} + +/** + * deliver_partial_bundle - deliver a (partial) bundle of Rx offload pkts + * @tdev: the offload device that will be receiving the packets + * @q: the SGE response queue that assembled the bundle + * @skbs: the partial bundle + * @n: the number of packets in the bundle + * + * Delivers a (partial) bundle of Rx offload packets to an offload device. + */ +static inline void deliver_partial_bundle(struct t3cdev *tdev, + struct sge_rspq *q, + struct sk_buff *skbs[], int n) +{ + if (n) { + q->offload_bundles++; + tdev->recv(tdev, skbs, n); + } +} + +/** + * ofld_poll - NAPI handler for offload packets in interrupt mode + * @dev: the network device doing the polling + * @budget: polling budget + * + * The NAPI handler for offload packets when a response queue is serviced + * by the hard interrupt handler, i.e., when it's operating in non-polling + * mode. Creates small packet batches and sends them through the offload + * receive handler. Batches need to be of modest size as we do prefetches + * on the packets in each. + */ +static int ofld_poll(struct napi_struct *napi, int budget) +{ + struct sge_qset *qs = container_of(napi, struct sge_qset, napi); + struct sge_rspq *q = &qs->rspq; + struct adapter *adapter = qs->adap; + int work_done = 0; + + while (work_done < budget) { + struct sk_buff *skb, *tmp, *skbs[RX_BUNDLE_SIZE]; + struct sk_buff_head queue; + int ngathered; + + spin_lock_irq(&q->lock); + __skb_queue_head_init(&queue); + skb_queue_splice_init(&q->rx_queue, &queue); + if (skb_queue_empty(&queue)) { + napi_complete(napi); + spin_unlock_irq(&q->lock); + return work_done; + } + spin_unlock_irq(&q->lock); + + ngathered = 0; + skb_queue_walk_safe(&queue, skb, tmp) { + if (work_done >= budget) + break; + work_done++; + + __skb_unlink(skb, &queue); + prefetch(skb->data); + skbs[ngathered] = skb; + if (++ngathered == RX_BUNDLE_SIZE) { + q->offload_bundles++; + adapter->tdev.recv(&adapter->tdev, skbs, + ngathered); + ngathered = 0; + } + } + if (!skb_queue_empty(&queue)) { + /* splice remaining packets back onto Rx queue */ + spin_lock_irq(&q->lock); + skb_queue_splice(&queue, &q->rx_queue); + spin_unlock_irq(&q->lock); + } + deliver_partial_bundle(&adapter->tdev, q, skbs, ngathered); + } + + return work_done; +} + +/** + * rx_offload - process a received offload packet + * @tdev: the offload device receiving the packet + * @rq: the response queue that received the packet + * @skb: the packet + * @rx_gather: a gather list of packets if we are building a bundle + * @gather_idx: index of the next available slot in the bundle + * + * Process an ingress offload pakcet and add it to the offload ingress + * queue. Returns the index of the next available slot in the bundle. + */ +static inline int rx_offload(struct t3cdev *tdev, struct sge_rspq *rq, + struct sk_buff *skb, struct sk_buff *rx_gather[], + unsigned int gather_idx) +{ + skb_reset_mac_header(skb); + skb_reset_network_header(skb); + skb_reset_transport_header(skb); + + if (rq->polling) { + rx_gather[gather_idx++] = skb; + if (gather_idx == RX_BUNDLE_SIZE) { + tdev->recv(tdev, rx_gather, RX_BUNDLE_SIZE); + gather_idx = 0; + rq->offload_bundles++; + } + } else + offload_enqueue(rq, skb); + + return gather_idx; +} + +/** + * restart_tx - check whether to restart suspended Tx queues + * @qs: the queue set to resume + * + * Restarts suspended Tx queues of an SGE queue set if they have enough + * free resources to resume operation. + */ +static void restart_tx(struct sge_qset *qs) +{ + if (test_bit(TXQ_ETH, &qs->txq_stopped) && + should_restart_tx(&qs->txq[TXQ_ETH]) && + test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) { + qs->txq[TXQ_ETH].restarts++; + if (netif_running(qs->netdev)) + netif_tx_wake_queue(qs->tx_q); + } + + if (test_bit(TXQ_OFLD, &qs->txq_stopped) && + should_restart_tx(&qs->txq[TXQ_OFLD]) && + test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped)) { + qs->txq[TXQ_OFLD].restarts++; + tasklet_schedule(&qs->txq[TXQ_OFLD].qresume_tsk); + } + if (test_bit(TXQ_CTRL, &qs->txq_stopped) && + should_restart_tx(&qs->txq[TXQ_CTRL]) && + test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped)) { + qs->txq[TXQ_CTRL].restarts++; + tasklet_schedule(&qs->txq[TXQ_CTRL].qresume_tsk); + } +} + +/** + * cxgb3_arp_process - process an ARP request probing a private IP address + * @adapter: the adapter + * @skb: the skbuff containing the ARP request + * + * Check if the ARP request is probing the private IP address + * dedicated to iSCSI, generate an ARP reply if so. + */ +static void cxgb3_arp_process(struct port_info *pi, struct sk_buff *skb) +{ + struct net_device *dev = skb->dev; + struct arphdr *arp; + unsigned char *arp_ptr; + unsigned char *sha; + __be32 sip, tip; + + if (!dev) + return; + + skb_reset_network_header(skb); + arp = arp_hdr(skb); + + if (arp->ar_op != htons(ARPOP_REQUEST)) + return; + + arp_ptr = (unsigned char *)(arp + 1); + sha = arp_ptr; + arp_ptr += dev->addr_len; + memcpy(&sip, arp_ptr, sizeof(sip)); + arp_ptr += sizeof(sip); + arp_ptr += dev->addr_len; + memcpy(&tip, arp_ptr, sizeof(tip)); + + if (tip != pi->iscsi_ipv4addr) + return; + + arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha, + pi->iscsic.mac_addr, sha); + +} + +static inline int is_arp(struct sk_buff *skb) +{ + return skb->protocol == htons(ETH_P_ARP); +} + +static void cxgb3_process_iscsi_prov_pack(struct port_info *pi, + struct sk_buff *skb) +{ + if (is_arp(skb)) { + cxgb3_arp_process(pi, skb); + return; + } + + if (pi->iscsic.recv) + pi->iscsic.recv(pi, skb); + +} + +/** + * rx_eth - process an ingress ethernet packet + * @adap: the adapter + * @rq: the response queue that received the packet + * @skb: the packet + * @pad: amount of padding at the start of the buffer + * + * Process an ingress ethernet pakcet and deliver it to the stack. + * The padding is 2 if the packet was delivered in an Rx buffer and 0 + * if it was immediate data in a response. + */ +static void rx_eth(struct adapter *adap, struct sge_rspq *rq, + struct sk_buff *skb, int pad, int lro) +{ + struct cpl_rx_pkt *p = (struct cpl_rx_pkt *)(skb->data + pad); + struct sge_qset *qs = rspq_to_qset(rq); + struct port_info *pi; + + skb_pull(skb, sizeof(*p) + pad); + skb->protocol = eth_type_trans(skb, adap->port[p->iff]); + pi = netdev_priv(skb->dev); + if ((skb->dev->features & NETIF_F_RXCSUM) && p->csum_valid && + p->csum == htons(0xffff) && !p->fragment) { + qs->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++; + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else + skb_checksum_none_assert(skb); + skb_record_rx_queue(skb, qs - &adap->sge.qs[pi->first_qset]); + + if (p->vlan_valid) { + qs->port_stats[SGE_PSTAT_VLANEX]++; + __vlan_hwaccel_put_tag(skb, ntohs(p->vlan)); + } + if (rq->polling) { + if (lro) + napi_gro_receive(&qs->napi, skb); + else { + if (unlikely(pi->iscsic.flags)) + cxgb3_process_iscsi_prov_pack(pi, skb); + netif_receive_skb(skb); + } + } else + netif_rx(skb); +} + +static inline int is_eth_tcp(u32 rss) +{ + return G_HASHTYPE(ntohl(rss)) == RSS_HASH_4_TUPLE; +} + +/** + * lro_add_page - add a page chunk to an LRO session + * @adap: the adapter + * @qs: the associated queue set + * @fl: the free list containing the page chunk to add + * @len: packet length + * @complete: Indicates the last fragment of a frame + * + * Add a received packet contained in a page chunk to an existing LRO + * session. + */ +static void lro_add_page(struct adapter *adap, struct sge_qset *qs, + struct sge_fl *fl, int len, int complete) +{ + struct rx_sw_desc *sd = &fl->sdesc[fl->cidx]; + struct port_info *pi = netdev_priv(qs->netdev); + struct sk_buff *skb = NULL; + struct cpl_rx_pkt *cpl; + struct skb_frag_struct *rx_frag; + int nr_frags; + int offset = 0; + + if (!qs->nomem) { + skb = napi_get_frags(&qs->napi); + qs->nomem = !skb; + } + + fl->credits--; + + pci_dma_sync_single_for_cpu(adap->pdev, + dma_unmap_addr(sd, dma_addr), + fl->buf_size - SGE_PG_RSVD, + PCI_DMA_FROMDEVICE); + + (*sd->pg_chunk.p_cnt)--; + if (!*sd->pg_chunk.p_cnt && sd->pg_chunk.page != fl->pg_chunk.page) + pci_unmap_page(adap->pdev, + sd->pg_chunk.mapping, + fl->alloc_size, + PCI_DMA_FROMDEVICE); + + if (!skb) { + put_page(sd->pg_chunk.page); + if (complete) + qs->nomem = 0; + return; + } + + rx_frag = skb_shinfo(skb)->frags; + nr_frags = skb_shinfo(skb)->nr_frags; + + if (!nr_frags) { + offset = 2 + sizeof(struct cpl_rx_pkt); + cpl = qs->lro_va = sd->pg_chunk.va + 2; + + if ((qs->netdev->features & NETIF_F_RXCSUM) && + cpl->csum_valid && cpl->csum == htons(0xffff)) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + qs->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++; + } else + skb->ip_summed = CHECKSUM_NONE; + } else + cpl = qs->lro_va; + + len -= offset; + + rx_frag += nr_frags; + rx_frag->page = sd->pg_chunk.page; + rx_frag->page_offset = sd->pg_chunk.offset + offset; + rx_frag->size = len; + + skb->len += len; + skb->data_len += len; + skb->truesize += len; + skb_shinfo(skb)->nr_frags++; + + if (!complete) + return; + + skb_record_rx_queue(skb, qs - &adap->sge.qs[pi->first_qset]); + + if (cpl->vlan_valid) + __vlan_hwaccel_put_tag(skb, ntohs(cpl->vlan)); + napi_gro_frags(&qs->napi); +} + +/** + * handle_rsp_cntrl_info - handles control information in a response + * @qs: the queue set corresponding to the response + * @flags: the response control flags + * + * Handles the control information of an SGE response, such as GTS + * indications and completion credits for the queue set's Tx queues. + * HW coalesces credits, we don't do any extra SW coalescing. + */ +static inline void handle_rsp_cntrl_info(struct sge_qset *qs, u32 flags) +{ + unsigned int credits; + +#if USE_GTS + if (flags & F_RSPD_TXQ0_GTS) + clear_bit(TXQ_RUNNING, &qs->txq[TXQ_ETH].flags); +#endif + + credits = G_RSPD_TXQ0_CR(flags); + if (credits) + qs->txq[TXQ_ETH].processed += credits; + + credits = G_RSPD_TXQ2_CR(flags); + if (credits) + qs->txq[TXQ_CTRL].processed += credits; + +# if USE_GTS + if (flags & F_RSPD_TXQ1_GTS) + clear_bit(TXQ_RUNNING, &qs->txq[TXQ_OFLD].flags); +# endif + credits = G_RSPD_TXQ1_CR(flags); + if (credits) + qs->txq[TXQ_OFLD].processed += credits; +} + +/** + * check_ring_db - check if we need to ring any doorbells + * @adapter: the adapter + * @qs: the queue set whose Tx queues are to be examined + * @sleeping: indicates which Tx queue sent GTS + * + * Checks if some of a queue set's Tx queues need to ring their doorbells + * to resume transmission after idling while they still have unprocessed + * descriptors. + */ +static void check_ring_db(struct adapter *adap, struct sge_qset *qs, + unsigned int sleeping) +{ + if (sleeping & F_RSPD_TXQ0_GTS) { + struct sge_txq *txq = &qs->txq[TXQ_ETH]; + + if (txq->cleaned + txq->in_use != txq->processed && + !test_and_set_bit(TXQ_LAST_PKT_DB, &txq->flags)) { + set_bit(TXQ_RUNNING, &txq->flags); + t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX | + V_EGRCNTX(txq->cntxt_id)); + } + } + + if (sleeping & F_RSPD_TXQ1_GTS) { + struct sge_txq *txq = &qs->txq[TXQ_OFLD]; + + if (txq->cleaned + txq->in_use != txq->processed && + !test_and_set_bit(TXQ_LAST_PKT_DB, &txq->flags)) { + set_bit(TXQ_RUNNING, &txq->flags); + t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX | + V_EGRCNTX(txq->cntxt_id)); + } + } +} + +/** + * is_new_response - check if a response is newly written + * @r: the response descriptor + * @q: the response queue + * + * Returns true if a response descriptor contains a yet unprocessed + * response. + */ +static inline int is_new_response(const struct rsp_desc *r, + const struct sge_rspq *q) +{ + return (r->intr_gen & F_RSPD_GEN2) == q->gen; +} + +static inline void clear_rspq_bufstate(struct sge_rspq * const q) +{ + q->pg_skb = NULL; + q->rx_recycle_buf = 0; +} + +#define RSPD_GTS_MASK (F_RSPD_TXQ0_GTS | F_RSPD_TXQ1_GTS) +#define RSPD_CTRL_MASK (RSPD_GTS_MASK | \ + V_RSPD_TXQ0_CR(M_RSPD_TXQ0_CR) | \ + V_RSPD_TXQ1_CR(M_RSPD_TXQ1_CR) | \ + V_RSPD_TXQ2_CR(M_RSPD_TXQ2_CR)) + +/* How long to delay the next interrupt in case of memory shortage, in 0.1us. */ +#define NOMEM_INTR_DELAY 2500 + +/** + * process_responses - process responses from an SGE response queue + * @adap: the adapter + * @qs: the queue set to which the response queue belongs + * @budget: how many responses can be processed in this round + * + * Process responses from an SGE response queue up to the supplied budget. + * Responses include received packets as well as credits and other events + * for the queues that belong to the response queue's queue set. + * A negative budget is effectively unlimited. + * + * Additionally choose the interrupt holdoff time for the next interrupt + * on this queue. If the system is under memory shortage use a fairly + * long delay to help recovery. + */ +static int process_responses(struct adapter *adap, struct sge_qset *qs, + int budget) +{ + struct sge_rspq *q = &qs->rspq; + struct rsp_desc *r = &q->desc[q->cidx]; + int budget_left = budget; + unsigned int sleeping = 0; + struct sk_buff *offload_skbs[RX_BUNDLE_SIZE]; + int ngathered = 0; + + q->next_holdoff = q->holdoff_tmr; + + while (likely(budget_left && is_new_response(r, q))) { + int packet_complete, eth, ethpad = 2; + int lro = !!(qs->netdev->features & NETIF_F_GRO); + struct sk_buff *skb = NULL; + u32 len, flags; + __be32 rss_hi, rss_lo; + + rmb(); + eth = r->rss_hdr.opcode == CPL_RX_PKT; + rss_hi = *(const __be32 *)r; + rss_lo = r->rss_hdr.rss_hash_val; + flags = ntohl(r->flags); + + if (unlikely(flags & F_RSPD_ASYNC_NOTIF)) { + skb = alloc_skb(AN_PKT_SIZE, GFP_ATOMIC); + if (!skb) + goto no_mem; + + memcpy(__skb_put(skb, AN_PKT_SIZE), r, AN_PKT_SIZE); + skb->data[0] = CPL_ASYNC_NOTIF; + rss_hi = htonl(CPL_ASYNC_NOTIF << 24); + q->async_notif++; + } else if (flags & F_RSPD_IMM_DATA_VALID) { + skb = get_imm_packet(r); + if (unlikely(!skb)) { +no_mem: + q->next_holdoff = NOMEM_INTR_DELAY; + q->nomem++; + /* consume one credit since we tried */ + budget_left--; + break; + } + q->imm_data++; + ethpad = 0; + } else if ((len = ntohl(r->len_cq)) != 0) { + struct sge_fl *fl; + + lro &= eth && is_eth_tcp(rss_hi); + + fl = (len & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0]; + if (fl->use_pages) { + void *addr = fl->sdesc[fl->cidx].pg_chunk.va; + + prefetch(addr); +#if L1_CACHE_BYTES < 128 + prefetch(addr + L1_CACHE_BYTES); +#endif + __refill_fl(adap, fl); + if (lro > 0) { + lro_add_page(adap, qs, fl, + G_RSPD_LEN(len), + flags & F_RSPD_EOP); + goto next_fl; + } + + skb = get_packet_pg(adap, fl, q, + G_RSPD_LEN(len), + eth ? + SGE_RX_DROP_THRES : 0); + q->pg_skb = skb; + } else + skb = get_packet(adap, fl, G_RSPD_LEN(len), + eth ? SGE_RX_DROP_THRES : 0); + if (unlikely(!skb)) { + if (!eth) + goto no_mem; + q->rx_drops++; + } else if (unlikely(r->rss_hdr.opcode == CPL_TRACE_PKT)) + __skb_pull(skb, 2); +next_fl: + if (++fl->cidx == fl->size) + fl->cidx = 0; + } else + q->pure_rsps++; + + if (flags & RSPD_CTRL_MASK) { + sleeping |= flags & RSPD_GTS_MASK; + handle_rsp_cntrl_info(qs, flags); + } + + r++; + if (unlikely(++q->cidx == q->size)) { + q->cidx = 0; + q->gen ^= 1; + r = q->desc; + } + prefetch(r); + + if (++q->credits >= (q->size / 4)) { + refill_rspq(adap, q, q->credits); + q->credits = 0; + } + + packet_complete = flags & + (F_RSPD_EOP | F_RSPD_IMM_DATA_VALID | + F_RSPD_ASYNC_NOTIF); + + if (skb != NULL && packet_complete) { + if (eth) + rx_eth(adap, q, skb, ethpad, lro); + else { + q->offload_pkts++; + /* Preserve the RSS info in csum & priority */ + skb->csum = rss_hi; + skb->priority = rss_lo; + ngathered = rx_offload(&adap->tdev, q, skb, + offload_skbs, + ngathered); + } + + if (flags & F_RSPD_EOP) + clear_rspq_bufstate(q); + } + --budget_left; + } + + deliver_partial_bundle(&adap->tdev, q, offload_skbs, ngathered); + + if (sleeping) + check_ring_db(adap, qs, sleeping); + + smp_mb(); /* commit Tx queue .processed updates */ + if (unlikely(qs->txq_stopped != 0)) + restart_tx(qs); + + budget -= budget_left; + return budget; +} + +static inline int is_pure_response(const struct rsp_desc *r) +{ + __be32 n = r->flags & htonl(F_RSPD_ASYNC_NOTIF | F_RSPD_IMM_DATA_VALID); + + return (n | r->len_cq) == 0; +} + +/** + * napi_rx_handler - the NAPI handler for Rx processing + * @napi: the napi instance + * @budget: how many packets we can process in this round + * + * Handler for new data events when using NAPI. + */ +static int napi_rx_handler(struct napi_struct *napi, int budget) +{ + struct sge_qset *qs = container_of(napi, struct sge_qset, napi); + struct adapter *adap = qs->adap; + int work_done = process_responses(adap, qs, budget); + + if (likely(work_done < budget)) { + napi_complete(napi); + + /* + * Because we don't atomically flush the following + * write it is possible that in very rare cases it can + * reach the device in a way that races with a new + * response being written plus an error interrupt + * causing the NAPI interrupt handler below to return + * unhandled status to the OS. To protect against + * this would require flushing the write and doing + * both the write and the flush with interrupts off. + * Way too expensive and unjustifiable given the + * rarity of the race. + * + * The race cannot happen at all with MSI-X. + */ + t3_write_reg(adap, A_SG_GTS, V_RSPQ(qs->rspq.cntxt_id) | + V_NEWTIMER(qs->rspq.next_holdoff) | + V_NEWINDEX(qs->rspq.cidx)); + } + return work_done; +} + +/* + * Returns true if the device is already scheduled for polling. + */ +static inline int napi_is_scheduled(struct napi_struct *napi) +{ + return test_bit(NAPI_STATE_SCHED, &napi->state); +} + +/** + * process_pure_responses - process pure responses from a response queue + * @adap: the adapter + * @qs: the queue set owning the response queue + * @r: the first pure response to process + * + * A simpler version of process_responses() that handles only pure (i.e., + * non data-carrying) responses. Such respones are too light-weight to + * justify calling a softirq under NAPI, so we handle them specially in + * the interrupt handler. The function is called with a pointer to a + * response, which the caller must ensure is a valid pure response. + * + * Returns 1 if it encounters a valid data-carrying response, 0 otherwise. + */ +static int process_pure_responses(struct adapter *adap, struct sge_qset *qs, + struct rsp_desc *r) +{ + struct sge_rspq *q = &qs->rspq; + unsigned int sleeping = 0; + + do { + u32 flags = ntohl(r->flags); + + r++; + if (unlikely(++q->cidx == q->size)) { + q->cidx = 0; + q->gen ^= 1; + r = q->desc; + } + prefetch(r); + + if (flags & RSPD_CTRL_MASK) { + sleeping |= flags & RSPD_GTS_MASK; + handle_rsp_cntrl_info(qs, flags); + } + + q->pure_rsps++; + if (++q->credits >= (q->size / 4)) { + refill_rspq(adap, q, q->credits); + q->credits = 0; + } + if (!is_new_response(r, q)) + break; + rmb(); + } while (is_pure_response(r)); + + if (sleeping) + check_ring_db(adap, qs, sleeping); + + smp_mb(); /* commit Tx queue .processed updates */ + if (unlikely(qs->txq_stopped != 0)) + restart_tx(qs); + + return is_new_response(r, q); +} + +/** + * handle_responses - decide what to do with new responses in NAPI mode + * @adap: the adapter + * @q: the response queue + * + * This is used by the NAPI interrupt handlers to decide what to do with + * new SGE responses. If there are no new responses it returns -1. If + * there are new responses and they are pure (i.e., non-data carrying) + * it handles them straight in hard interrupt context as they are very + * cheap and don't deliver any packets. Finally, if there are any data + * signaling responses it schedules the NAPI handler. Returns 1 if it + * schedules NAPI, 0 if all new responses were pure. + * + * The caller must ascertain NAPI is not already running. + */ +static inline int handle_responses(struct adapter *adap, struct sge_rspq *q) +{ + struct sge_qset *qs = rspq_to_qset(q); + struct rsp_desc *r = &q->desc[q->cidx]; + + if (!is_new_response(r, q)) + return -1; + rmb(); + if (is_pure_response(r) && process_pure_responses(adap, qs, r) == 0) { + t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) | + V_NEWTIMER(q->holdoff_tmr) | V_NEWINDEX(q->cidx)); + return 0; + } + napi_schedule(&qs->napi); + return 1; +} + +/* + * The MSI-X interrupt handler for an SGE response queue for the non-NAPI case + * (i.e., response queue serviced in hard interrupt). + */ +static irqreturn_t t3_sge_intr_msix(int irq, void *cookie) +{ + struct sge_qset *qs = cookie; + struct adapter *adap = qs->adap; + struct sge_rspq *q = &qs->rspq; + + spin_lock(&q->lock); + if (process_responses(adap, qs, -1) == 0) + q->unhandled_irqs++; + t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) | + V_NEWTIMER(q->next_holdoff) | V_NEWINDEX(q->cidx)); + spin_unlock(&q->lock); + return IRQ_HANDLED; +} + +/* + * The MSI-X interrupt handler for an SGE response queue for the NAPI case + * (i.e., response queue serviced by NAPI polling). + */ +static irqreturn_t t3_sge_intr_msix_napi(int irq, void *cookie) +{ + struct sge_qset *qs = cookie; + struct sge_rspq *q = &qs->rspq; + + spin_lock(&q->lock); + + if (handle_responses(qs->adap, q) < 0) + q->unhandled_irqs++; + spin_unlock(&q->lock); + return IRQ_HANDLED; +} + +/* + * The non-NAPI MSI interrupt handler. This needs to handle data events from + * SGE response queues as well as error and other async events as they all use + * the same MSI vector. We use one SGE response queue per port in this mode + * and protect all response queues with queue 0's lock. + */ +static irqreturn_t t3_intr_msi(int irq, void *cookie) +{ + int new_packets = 0; + struct adapter *adap = cookie; + struct sge_rspq *q = &adap->sge.qs[0].rspq; + + spin_lock(&q->lock); + + if (process_responses(adap, &adap->sge.qs[0], -1)) { + t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) | + V_NEWTIMER(q->next_holdoff) | V_NEWINDEX(q->cidx)); + new_packets = 1; + } + + if (adap->params.nports == 2 && + process_responses(adap, &adap->sge.qs[1], -1)) { + struct sge_rspq *q1 = &adap->sge.qs[1].rspq; + + t3_write_reg(adap, A_SG_GTS, V_RSPQ(q1->cntxt_id) | + V_NEWTIMER(q1->next_holdoff) | + V_NEWINDEX(q1->cidx)); + new_packets = 1; + } + + if (!new_packets && t3_slow_intr_handler(adap) == 0) + q->unhandled_irqs++; + + spin_unlock(&q->lock); + return IRQ_HANDLED; +} + +static int rspq_check_napi(struct sge_qset *qs) +{ + struct sge_rspq *q = &qs->rspq; + + if (!napi_is_scheduled(&qs->napi) && + is_new_response(&q->desc[q->cidx], q)) { + napi_schedule(&qs->napi); + return 1; + } + return 0; +} + +/* + * The MSI interrupt handler for the NAPI case (i.e., response queues serviced + * by NAPI polling). Handles data events from SGE response queues as well as + * error and other async events as they all use the same MSI vector. We use + * one SGE response queue per port in this mode and protect all response + * queues with queue 0's lock. + */ +static irqreturn_t t3_intr_msi_napi(int irq, void *cookie) +{ + int new_packets; + struct adapter *adap = cookie; + struct sge_rspq *q = &adap->sge.qs[0].rspq; + + spin_lock(&q->lock); + + new_packets = rspq_check_napi(&adap->sge.qs[0]); + if (adap->params.nports == 2) + new_packets += rspq_check_napi(&adap->sge.qs[1]); + if (!new_packets && t3_slow_intr_handler(adap) == 0) + q->unhandled_irqs++; + + spin_unlock(&q->lock); + return IRQ_HANDLED; +} + +/* + * A helper function that processes responses and issues GTS. + */ +static inline int process_responses_gts(struct adapter *adap, + struct sge_rspq *rq) +{ + int work; + + work = process_responses(adap, rspq_to_qset(rq), -1); + t3_write_reg(adap, A_SG_GTS, V_RSPQ(rq->cntxt_id) | + V_NEWTIMER(rq->next_holdoff) | V_NEWINDEX(rq->cidx)); + return work; +} + +/* + * The legacy INTx interrupt handler. This needs to handle data events from + * SGE response queues as well as error and other async events as they all use + * the same interrupt pin. We use one SGE response queue per port in this mode + * and protect all response queues with queue 0's lock. + */ +static irqreturn_t t3_intr(int irq, void *cookie) +{ + int work_done, w0, w1; + struct adapter *adap = cookie; + struct sge_rspq *q0 = &adap->sge.qs[0].rspq; + struct sge_rspq *q1 = &adap->sge.qs[1].rspq; + + spin_lock(&q0->lock); + + w0 = is_new_response(&q0->desc[q0->cidx], q0); + w1 = adap->params.nports == 2 && + is_new_response(&q1->desc[q1->cidx], q1); + + if (likely(w0 | w1)) { + t3_write_reg(adap, A_PL_CLI, 0); + t3_read_reg(adap, A_PL_CLI); /* flush */ + + if (likely(w0)) + process_responses_gts(adap, q0); + + if (w1) + process_responses_gts(adap, q1); + + work_done = w0 | w1; + } else + work_done = t3_slow_intr_handler(adap); + + spin_unlock(&q0->lock); + return IRQ_RETVAL(work_done != 0); +} + +/* + * Interrupt handler for legacy INTx interrupts for T3B-based cards. + * Handles data events from SGE response queues as well as error and other + * async events as they all use the same interrupt pin. We use one SGE + * response queue per port in this mode and protect all response queues with + * queue 0's lock. + */ +static irqreturn_t t3b_intr(int irq, void *cookie) +{ + u32 map; + struct adapter *adap = cookie; + struct sge_rspq *q0 = &adap->sge.qs[0].rspq; + + t3_write_reg(adap, A_PL_CLI, 0); + map = t3_read_reg(adap, A_SG_DATA_INTR); + + if (unlikely(!map)) /* shared interrupt, most likely */ + return IRQ_NONE; + + spin_lock(&q0->lock); + + if (unlikely(map & F_ERRINTR)) + t3_slow_intr_handler(adap); + + if (likely(map & 1)) + process_responses_gts(adap, q0); + + if (map & 2) + process_responses_gts(adap, &adap->sge.qs[1].rspq); + + spin_unlock(&q0->lock); + return IRQ_HANDLED; +} + +/* + * NAPI interrupt handler for legacy INTx interrupts for T3B-based cards. + * Handles data events from SGE response queues as well as error and other + * async events as they all use the same interrupt pin. We use one SGE + * response queue per port in this mode and protect all response queues with + * queue 0's lock. + */ +static irqreturn_t t3b_intr_napi(int irq, void *cookie) +{ + u32 map; + struct adapter *adap = cookie; + struct sge_qset *qs0 = &adap->sge.qs[0]; + struct sge_rspq *q0 = &qs0->rspq; + + t3_write_reg(adap, A_PL_CLI, 0); + map = t3_read_reg(adap, A_SG_DATA_INTR); + + if (unlikely(!map)) /* shared interrupt, most likely */ + return IRQ_NONE; + + spin_lock(&q0->lock); + + if (unlikely(map & F_ERRINTR)) + t3_slow_intr_handler(adap); + + if (likely(map & 1)) + napi_schedule(&qs0->napi); + + if (map & 2) + napi_schedule(&adap->sge.qs[1].napi); + + spin_unlock(&q0->lock); + return IRQ_HANDLED; +} + +/** + * t3_intr_handler - select the top-level interrupt handler + * @adap: the adapter + * @polling: whether using NAPI to service response queues + * + * Selects the top-level interrupt handler based on the type of interrupts + * (MSI-X, MSI, or legacy) and whether NAPI will be used to service the + * response queues. + */ +irq_handler_t t3_intr_handler(struct adapter *adap, int polling) +{ + if (adap->flags & USING_MSIX) + return polling ? t3_sge_intr_msix_napi : t3_sge_intr_msix; + if (adap->flags & USING_MSI) + return polling ? t3_intr_msi_napi : t3_intr_msi; + if (adap->params.rev > 0) + return polling ? t3b_intr_napi : t3b_intr; + return t3_intr; +} + +#define SGE_PARERR (F_CPPARITYERROR | F_OCPARITYERROR | F_RCPARITYERROR | \ + F_IRPARITYERROR | V_ITPARITYERROR(M_ITPARITYERROR) | \ + V_FLPARITYERROR(M_FLPARITYERROR) | F_LODRBPARITYERROR | \ + F_HIDRBPARITYERROR | F_LORCQPARITYERROR | \ + F_HIRCQPARITYERROR) +#define SGE_FRAMINGERR (F_UC_REQ_FRAMINGERROR | F_R_REQ_FRAMINGERROR) +#define SGE_FATALERR (SGE_PARERR | SGE_FRAMINGERR | F_RSPQCREDITOVERFOW | \ + F_RSPQDISABLED) + +/** + * t3_sge_err_intr_handler - SGE async event interrupt handler + * @adapter: the adapter + * + * Interrupt handler for SGE asynchronous (non-data) events. + */ +void t3_sge_err_intr_handler(struct adapter *adapter) +{ + unsigned int v, status = t3_read_reg(adapter, A_SG_INT_CAUSE) & + ~F_FLEMPTY; + + if (status & SGE_PARERR) + CH_ALERT(adapter, "SGE parity error (0x%x)\n", + status & SGE_PARERR); + if (status & SGE_FRAMINGERR) + CH_ALERT(adapter, "SGE framing error (0x%x)\n", + status & SGE_FRAMINGERR); + + if (status & F_RSPQCREDITOVERFOW) + CH_ALERT(adapter, "SGE response queue credit overflow\n"); + + if (status & F_RSPQDISABLED) { + v = t3_read_reg(adapter, A_SG_RSPQ_FL_STATUS); + + CH_ALERT(adapter, + "packet delivered to disabled response queue " + "(0x%x)\n", (v >> S_RSPQ0DISABLED) & 0xff); + } + + if (status & (F_HIPIODRBDROPERR | F_LOPIODRBDROPERR)) + queue_work(cxgb3_wq, &adapter->db_drop_task); + + if (status & (F_HIPRIORITYDBFULL | F_LOPRIORITYDBFULL)) + queue_work(cxgb3_wq, &adapter->db_full_task); + + if (status & (F_HIPRIORITYDBEMPTY | F_LOPRIORITYDBEMPTY)) + queue_work(cxgb3_wq, &adapter->db_empty_task); + + t3_write_reg(adapter, A_SG_INT_CAUSE, status); + if (status & SGE_FATALERR) + t3_fatal_err(adapter); +} + +/** + * sge_timer_tx - 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: + * + * 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. + * + */ +static void sge_timer_tx(unsigned long data) +{ + struct sge_qset *qs = (struct sge_qset *)data; + struct port_info *pi = netdev_priv(qs->netdev); + struct adapter *adap = pi->adapter; + unsigned int tbd[SGE_TXQ_PER_SET] = {0, 0}; + unsigned long next_period; + + if (__netif_tx_trylock(qs->tx_q)) { + tbd[TXQ_ETH] = reclaim_completed_tx(adap, &qs->txq[TXQ_ETH], + TX_RECLAIM_TIMER_CHUNK); + __netif_tx_unlock(qs->tx_q); + } + + if (spin_trylock(&qs->txq[TXQ_OFLD].lock)) { + tbd[TXQ_OFLD] = reclaim_completed_tx(adap, &qs->txq[TXQ_OFLD], + TX_RECLAIM_TIMER_CHUNK); + spin_unlock(&qs->txq[TXQ_OFLD].lock); + } + + next_period = TX_RECLAIM_PERIOD >> + (max(tbd[TXQ_ETH], tbd[TXQ_OFLD]) / + TX_RECLAIM_TIMER_CHUNK); + mod_timer(&qs->tx_reclaim_timer, jiffies + next_period); +} + +/* + * sge_timer_rx - perform periodic maintenance of an SGE qset + * @data: the SGE queue set to maintain + * + * a) 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. + * + * b) Return coalesced response queue credits in case a response queue is + * starved. + * + */ +static void sge_timer_rx(unsigned long data) +{ + spinlock_t *lock; + struct sge_qset *qs = (struct sge_qset *)data; + struct port_info *pi = netdev_priv(qs->netdev); + struct adapter *adap = pi->adapter; + u32 status; + + lock = adap->params.rev > 0 ? + &qs->rspq.lock : &adap->sge.qs[0].rspq.lock; + + if (!spin_trylock_irq(lock)) + goto out; + + if (napi_is_scheduled(&qs->napi)) + goto unlock; + + if (adap->params.rev < 4) { + status = t3_read_reg(adap, A_SG_RSPQ_FL_STATUS); + + if (status & (1 << qs->rspq.cntxt_id)) { + qs->rspq.starved++; + if (qs->rspq.credits) { + qs->rspq.credits--; + refill_rspq(adap, &qs->rspq, 1); + qs->rspq.restarted++; + t3_write_reg(adap, A_SG_RSPQ_FL_STATUS, + 1 << qs->rspq.cntxt_id); + } + } + } + + if (qs->fl[0].credits < qs->fl[0].size) + __refill_fl(adap, &qs->fl[0]); + if (qs->fl[1].credits < qs->fl[1].size) + __refill_fl(adap, &qs->fl[1]); + +unlock: + spin_unlock_irq(lock); +out: + mod_timer(&qs->rx_reclaim_timer, jiffies + RX_RECLAIM_PERIOD); +} + +/** + * t3_update_qset_coalesce - update coalescing settings for a queue set + * @qs: the SGE queue set + * @p: new queue set parameters + * + * Update the coalescing settings for an SGE queue set. Nothing is done + * if the queue set is not initialized yet. + */ +void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p) +{ + qs->rspq.holdoff_tmr = max(p->coalesce_usecs * 10, 1U);/* can't be 0 */ + qs->rspq.polling = p->polling; + qs->napi.poll = p->polling ? napi_rx_handler : ofld_poll; +} + +/** + * t3_sge_alloc_qset - initialize an SGE queue set + * @adapter: the adapter + * @id: the queue set id + * @nports: how many Ethernet ports will be using this queue set + * @irq_vec_idx: the IRQ vector index for response queue interrupts + * @p: configuration parameters for this queue set + * @ntxq: number of Tx queues for the queue set + * @netdev: net device associated with this queue set + * @netdevq: net device TX queue associated with this queue set + * + * Allocate resources and initialize an SGE queue set. A queue set + * comprises a response queue, two Rx free-buffer queues, and up to 3 + * Tx queues. The Tx queues are assigned roles in the order Ethernet + * queue, offload queue, and control queue. + */ +int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, + int irq_vec_idx, const struct qset_params *p, + int ntxq, struct net_device *dev, + struct netdev_queue *netdevq) +{ + int i, avail, ret = -ENOMEM; + struct sge_qset *q = &adapter->sge.qs[id]; + + init_qset_cntxt(q, id); + setup_timer(&q->tx_reclaim_timer, sge_timer_tx, (unsigned long)q); + setup_timer(&q->rx_reclaim_timer, sge_timer_rx, (unsigned long)q); + + q->fl[0].desc = alloc_ring(adapter->pdev, p->fl_size, + sizeof(struct rx_desc), + sizeof(struct rx_sw_desc), + &q->fl[0].phys_addr, &q->fl[0].sdesc); + if (!q->fl[0].desc) + goto err; + + q->fl[1].desc = alloc_ring(adapter->pdev, p->jumbo_size, + sizeof(struct rx_desc), + sizeof(struct rx_sw_desc), + &q->fl[1].phys_addr, &q->fl[1].sdesc); + if (!q->fl[1].desc) + goto err; + + q->rspq.desc = alloc_ring(adapter->pdev, p->rspq_size, + sizeof(struct rsp_desc), 0, + &q->rspq.phys_addr, NULL); + if (!q->rspq.desc) + goto err; + + for (i = 0; i < ntxq; ++i) { + /* + * The control queue always uses immediate data so does not + * need to keep track of any sk_buffs. + */ + size_t sz = i == TXQ_CTRL ? 0 : sizeof(struct tx_sw_desc); + + q->txq[i].desc = alloc_ring(adapter->pdev, p->txq_size[i], + sizeof(struct tx_desc), sz, + &q->txq[i].phys_addr, + &q->txq[i].sdesc); + if (!q->txq[i].desc) + goto err; + + q->txq[i].gen = 1; + q->txq[i].size = p->txq_size[i]; + spin_lock_init(&q->txq[i].lock); + skb_queue_head_init(&q->txq[i].sendq); + } + + tasklet_init(&q->txq[TXQ_OFLD].qresume_tsk, restart_offloadq, + (unsigned long)q); + tasklet_init(&q->txq[TXQ_CTRL].qresume_tsk, restart_ctrlq, + (unsigned long)q); + + 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.size = p->rspq_size; + spin_lock_init(&q->rspq.lock); + skb_queue_head_init(&q->rspq.rx_queue); + + q->txq[TXQ_ETH].stop_thres = nports * + flits_to_desc(sgl_len(MAX_SKB_FRAGS + 1) + 3); + +#if FL0_PG_CHUNK_SIZE > 0 + q->fl[0].buf_size = FL0_PG_CHUNK_SIZE; +#else + q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + sizeof(struct cpl_rx_data); +#endif +#if FL1_PG_CHUNK_SIZE > 0 + q->fl[1].buf_size = FL1_PG_CHUNK_SIZE; +#else + q->fl[1].buf_size = is_offload(adapter) ? + (16 * 1024) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) : + MAX_FRAME_SIZE + 2 + sizeof(struct cpl_rx_pkt); +#endif + + q->fl[0].use_pages = FL0_PG_CHUNK_SIZE > 0; + q->fl[1].use_pages = FL1_PG_CHUNK_SIZE > 0; + q->fl[0].order = FL0_PG_ORDER; + q->fl[1].order = FL1_PG_ORDER; + q->fl[0].alloc_size = FL0_PG_ALLOC_SIZE; + q->fl[1].alloc_size = FL1_PG_ALLOC_SIZE; + + spin_lock_irq(&adapter->sge.reg_lock); + + /* FL threshold comparison uses < */ + ret = t3_sge_init_rspcntxt(adapter, q->rspq.cntxt_id, irq_vec_idx, + q->rspq.phys_addr, q->rspq.size, + q->fl[0].buf_size - SGE_PG_RSVD, 1, 0); + if (ret) + goto err_unlock; + + for (i = 0; i < SGE_RXQ_PER_SET; ++i) { + ret = t3_sge_init_flcntxt(adapter, q->fl[i].cntxt_id, 0, + q->fl[i].phys_addr, q->fl[i].size, + q->fl[i].buf_size - SGE_PG_RSVD, + p->cong_thres, 1, 0); + if (ret) + goto err_unlock; + } + + ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_ETH].cntxt_id, USE_GTS, + SGE_CNTXT_ETH, id, q->txq[TXQ_ETH].phys_addr, + q->txq[TXQ_ETH].size, q->txq[TXQ_ETH].token, + 1, 0); + if (ret) + goto err_unlock; + + if (ntxq > 1) { + ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_OFLD].cntxt_id, + USE_GTS, SGE_CNTXT_OFLD, id, + q->txq[TXQ_OFLD].phys_addr, + q->txq[TXQ_OFLD].size, 0, 1, 0); + if (ret) + goto err_unlock; + } + + if (ntxq > 2) { + ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_CTRL].cntxt_id, 0, + SGE_CNTXT_CTRL, id, + q->txq[TXQ_CTRL].phys_addr, + q->txq[TXQ_CTRL].size, + q->txq[TXQ_CTRL].token, 1, 0); + if (ret) + goto err_unlock; + } + + spin_unlock_irq(&adapter->sge.reg_lock); + + q->adap = adapter; + q->netdev = dev; + q->tx_q = netdevq; + t3_update_qset_coalesce(q, p); + + avail = refill_fl(adapter, &q->fl[0], q->fl[0].size, + GFP_KERNEL | __GFP_COMP); + if (!avail) { + CH_ALERT(adapter, "free list queue 0 initialization failed\n"); + goto err; + } + if (avail < q->fl[0].size) + CH_WARN(adapter, "free list queue 0 enabled with %d credits\n", + avail); + + avail = refill_fl(adapter, &q->fl[1], q->fl[1].size, + GFP_KERNEL | __GFP_COMP); + if (avail < q->fl[1].size) + CH_WARN(adapter, "free list queue 1 enabled with %d credits\n", + avail); + refill_rspq(adapter, &q->rspq, q->rspq.size - 1); + + t3_write_reg(adapter, A_SG_GTS, V_RSPQ(q->rspq.cntxt_id) | + V_NEWTIMER(q->rspq.holdoff_tmr)); + + return 0; + +err_unlock: + spin_unlock_irq(&adapter->sge.reg_lock); +err: + t3_free_qset(adapter, q); + return ret; +} + +/** + * t3_start_sge_timers - start SGE timer call backs + * @adap: the adapter + * + * Starts each SGE queue set's timer call back + */ +void t3_start_sge_timers(struct adapter *adap) +{ + int i; + + for (i = 0; i < SGE_QSETS; ++i) { + struct sge_qset *q = &adap->sge.qs[i]; + + if (q->tx_reclaim_timer.function) + mod_timer(&q->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD); + + if (q->rx_reclaim_timer.function) + mod_timer(&q->rx_reclaim_timer, jiffies + RX_RECLAIM_PERIOD); + } +} + +/** + * t3_stop_sge_timers - stop SGE timer call backs + * @adap: the adapter + * + * Stops each SGE queue set's timer call back + */ +void t3_stop_sge_timers(struct adapter *adap) +{ + int i; + + for (i = 0; i < SGE_QSETS; ++i) { + struct sge_qset *q = &adap->sge.qs[i]; + + if (q->tx_reclaim_timer.function) + del_timer_sync(&q->tx_reclaim_timer); + if (q->rx_reclaim_timer.function) + del_timer_sync(&q->rx_reclaim_timer); + } +} + +/** + * t3_free_sge_resources - free SGE resources + * @adap: the adapter + * + * Frees resources used by the SGE queue sets. + */ +void t3_free_sge_resources(struct adapter *adap) +{ + int i; + + for (i = 0; i < SGE_QSETS; ++i) + t3_free_qset(adap, &adap->sge.qs[i]); +} + +/** + * t3_sge_start - enable SGE + * @adap: the adapter + * + * Enables the SGE for DMAs. This is the last step in starting packet + * transfers. + */ +void t3_sge_start(struct adapter *adap) +{ + t3_set_reg_field(adap, A_SG_CONTROL, F_GLOBALENABLE, F_GLOBALENABLE); +} + +/** + * t3_sge_stop - disable SGE operation + * @adap: the adapter + * + * Disables the DMA engine. This can be called in emeregencies (e.g., + * from error interrupts) or from normal process context. In the latter + * case it also disables any pending queue restart tasklets. Note that + * if it is called in interrupt context it cannot disable the restart + * tasklets as it cannot wait, however the tasklets will have no effect + * since the doorbells are disabled and the driver will call this again + * later from process context, at which time the tasklets will be stopped + * if they are still running. + */ +void t3_sge_stop(struct adapter *adap) +{ + t3_set_reg_field(adap, A_SG_CONTROL, F_GLOBALENABLE, 0); + if (!in_interrupt()) { + int i; + + for (i = 0; i < SGE_QSETS; ++i) { + struct sge_qset *qs = &adap->sge.qs[i]; + + tasklet_kill(&qs->txq[TXQ_OFLD].qresume_tsk); + tasklet_kill(&qs->txq[TXQ_CTRL].qresume_tsk); + } + } +} + +/** + * t3_sge_init - initialize SGE + * @adap: the adapter + * @p: the SGE parameters + * + * Performs SGE initialization needed every time after a chip reset. + * We do not initialize any of the queue sets here, instead the driver + * top-level must request those individually. We also do not enable DMA + * here, that should be done after the queues have been set up. + */ +void t3_sge_init(struct adapter *adap, struct sge_params *p) +{ + unsigned int ctrl, ups = ffs(pci_resource_len(adap->pdev, 2) >> 12); + + ctrl = F_DROPPKT | V_PKTSHIFT(2) | F_FLMODE | F_AVOIDCQOVFL | + F_CQCRDTCTRL | F_CONGMODE | F_TNLFLMODE | F_FATLPERREN | + V_HOSTPAGESIZE(PAGE_SHIFT - 11) | F_BIGENDIANINGRESS | + V_USERSPACESIZE(ups ? ups - 1 : 0) | F_ISCSICOALESCING; +#if SGE_NUM_GENBITS == 1 + ctrl |= F_EGRGENCTRL; +#endif + if (adap->params.rev > 0) { + if (!(adap->flags & (USING_MSIX | USING_MSI))) + ctrl |= F_ONEINTMULTQ | F_OPTONEINTMULTQ; + } + t3_write_reg(adap, A_SG_CONTROL, ctrl); + t3_write_reg(adap, A_SG_EGR_RCQ_DRB_THRSH, V_HIRCQDRBTHRSH(512) | + V_LORCQDRBTHRSH(512)); + t3_write_reg(adap, A_SG_TIMER_TICK, core_ticks_per_usec(adap) / 10); + t3_write_reg(adap, A_SG_CMDQ_CREDIT_TH, V_THRESHOLD(32) | + V_TIMEOUT(200 * core_ticks_per_usec(adap))); + t3_write_reg(adap, A_SG_HI_DRB_HI_THRSH, + adap->params.rev < T3_REV_C ? 1000 : 500); + t3_write_reg(adap, A_SG_HI_DRB_LO_THRSH, 256); + t3_write_reg(adap, A_SG_LO_DRB_HI_THRSH, 1000); + t3_write_reg(adap, A_SG_LO_DRB_LO_THRSH, 256); + t3_write_reg(adap, A_SG_OCO_BASE, V_BASE1(0xfff)); + t3_write_reg(adap, A_SG_DRB_PRI_THRESH, 63 * 1024); +} + +/** + * t3_sge_prep - one-time SGE initialization + * @adap: the associated adapter + * @p: SGE parameters + * + * Performs one-time initialization of SGE SW state. Includes determining + * defaults for the assorted SGE parameters, which admins can change until + * they are used to initialize the SGE. + */ +void t3_sge_prep(struct adapter *adap, struct sge_params *p) +{ + int i; + + p->max_pkt_size = (16 * 1024) - sizeof(struct cpl_rx_data) - + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + + for (i = 0; i < SGE_QSETS; ++i) { + struct qset_params *q = p->qset + i; + + q->polling = adap->params.rev > 0; + q->coalesce_usecs = 5; + q->rspq_size = 1024; + q->fl_size = 1024; + q->jumbo_size = 512; + q->txq_size[TXQ_ETH] = 1024; + q->txq_size[TXQ_OFLD] = 1024; + q->txq_size[TXQ_CTRL] = 256; + q->cong_thres = 0; + } + + spin_lock_init(&adap->sge.reg_lock); +} diff --git a/drivers/net/ethernet/chelsio/cxgb3/sge_defs.h b/drivers/net/ethernet/chelsio/cxgb3/sge_defs.h new file mode 100644 index 000000000000..29b6c800b238 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb3/sge_defs.h @@ -0,0 +1,255 @@ +/* + * This file is automatically generated --- any changes will be lost. + */ + +#ifndef _SGE_DEFS_H +#define _SGE_DEFS_H + +#define S_EC_CREDITS 0 +#define M_EC_CREDITS 0x7FFF +#define V_EC_CREDITS(x) ((x) << S_EC_CREDITS) +#define G_EC_CREDITS(x) (((x) >> S_EC_CREDITS) & M_EC_CREDITS) + +#define S_EC_GTS 15 +#define V_EC_GTS(x) ((x) << S_EC_GTS) +#define F_EC_GTS V_EC_GTS(1U) + +#define S_EC_INDEX 16 +#define M_EC_INDEX 0xFFFF +#define V_EC_INDEX(x) ((x) << S_EC_INDEX) +#define G_EC_INDEX(x) (((x) >> S_EC_INDEX) & M_EC_INDEX) + +#define S_EC_SIZE 0 +#define M_EC_SIZE 0xFFFF +#define V_EC_SIZE(x) ((x) << S_EC_SIZE) +#define G_EC_SIZE(x) (((x) >> S_EC_SIZE) & M_EC_SIZE) + +#define S_EC_BASE_LO 16 +#define M_EC_BASE_LO 0xFFFF +#define V_EC_BASE_LO(x) ((x) << S_EC_BASE_LO) +#define G_EC_BASE_LO(x) (((x) >> S_EC_BASE_LO) & M_EC_BASE_LO) + +#define S_EC_BASE_HI 0 +#define M_EC_BASE_HI 0xF +#define V_EC_BASE_HI(x) ((x) << S_EC_BASE_HI) +#define G_EC_BASE_HI(x) (((x) >> S_EC_BASE_HI) & M_EC_BASE_HI) + +#define S_EC_RESPQ 4 +#define M_EC_RESPQ 0x7 +#define V_EC_RESPQ(x) ((x) << S_EC_RESPQ) +#define G_EC_RESPQ(x) (((x) >> S_EC_RESPQ) & M_EC_RESPQ) + +#define S_EC_TYPE 7 +#define M_EC_TYPE 0x7 +#define V_EC_TYPE(x) ((x) << S_EC_TYPE) +#define G_EC_TYPE(x) (((x) >> S_EC_TYPE) & M_EC_TYPE) + +#define S_EC_GEN 10 +#define V_EC_GEN(x) ((x) << S_EC_GEN) +#define F_EC_GEN V_EC_GEN(1U) + +#define S_EC_UP_TOKEN 11 +#define M_EC_UP_TOKEN 0xFFFFF +#define V_EC_UP_TOKEN(x) ((x) << S_EC_UP_TOKEN) +#define G_EC_UP_TOKEN(x) (((x) >> S_EC_UP_TOKEN) & M_EC_UP_TOKEN) + +#define S_EC_VALID 31 +#define V_EC_VALID(x) ((x) << S_EC_VALID) +#define F_EC_VALID V_EC_VALID(1U) + +#define S_RQ_MSI_VEC 20 +#define M_RQ_MSI_VEC 0x3F +#define V_RQ_MSI_VEC(x) ((x) << S_RQ_MSI_VEC) +#define G_RQ_MSI_VEC(x) (((x) >> S_RQ_MSI_VEC) & M_RQ_MSI_VEC) + +#define S_RQ_INTR_EN 26 +#define V_RQ_INTR_EN(x) ((x) << S_RQ_INTR_EN) +#define F_RQ_INTR_EN V_RQ_INTR_EN(1U) + +#define S_RQ_GEN 28 +#define V_RQ_GEN(x) ((x) << S_RQ_GEN) +#define F_RQ_GEN V_RQ_GEN(1U) + +#define S_CQ_INDEX 0 +#define M_CQ_INDEX 0xFFFF +#define V_CQ_INDEX(x) ((x) << S_CQ_INDEX) +#define G_CQ_INDEX(x) (((x) >> S_CQ_INDEX) & M_CQ_INDEX) + +#define S_CQ_SIZE 16 +#define M_CQ_SIZE 0xFFFF +#define V_CQ_SIZE(x) ((x) << S_CQ_SIZE) +#define G_CQ_SIZE(x) (((x) >> S_CQ_SIZE) & M_CQ_SIZE) + +#define S_CQ_BASE_HI 0 +#define M_CQ_BASE_HI 0xFFFFF +#define V_CQ_BASE_HI(x) ((x) << S_CQ_BASE_HI) +#define G_CQ_BASE_HI(x) (((x) >> S_CQ_BASE_HI) & M_CQ_BASE_HI) + +#define S_CQ_RSPQ 20 +#define M_CQ_RSPQ 0x3F +#define V_CQ_RSPQ(x) ((x) << S_CQ_RSPQ) +#define G_CQ_RSPQ(x) (((x) >> S_CQ_RSPQ) & M_CQ_RSPQ) + +#define S_CQ_ASYNC_NOTIF 26 +#define V_CQ_ASYNC_NOTIF(x) ((x) << S_CQ_ASYNC_NOTIF) +#define F_CQ_ASYNC_NOTIF V_CQ_ASYNC_NOTIF(1U) + +#define S_CQ_ARMED 27 +#define V_CQ_ARMED(x) ((x) << S_CQ_ARMED) +#define F_CQ_ARMED V_CQ_ARMED(1U) + +#define S_CQ_ASYNC_NOTIF_SOL 28 +#define V_CQ_ASYNC_NOTIF_SOL(x) ((x) << S_CQ_ASYNC_NOTIF_SOL) +#define F_CQ_ASYNC_NOTIF_SOL V_CQ_ASYNC_NOTIF_SOL(1U) + +#define S_CQ_GEN 29 +#define V_CQ_GEN(x) ((x) << S_CQ_GEN) +#define F_CQ_GEN V_CQ_GEN(1U) + +#define S_CQ_ERR 30 +#define V_CQ_ERR(x) ((x) << S_CQ_ERR) +#define F_CQ_ERR V_CQ_ERR(1U) + +#define S_CQ_OVERFLOW_MODE 31 +#define V_CQ_OVERFLOW_MODE(x) ((x) << S_CQ_OVERFLOW_MODE) +#define F_CQ_OVERFLOW_MODE V_CQ_OVERFLOW_MODE(1U) + +#define S_CQ_CREDITS 0 +#define M_CQ_CREDITS 0xFFFF +#define V_CQ_CREDITS(x) ((x) << S_CQ_CREDITS) +#define G_CQ_CREDITS(x) (((x) >> S_CQ_CREDITS) & M_CQ_CREDITS) + +#define S_CQ_CREDIT_THRES 16 +#define M_CQ_CREDIT_THRES 0x1FFF +#define V_CQ_CREDIT_THRES(x) ((x) << S_CQ_CREDIT_THRES) +#define G_CQ_CREDIT_THRES(x) (((x) >> S_CQ_CREDIT_THRES) & M_CQ_CREDIT_THRES) + +#define S_FL_BASE_HI 0 +#define M_FL_BASE_HI 0xFFFFF +#define V_FL_BASE_HI(x) ((x) << S_FL_BASE_HI) +#define G_FL_BASE_HI(x) (((x) >> S_FL_BASE_HI) & M_FL_BASE_HI) + +#define S_FL_INDEX_LO 20 +#define M_FL_INDEX_LO 0xFFF +#define V_FL_INDEX_LO(x) ((x) << S_FL_INDEX_LO) +#define G_FL_INDEX_LO(x) (((x) >> S_FL_INDEX_LO) & M_FL_INDEX_LO) + +#define S_FL_INDEX_HI 0 +#define M_FL_INDEX_HI 0xF +#define V_FL_INDEX_HI(x) ((x) << S_FL_INDEX_HI) +#define G_FL_INDEX_HI(x) (((x) >> S_FL_INDEX_HI) & M_FL_INDEX_HI) + +#define S_FL_SIZE 4 +#define M_FL_SIZE 0xFFFF +#define V_FL_SIZE(x) ((x) << S_FL_SIZE) +#define G_FL_SIZE(x) (((x) >> S_FL_SIZE) & M_FL_SIZE) + +#define S_FL_GEN 20 +#define V_FL_GEN(x) ((x) << S_FL_GEN) +#define F_FL_GEN V_FL_GEN(1U) + +#define S_FL_ENTRY_SIZE_LO 21 +#define M_FL_ENTRY_SIZE_LO 0x7FF +#define V_FL_ENTRY_SIZE_LO(x) ((x) << S_FL_ENTRY_SIZE_LO) +#define G_FL_ENTRY_SIZE_LO(x) (((x) >> S_FL_ENTRY_SIZE_LO) & M_FL_ENTRY_SIZE_LO) + +#define S_FL_ENTRY_SIZE_HI 0 +#define M_FL_ENTRY_SIZE_HI 0x1FFFFF +#define V_FL_ENTRY_SIZE_HI(x) ((x) << S_FL_ENTRY_SIZE_HI) +#define G_FL_ENTRY_SIZE_HI(x) (((x) >> S_FL_ENTRY_SIZE_HI) & M_FL_ENTRY_SIZE_HI) + +#define S_FL_CONG_THRES 21 +#define M_FL_CONG_THRES 0x3FF +#define V_FL_CONG_THRES(x) ((x) << S_FL_CONG_THRES) +#define G_FL_CONG_THRES(x) (((x) >> S_FL_CONG_THRES) & M_FL_CONG_THRES) + +#define S_FL_GTS 31 +#define V_FL_GTS(x) ((x) << S_FL_GTS) +#define F_FL_GTS V_FL_GTS(1U) + +#define S_FLD_GEN1 31 +#define V_FLD_GEN1(x) ((x) << S_FLD_GEN1) +#define F_FLD_GEN1 V_FLD_GEN1(1U) + +#define S_FLD_GEN2 0 +#define V_FLD_GEN2(x) ((x) << S_FLD_GEN2) +#define F_FLD_GEN2 V_FLD_GEN2(1U) + +#define S_RSPD_TXQ1_CR 0 +#define M_RSPD_TXQ1_CR 0x7F +#define V_RSPD_TXQ1_CR(x) ((x) << S_RSPD_TXQ1_CR) +#define G_RSPD_TXQ1_CR(x) (((x) >> S_RSPD_TXQ1_CR) & M_RSPD_TXQ1_CR) + +#define S_RSPD_TXQ1_GTS 7 +#define V_RSPD_TXQ1_GTS(x) ((x) << S_RSPD_TXQ1_GTS) +#define F_RSPD_TXQ1_GTS V_RSPD_TXQ1_GTS(1U) + +#define S_RSPD_TXQ2_CR 8 +#define M_RSPD_TXQ2_CR 0x7F +#define V_RSPD_TXQ2_CR(x) ((x) << S_RSPD_TXQ2_CR) +#define G_RSPD_TXQ2_CR(x) (((x) >> S_RSPD_TXQ2_CR) & M_RSPD_TXQ2_CR) + +#define S_RSPD_TXQ2_GTS 15 +#define V_RSPD_TXQ2_GTS(x) ((x) << S_RSPD_TXQ2_GTS) +#define F_RSPD_TXQ2_GTS V_RSPD_TXQ2_GTS(1U) + +#define S_RSPD_TXQ0_CR 16 +#define M_RSPD_TXQ0_CR 0x7F +#define V_RSPD_TXQ0_CR(x) ((x) << S_RSPD_TXQ0_CR) +#define G_RSPD_TXQ0_CR(x) (((x) >> S_RSPD_TXQ0_CR) & M_RSPD_TXQ0_CR) + +#define S_RSPD_TXQ0_GTS 23 +#define V_RSPD_TXQ0_GTS(x) ((x) << S_RSPD_TXQ0_GTS) +#define F_RSPD_TXQ0_GTS V_RSPD_TXQ0_GTS(1U) + +#define S_RSPD_EOP 24 +#define V_RSPD_EOP(x) ((x) << S_RSPD_EOP) +#define F_RSPD_EOP V_RSPD_EOP(1U) + +#define S_RSPD_SOP 25 +#define V_RSPD_SOP(x) ((x) << S_RSPD_SOP) +#define F_RSPD_SOP V_RSPD_SOP(1U) + +#define S_RSPD_ASYNC_NOTIF 26 +#define V_RSPD_ASYNC_NOTIF(x) ((x) << S_RSPD_ASYNC_NOTIF) +#define F_RSPD_ASYNC_NOTIF V_RSPD_ASYNC_NOTIF(1U) + +#define S_RSPD_FL0_GTS 27 +#define V_RSPD_FL0_GTS(x) ((x) << S_RSPD_FL0_GTS) +#define F_RSPD_FL0_GTS V_RSPD_FL0_GTS(1U) + +#define S_RSPD_FL1_GTS 28 +#define V_RSPD_FL1_GTS(x) ((x) << S_RSPD_FL1_GTS) +#define F_RSPD_FL1_GTS V_RSPD_FL1_GTS(1U) + +#define S_RSPD_IMM_DATA_VALID 29 +#define V_RSPD_IMM_DATA_VALID(x) ((x) << S_RSPD_IMM_DATA_VALID) +#define F_RSPD_IMM_DATA_VALID V_RSPD_IMM_DATA_VALID(1U) + +#define S_RSPD_OFFLOAD 30 +#define V_RSPD_OFFLOAD(x) ((x) << S_RSPD_OFFLOAD) +#define F_RSPD_OFFLOAD V_RSPD_OFFLOAD(1U) + +#define S_RSPD_GEN1 31 +#define V_RSPD_GEN1(x) ((x) << S_RSPD_GEN1) +#define F_RSPD_GEN1 V_RSPD_GEN1(1U) + +#define S_RSPD_LEN 0 +#define M_RSPD_LEN 0x7FFFFFFF +#define V_RSPD_LEN(x) ((x) << S_RSPD_LEN) +#define G_RSPD_LEN(x) (((x) >> S_RSPD_LEN) & M_RSPD_LEN) + +#define S_RSPD_FLQ 31 +#define V_RSPD_FLQ(x) ((x) << S_RSPD_FLQ) +#define F_RSPD_FLQ V_RSPD_FLQ(1U) + +#define S_RSPD_GEN2 0 +#define V_RSPD_GEN2(x) ((x) << S_RSPD_GEN2) +#define F_RSPD_GEN2 V_RSPD_GEN2(1U) + +#define S_RSPD_INR_VEC 1 +#define M_RSPD_INR_VEC 0x7F +#define V_RSPD_INR_VEC(x) ((x) << S_RSPD_INR_VEC) +#define G_RSPD_INR_VEC(x) (((x) >> S_RSPD_INR_VEC) & M_RSPD_INR_VEC) + +#endif /* _SGE_DEFS_H */ diff --git a/drivers/net/ethernet/chelsio/cxgb3/t3_cpl.h b/drivers/net/ethernet/chelsio/cxgb3/t3_cpl.h new file mode 100644 index 000000000000..852c399a8b0a --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb3/t3_cpl.h @@ -0,0 +1,1495 @@ +/* + * Copyright (c) 2004-2008 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef T3_CPL_H +#define T3_CPL_H + +#if !defined(__LITTLE_ENDIAN_BITFIELD) && !defined(__BIG_ENDIAN_BITFIELD) +# include +#endif + +enum CPL_opcode { + CPL_PASS_OPEN_REQ = 0x1, + CPL_PASS_ACCEPT_RPL = 0x2, + CPL_ACT_OPEN_REQ = 0x3, + CPL_SET_TCB = 0x4, + CPL_SET_TCB_FIELD = 0x5, + CPL_GET_TCB = 0x6, + CPL_PCMD = 0x7, + CPL_CLOSE_CON_REQ = 0x8, + CPL_CLOSE_LISTSRV_REQ = 0x9, + CPL_ABORT_REQ = 0xA, + CPL_ABORT_RPL = 0xB, + CPL_TX_DATA = 0xC, + CPL_RX_DATA_ACK = 0xD, + CPL_TX_PKT = 0xE, + CPL_RTE_DELETE_REQ = 0xF, + CPL_RTE_WRITE_REQ = 0x10, + CPL_RTE_READ_REQ = 0x11, + CPL_L2T_WRITE_REQ = 0x12, + CPL_L2T_READ_REQ = 0x13, + CPL_SMT_WRITE_REQ = 0x14, + CPL_SMT_READ_REQ = 0x15, + CPL_TX_PKT_LSO = 0x16, + CPL_PCMD_READ = 0x17, + CPL_BARRIER = 0x18, + CPL_TID_RELEASE = 0x1A, + + CPL_CLOSE_LISTSRV_RPL = 0x20, + CPL_ERROR = 0x21, + CPL_GET_TCB_RPL = 0x22, + CPL_L2T_WRITE_RPL = 0x23, + CPL_PCMD_READ_RPL = 0x24, + CPL_PCMD_RPL = 0x25, + CPL_PEER_CLOSE = 0x26, + CPL_RTE_DELETE_RPL = 0x27, + CPL_RTE_WRITE_RPL = 0x28, + CPL_RX_DDP_COMPLETE = 0x29, + CPL_RX_PHYS_ADDR = 0x2A, + CPL_RX_PKT = 0x2B, + CPL_RX_URG_NOTIFY = 0x2C, + CPL_SET_TCB_RPL = 0x2D, + CPL_SMT_WRITE_RPL = 0x2E, + CPL_TX_DATA_ACK = 0x2F, + + CPL_ABORT_REQ_RSS = 0x30, + CPL_ABORT_RPL_RSS = 0x31, + CPL_CLOSE_CON_RPL = 0x32, + CPL_ISCSI_HDR = 0x33, + CPL_L2T_READ_RPL = 0x34, + CPL_RDMA_CQE = 0x35, + CPL_RDMA_CQE_READ_RSP = 0x36, + CPL_RDMA_CQE_ERR = 0x37, + CPL_RTE_READ_RPL = 0x38, + CPL_RX_DATA = 0x39, + + CPL_ACT_OPEN_RPL = 0x40, + CPL_PASS_OPEN_RPL = 0x41, + CPL_RX_DATA_DDP = 0x42, + CPL_SMT_READ_RPL = 0x43, + + CPL_ACT_ESTABLISH = 0x50, + CPL_PASS_ESTABLISH = 0x51, + + CPL_PASS_ACCEPT_REQ = 0x70, + + CPL_ASYNC_NOTIF = 0x80, /* fake opcode for async notifications */ + + CPL_TX_DMA_ACK = 0xA0, + CPL_RDMA_READ_REQ = 0xA1, + CPL_RDMA_TERMINATE = 0xA2, + CPL_TRACE_PKT = 0xA3, + CPL_RDMA_EC_STATUS = 0xA5, + + NUM_CPL_CMDS /* must be last and previous entries must be sorted */ +}; + +enum CPL_error { + CPL_ERR_NONE = 0, + CPL_ERR_TCAM_PARITY = 1, + CPL_ERR_TCAM_FULL = 3, + CPL_ERR_CONN_RESET = 20, + CPL_ERR_CONN_EXIST = 22, + CPL_ERR_ARP_MISS = 23, + CPL_ERR_BAD_SYN = 24, + CPL_ERR_CONN_TIMEDOUT = 30, + CPL_ERR_XMIT_TIMEDOUT = 31, + CPL_ERR_PERSIST_TIMEDOUT = 32, + CPL_ERR_FINWAIT2_TIMEDOUT = 33, + CPL_ERR_KEEPALIVE_TIMEDOUT = 34, + CPL_ERR_RTX_NEG_ADVICE = 35, + CPL_ERR_PERSIST_NEG_ADVICE = 36, + CPL_ERR_ABORT_FAILED = 42, + CPL_ERR_GENERAL = 99 +}; + +enum { + CPL_CONN_POLICY_AUTO = 0, + CPL_CONN_POLICY_ASK = 1, + CPL_CONN_POLICY_DENY = 3 +}; + +enum { + ULP_MODE_NONE = 0, + ULP_MODE_ISCSI = 2, + ULP_MODE_RDMA = 4, + ULP_MODE_TCPDDP = 5 +}; + +enum { + ULP_CRC_HEADER = 1 << 0, + ULP_CRC_DATA = 1 << 1 +}; + +enum { + CPL_PASS_OPEN_ACCEPT, + CPL_PASS_OPEN_REJECT +}; + +enum { + CPL_ABORT_SEND_RST = 0, + CPL_ABORT_NO_RST, + CPL_ABORT_POST_CLOSE_REQ = 2 +}; + +enum { /* TX_PKT_LSO ethernet types */ + CPL_ETH_II, + CPL_ETH_II_VLAN, + CPL_ETH_802_3, + CPL_ETH_802_3_VLAN +}; + +enum { /* TCP congestion control algorithms */ + CONG_ALG_RENO, + CONG_ALG_TAHOE, + CONG_ALG_NEWRENO, + CONG_ALG_HIGHSPEED +}; + +enum { /* RSS hash type */ + RSS_HASH_NONE = 0, + RSS_HASH_2_TUPLE = 1, + RSS_HASH_4_TUPLE = 2, + RSS_HASH_TCPV6 = 3 +}; + +union opcode_tid { + __be32 opcode_tid; + __u8 opcode; +}; + +#define S_OPCODE 24 +#define V_OPCODE(x) ((x) << S_OPCODE) +#define G_OPCODE(x) (((x) >> S_OPCODE) & 0xFF) +#define G_TID(x) ((x) & 0xFFFFFF) + +#define S_QNUM 0 +#define G_QNUM(x) (((x) >> S_QNUM) & 0xFFFF) + +#define S_HASHTYPE 22 +#define M_HASHTYPE 0x3 +#define G_HASHTYPE(x) (((x) >> S_HASHTYPE) & M_HASHTYPE) + +/* tid is assumed to be 24-bits */ +#define MK_OPCODE_TID(opcode, tid) (V_OPCODE(opcode) | (tid)) + +#define OPCODE_TID(cmd) ((cmd)->ot.opcode_tid) + +/* extract the TID from a CPL command */ +#define GET_TID(cmd) (G_TID(ntohl(OPCODE_TID(cmd)))) + +struct tcp_options { + __be16 mss; + __u8 wsf; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8:5; + __u8 ecn:1; + __u8 sack:1; + __u8 tstamp:1; +#else + __u8 tstamp:1; + __u8 sack:1; + __u8 ecn:1; + __u8:5; +#endif +}; + +struct rss_header { + __u8 opcode; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 cpu_idx:6; + __u8 hash_type:2; +#else + __u8 hash_type:2; + __u8 cpu_idx:6; +#endif + __be16 cq_idx; + __be32 rss_hash_val; +}; + +#ifndef CHELSIO_FW +struct work_request_hdr { + __be32 wr_hi; + __be32 wr_lo; +}; + +/* wr_hi fields */ +#define S_WR_SGE_CREDITS 0 +#define M_WR_SGE_CREDITS 0xFF +#define V_WR_SGE_CREDITS(x) ((x) << S_WR_SGE_CREDITS) +#define G_WR_SGE_CREDITS(x) (((x) >> S_WR_SGE_CREDITS) & M_WR_SGE_CREDITS) + +#define S_WR_SGLSFLT 8 +#define M_WR_SGLSFLT 0xFF +#define V_WR_SGLSFLT(x) ((x) << S_WR_SGLSFLT) +#define G_WR_SGLSFLT(x) (((x) >> S_WR_SGLSFLT) & M_WR_SGLSFLT) + +#define S_WR_BCNTLFLT 16 +#define M_WR_BCNTLFLT 0xF +#define V_WR_BCNTLFLT(x) ((x) << S_WR_BCNTLFLT) +#define G_WR_BCNTLFLT(x) (((x) >> S_WR_BCNTLFLT) & M_WR_BCNTLFLT) + +#define S_WR_DATATYPE 20 +#define V_WR_DATATYPE(x) ((x) << S_WR_DATATYPE) +#define F_WR_DATATYPE V_WR_DATATYPE(1U) + +#define S_WR_COMPL 21 +#define V_WR_COMPL(x) ((x) << S_WR_COMPL) +#define F_WR_COMPL V_WR_COMPL(1U) + +#define S_WR_EOP 22 +#define V_WR_EOP(x) ((x) << S_WR_EOP) +#define F_WR_EOP V_WR_EOP(1U) + +#define S_WR_SOP 23 +#define V_WR_SOP(x) ((x) << S_WR_SOP) +#define F_WR_SOP V_WR_SOP(1U) + +#define S_WR_OP 24 +#define M_WR_OP 0xFF +#define V_WR_OP(x) ((x) << S_WR_OP) +#define G_WR_OP(x) (((x) >> S_WR_OP) & M_WR_OP) + +/* wr_lo fields */ +#define S_WR_LEN 0 +#define M_WR_LEN 0xFF +#define V_WR_LEN(x) ((x) << S_WR_LEN) +#define G_WR_LEN(x) (((x) >> S_WR_LEN) & M_WR_LEN) + +#define S_WR_TID 8 +#define M_WR_TID 0xFFFFF +#define V_WR_TID(x) ((x) << S_WR_TID) +#define G_WR_TID(x) (((x) >> S_WR_TID) & M_WR_TID) + +#define S_WR_CR_FLUSH 30 +#define V_WR_CR_FLUSH(x) ((x) << S_WR_CR_FLUSH) +#define F_WR_CR_FLUSH V_WR_CR_FLUSH(1U) + +#define S_WR_GEN 31 +#define V_WR_GEN(x) ((x) << S_WR_GEN) +#define F_WR_GEN V_WR_GEN(1U) + +# define WR_HDR struct work_request_hdr wr +# define RSS_HDR +#else +# define WR_HDR +# define RSS_HDR struct rss_header rss_hdr; +#endif + +/* option 0 lower-half fields */ +#define S_CPL_STATUS 0 +#define M_CPL_STATUS 0xFF +#define V_CPL_STATUS(x) ((x) << S_CPL_STATUS) +#define G_CPL_STATUS(x) (((x) >> S_CPL_STATUS) & M_CPL_STATUS) + +#define S_INJECT_TIMER 6 +#define V_INJECT_TIMER(x) ((x) << S_INJECT_TIMER) +#define F_INJECT_TIMER V_INJECT_TIMER(1U) + +#define S_NO_OFFLOAD 7 +#define V_NO_OFFLOAD(x) ((x) << S_NO_OFFLOAD) +#define F_NO_OFFLOAD V_NO_OFFLOAD(1U) + +#define S_ULP_MODE 8 +#define M_ULP_MODE 0xF +#define V_ULP_MODE(x) ((x) << S_ULP_MODE) +#define G_ULP_MODE(x) (((x) >> S_ULP_MODE) & M_ULP_MODE) + +#define S_RCV_BUFSIZ 12 +#define M_RCV_BUFSIZ 0x3FFF +#define V_RCV_BUFSIZ(x) ((x) << S_RCV_BUFSIZ) +#define G_RCV_BUFSIZ(x) (((x) >> S_RCV_BUFSIZ) & M_RCV_BUFSIZ) + +#define S_TOS 26 +#define M_TOS 0x3F +#define V_TOS(x) ((x) << S_TOS) +#define G_TOS(x) (((x) >> S_TOS) & M_TOS) + +/* option 0 upper-half fields */ +#define S_DELACK 0 +#define V_DELACK(x) ((x) << S_DELACK) +#define F_DELACK V_DELACK(1U) + +#define S_NO_CONG 1 +#define V_NO_CONG(x) ((x) << S_NO_CONG) +#define F_NO_CONG V_NO_CONG(1U) + +#define S_SRC_MAC_SEL 2 +#define M_SRC_MAC_SEL 0x3 +#define V_SRC_MAC_SEL(x) ((x) << S_SRC_MAC_SEL) +#define G_SRC_MAC_SEL(x) (((x) >> S_SRC_MAC_SEL) & M_SRC_MAC_SEL) + +#define S_L2T_IDX 4 +#define M_L2T_IDX 0x7FF +#define V_L2T_IDX(x) ((x) << S_L2T_IDX) +#define G_L2T_IDX(x) (((x) >> S_L2T_IDX) & M_L2T_IDX) + +#define S_TX_CHANNEL 15 +#define V_TX_CHANNEL(x) ((x) << S_TX_CHANNEL) +#define F_TX_CHANNEL V_TX_CHANNEL(1U) + +#define S_TCAM_BYPASS 16 +#define V_TCAM_BYPASS(x) ((x) << S_TCAM_BYPASS) +#define F_TCAM_BYPASS V_TCAM_BYPASS(1U) + +#define S_NAGLE 17 +#define V_NAGLE(x) ((x) << S_NAGLE) +#define F_NAGLE V_NAGLE(1U) + +#define S_WND_SCALE 18 +#define M_WND_SCALE 0xF +#define V_WND_SCALE(x) ((x) << S_WND_SCALE) +#define G_WND_SCALE(x) (((x) >> S_WND_SCALE) & M_WND_SCALE) + +#define S_KEEP_ALIVE 22 +#define V_KEEP_ALIVE(x) ((x) << S_KEEP_ALIVE) +#define F_KEEP_ALIVE V_KEEP_ALIVE(1U) + +#define S_MAX_RETRANS 23 +#define M_MAX_RETRANS 0xF +#define V_MAX_RETRANS(x) ((x) << S_MAX_RETRANS) +#define G_MAX_RETRANS(x) (((x) >> S_MAX_RETRANS) & M_MAX_RETRANS) + +#define S_MAX_RETRANS_OVERRIDE 27 +#define V_MAX_RETRANS_OVERRIDE(x) ((x) << S_MAX_RETRANS_OVERRIDE) +#define F_MAX_RETRANS_OVERRIDE V_MAX_RETRANS_OVERRIDE(1U) + +#define S_MSS_IDX 28 +#define M_MSS_IDX 0xF +#define V_MSS_IDX(x) ((x) << S_MSS_IDX) +#define G_MSS_IDX(x) (((x) >> S_MSS_IDX) & M_MSS_IDX) + +/* option 1 fields */ +#define S_RSS_ENABLE 0 +#define V_RSS_ENABLE(x) ((x) << S_RSS_ENABLE) +#define F_RSS_ENABLE V_RSS_ENABLE(1U) + +#define S_RSS_MASK_LEN 1 +#define M_RSS_MASK_LEN 0x7 +#define V_RSS_MASK_LEN(x) ((x) << S_RSS_MASK_LEN) +#define G_RSS_MASK_LEN(x) (((x) >> S_RSS_MASK_LEN) & M_RSS_MASK_LEN) + +#define S_CPU_IDX 4 +#define M_CPU_IDX 0x3F +#define V_CPU_IDX(x) ((x) << S_CPU_IDX) +#define G_CPU_IDX(x) (((x) >> S_CPU_IDX) & M_CPU_IDX) + +#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) + +#define S_CONN_POLICY 19 +#define M_CONN_POLICY 0x3 +#define V_CONN_POLICY(x) ((x) << S_CONN_POLICY) +#define G_CONN_POLICY(x) (((x) >> S_CONN_POLICY) & M_CONN_POLICY) + +#define S_SYN_DEFENSE 21 +#define V_SYN_DEFENSE(x) ((x) << S_SYN_DEFENSE) +#define F_SYN_DEFENSE V_SYN_DEFENSE(1U) + +#define S_VLAN_PRI 22 +#define M_VLAN_PRI 0x3 +#define V_VLAN_PRI(x) ((x) << S_VLAN_PRI) +#define G_VLAN_PRI(x) (((x) >> S_VLAN_PRI) & M_VLAN_PRI) + +#define S_VLAN_PRI_VALID 24 +#define V_VLAN_PRI_VALID(x) ((x) << S_VLAN_PRI_VALID) +#define F_VLAN_PRI_VALID V_VLAN_PRI_VALID(1U) + +#define S_PKT_TYPE 25 +#define M_PKT_TYPE 0x3 +#define V_PKT_TYPE(x) ((x) << S_PKT_TYPE) +#define G_PKT_TYPE(x) (((x) >> S_PKT_TYPE) & M_PKT_TYPE) + +#define S_MAC_MATCH 27 +#define M_MAC_MATCH 0x1F +#define V_MAC_MATCH(x) ((x) << S_MAC_MATCH) +#define G_MAC_MATCH(x) (((x) >> S_MAC_MATCH) & M_MAC_MATCH) + +/* option 2 fields */ +#define S_CPU_INDEX 0 +#define M_CPU_INDEX 0x7F +#define V_CPU_INDEX(x) ((x) << S_CPU_INDEX) +#define G_CPU_INDEX(x) (((x) >> S_CPU_INDEX) & M_CPU_INDEX) + +#define S_CPU_INDEX_VALID 7 +#define V_CPU_INDEX_VALID(x) ((x) << S_CPU_INDEX_VALID) +#define F_CPU_INDEX_VALID V_CPU_INDEX_VALID(1U) + +#define S_RX_COALESCE 8 +#define M_RX_COALESCE 0x3 +#define V_RX_COALESCE(x) ((x) << S_RX_COALESCE) +#define G_RX_COALESCE(x) (((x) >> S_RX_COALESCE) & M_RX_COALESCE) + +#define S_RX_COALESCE_VALID 10 +#define V_RX_COALESCE_VALID(x) ((x) << S_RX_COALESCE_VALID) +#define F_RX_COALESCE_VALID V_RX_COALESCE_VALID(1U) + +#define S_CONG_CONTROL_FLAVOR 11 +#define M_CONG_CONTROL_FLAVOR 0x3 +#define V_CONG_CONTROL_FLAVOR(x) ((x) << S_CONG_CONTROL_FLAVOR) +#define G_CONG_CONTROL_FLAVOR(x) (((x) >> S_CONG_CONTROL_FLAVOR) & M_CONG_CONTROL_FLAVOR) + +#define S_PACING_FLAVOR 13 +#define M_PACING_FLAVOR 0x3 +#define V_PACING_FLAVOR(x) ((x) << S_PACING_FLAVOR) +#define G_PACING_FLAVOR(x) (((x) >> S_PACING_FLAVOR) & M_PACING_FLAVOR) + +#define S_FLAVORS_VALID 15 +#define V_FLAVORS_VALID(x) ((x) << S_FLAVORS_VALID) +#define F_FLAVORS_VALID V_FLAVORS_VALID(1U) + +#define S_RX_FC_DISABLE 16 +#define V_RX_FC_DISABLE(x) ((x) << S_RX_FC_DISABLE) +#define F_RX_FC_DISABLE V_RX_FC_DISABLE(1U) + +#define S_RX_FC_VALID 17 +#define V_RX_FC_VALID(x) ((x) << S_RX_FC_VALID) +#define F_RX_FC_VALID V_RX_FC_VALID(1U) + +struct cpl_pass_open_req { + WR_HDR; + union opcode_tid ot; + __be16 local_port; + __be16 peer_port; + __be32 local_ip; + __be32 peer_ip; + __be32 opt0h; + __be32 opt0l; + __be32 peer_netmask; + __be32 opt1; +}; + +struct cpl_pass_open_rpl { + RSS_HDR union opcode_tid ot; + __be16 local_port; + __be16 peer_port; + __be32 local_ip; + __be32 peer_ip; + __u8 resvd[7]; + __u8 status; +}; + +struct cpl_pass_establish { + RSS_HDR union opcode_tid ot; + __be16 local_port; + __be16 peer_port; + __be32 local_ip; + __be32 peer_ip; + __be32 tos_tid; + __be16 l2t_idx; + __be16 tcp_opt; + __be32 snd_isn; + __be32 rcv_isn; +}; + +/* cpl_pass_establish.tos_tid fields */ +#define S_PASS_OPEN_TID 0 +#define M_PASS_OPEN_TID 0xFFFFFF +#define V_PASS_OPEN_TID(x) ((x) << S_PASS_OPEN_TID) +#define G_PASS_OPEN_TID(x) (((x) >> S_PASS_OPEN_TID) & M_PASS_OPEN_TID) + +#define S_PASS_OPEN_TOS 24 +#define M_PASS_OPEN_TOS 0xFF +#define V_PASS_OPEN_TOS(x) ((x) << S_PASS_OPEN_TOS) +#define G_PASS_OPEN_TOS(x) (((x) >> S_PASS_OPEN_TOS) & M_PASS_OPEN_TOS) + +/* cpl_pass_establish.l2t_idx fields */ +#define S_L2T_IDX16 5 +#define M_L2T_IDX16 0x7FF +#define V_L2T_IDX16(x) ((x) << S_L2T_IDX16) +#define G_L2T_IDX16(x) (((x) >> S_L2T_IDX16) & M_L2T_IDX16) + +/* cpl_pass_establish.tcp_opt fields (also applies act_open_establish) */ +#define G_TCPOPT_WSCALE_OK(x) (((x) >> 5) & 1) +#define G_TCPOPT_SACK(x) (((x) >> 6) & 1) +#define G_TCPOPT_TSTAMP(x) (((x) >> 7) & 1) +#define G_TCPOPT_SND_WSCALE(x) (((x) >> 8) & 0xf) +#define G_TCPOPT_MSS(x) (((x) >> 12) & 0xf) + +struct cpl_pass_accept_req { + RSS_HDR union opcode_tid ot; + __be16 local_port; + __be16 peer_port; + __be32 local_ip; + __be32 peer_ip; + __be32 tos_tid; + struct tcp_options tcp_options; + __u8 dst_mac[6]; + __be16 vlan_tag; + __u8 src_mac[6]; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8:3; + __u8 addr_idx:3; + __u8 port_idx:1; + __u8 exact_match:1; +#else + __u8 exact_match:1; + __u8 port_idx:1; + __u8 addr_idx:3; + __u8:3; +#endif + __u8 rsvd; + __be32 rcv_isn; + __be32 rsvd2; +}; + +struct cpl_pass_accept_rpl { + WR_HDR; + union opcode_tid ot; + __be32 opt2; + __be32 rsvd; + __be32 peer_ip; + __be32 opt0h; + __be32 opt0l_status; +}; + +struct cpl_act_open_req { + WR_HDR; + union opcode_tid ot; + __be16 local_port; + __be16 peer_port; + __be32 local_ip; + __be32 peer_ip; + __be32 opt0h; + __be32 opt0l; + __be32 params; + __be32 opt2; +}; + +/* cpl_act_open_req.params fields */ +#define S_AOPEN_VLAN_PRI 9 +#define M_AOPEN_VLAN_PRI 0x3 +#define V_AOPEN_VLAN_PRI(x) ((x) << S_AOPEN_VLAN_PRI) +#define G_AOPEN_VLAN_PRI(x) (((x) >> S_AOPEN_VLAN_PRI) & M_AOPEN_VLAN_PRI) + +#define S_AOPEN_VLAN_PRI_VALID 11 +#define V_AOPEN_VLAN_PRI_VALID(x) ((x) << S_AOPEN_VLAN_PRI_VALID) +#define F_AOPEN_VLAN_PRI_VALID V_AOPEN_VLAN_PRI_VALID(1U) + +#define S_AOPEN_PKT_TYPE 12 +#define M_AOPEN_PKT_TYPE 0x3 +#define V_AOPEN_PKT_TYPE(x) ((x) << S_AOPEN_PKT_TYPE) +#define G_AOPEN_PKT_TYPE(x) (((x) >> S_AOPEN_PKT_TYPE) & M_AOPEN_PKT_TYPE) + +#define S_AOPEN_MAC_MATCH 14 +#define M_AOPEN_MAC_MATCH 0x1F +#define V_AOPEN_MAC_MATCH(x) ((x) << S_AOPEN_MAC_MATCH) +#define G_AOPEN_MAC_MATCH(x) (((x) >> S_AOPEN_MAC_MATCH) & M_AOPEN_MAC_MATCH) + +#define S_AOPEN_MAC_MATCH_VALID 19 +#define V_AOPEN_MAC_MATCH_VALID(x) ((x) << S_AOPEN_MAC_MATCH_VALID) +#define F_AOPEN_MAC_MATCH_VALID V_AOPEN_MAC_MATCH_VALID(1U) + +#define S_AOPEN_IFF_VLAN 20 +#define M_AOPEN_IFF_VLAN 0xFFF +#define V_AOPEN_IFF_VLAN(x) ((x) << S_AOPEN_IFF_VLAN) +#define G_AOPEN_IFF_VLAN(x) (((x) >> S_AOPEN_IFF_VLAN) & M_AOPEN_IFF_VLAN) + +struct cpl_act_open_rpl { + RSS_HDR union opcode_tid ot; + __be16 local_port; + __be16 peer_port; + __be32 local_ip; + __be32 peer_ip; + __be32 atid; + __u8 rsvd[3]; + __u8 status; +}; + +struct cpl_act_establish { + RSS_HDR union opcode_tid ot; + __be16 local_port; + __be16 peer_port; + __be32 local_ip; + __be32 peer_ip; + __be32 tos_tid; + __be16 l2t_idx; + __be16 tcp_opt; + __be32 snd_isn; + __be32 rcv_isn; +}; + +struct cpl_get_tcb { + WR_HDR; + union opcode_tid ot; + __be16 cpuno; + __be16 rsvd; +}; + +struct cpl_get_tcb_rpl { + RSS_HDR union opcode_tid ot; + __u8 rsvd; + __u8 status; + __be16 len; +}; + +struct cpl_set_tcb { + WR_HDR; + union opcode_tid ot; + __u8 reply; + __u8 cpu_idx; + __be16 len; +}; + +/* cpl_set_tcb.reply fields */ +#define S_NO_REPLY 7 +#define V_NO_REPLY(x) ((x) << S_NO_REPLY) +#define F_NO_REPLY V_NO_REPLY(1U) + +struct cpl_set_tcb_field { + WR_HDR; + union opcode_tid ot; + __u8 reply; + __u8 cpu_idx; + __be16 word; + __be64 mask; + __be64 val; +}; + +struct cpl_set_tcb_rpl { + RSS_HDR union opcode_tid ot; + __u8 rsvd[3]; + __u8 status; +}; + +struct cpl_pcmd { + WR_HDR; + union opcode_tid ot; + __u8 rsvd[3]; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 src:1; + __u8 bundle:1; + __u8 channel:1; + __u8:5; +#else + __u8:5; + __u8 channel:1; + __u8 bundle:1; + __u8 src:1; +#endif + __be32 pcmd_parm[2]; +}; + +struct cpl_pcmd_reply { + RSS_HDR union opcode_tid ot; + __u8 status; + __u8 rsvd; + __be16 len; +}; + +struct cpl_close_con_req { + WR_HDR; + union opcode_tid ot; + __be32 rsvd; +}; + +struct cpl_close_con_rpl { + RSS_HDR union opcode_tid ot; + __u8 rsvd[3]; + __u8 status; + __be32 snd_nxt; + __be32 rcv_nxt; +}; + +struct cpl_close_listserv_req { + WR_HDR; + union opcode_tid ot; + __u8 rsvd0; + __u8 cpu_idx; + __be16 rsvd1; +}; + +struct cpl_close_listserv_rpl { + RSS_HDR union opcode_tid ot; + __u8 rsvd[3]; + __u8 status; +}; + +struct cpl_abort_req_rss { + RSS_HDR union opcode_tid ot; + __be32 rsvd0; + __u8 rsvd1; + __u8 status; + __u8 rsvd2[6]; +}; + +struct cpl_abort_req { + WR_HDR; + union opcode_tid ot; + __be32 rsvd0; + __u8 rsvd1; + __u8 cmd; + __u8 rsvd2[6]; +}; + +struct cpl_abort_rpl_rss { + RSS_HDR union opcode_tid ot; + __be32 rsvd0; + __u8 rsvd1; + __u8 status; + __u8 rsvd2[6]; +}; + +struct cpl_abort_rpl { + WR_HDR; + union opcode_tid ot; + __be32 rsvd0; + __u8 rsvd1; + __u8 cmd; + __u8 rsvd2[6]; +}; + +struct cpl_peer_close { + RSS_HDR union opcode_tid ot; + __be32 rcv_nxt; +}; + +struct tx_data_wr { + __be32 wr_hi; + __be32 wr_lo; + __be32 len; + __be32 flags; + __be32 sndseq; + __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 +#define V_TX_PORT(x) ((x) << S_TX_PORT) +#define G_TX_PORT(x) (((x) >> S_TX_PORT) & M_TX_PORT) + +#define S_TX_MSS 4 +#define M_TX_MSS 0xF +#define V_TX_MSS(x) ((x) << S_TX_MSS) +#define G_TX_MSS(x) (((x) >> S_TX_MSS) & M_TX_MSS) + +#define S_TX_QOS 8 +#define M_TX_QOS 0xFF +#define V_TX_QOS(x) ((x) << S_TX_QOS) +#define G_TX_QOS(x) (((x) >> S_TX_QOS) & M_TX_QOS) + +#define S_TX_SNDBUF 16 +#define M_TX_SNDBUF 0xFFFF +#define V_TX_SNDBUF(x) ((x) << S_TX_SNDBUF) +#define G_TX_SNDBUF(x) (((x) >> S_TX_SNDBUF) & M_TX_SNDBUF) + +struct cpl_tx_data { + union opcode_tid ot; + __be32 len; + __be32 rsvd; + __be16 urg; + __be16 flags; +}; + +/* cpl_tx_data.flags fields */ +#define S_TX_ULP_SUBMODE 6 +#define M_TX_ULP_SUBMODE 0xF +#define V_TX_ULP_SUBMODE(x) ((x) << S_TX_ULP_SUBMODE) +#define G_TX_ULP_SUBMODE(x) (((x) >> S_TX_ULP_SUBMODE) & M_TX_ULP_SUBMODE) + +#define S_TX_ULP_MODE 10 +#define M_TX_ULP_MODE 0xF +#define V_TX_ULP_MODE(x) ((x) << S_TX_ULP_MODE) +#define G_TX_ULP_MODE(x) (((x) >> S_TX_ULP_MODE) & M_TX_ULP_MODE) + +#define S_TX_SHOVE 14 +#define V_TX_SHOVE(x) ((x) << S_TX_SHOVE) +#define F_TX_SHOVE V_TX_SHOVE(1U) + +#define S_TX_MORE 15 +#define V_TX_MORE(x) ((x) << S_TX_MORE) +#define F_TX_MORE V_TX_MORE(1U) + +/* additional tx_data_wr.flags fields */ +#define S_TX_CPU_IDX 0 +#define M_TX_CPU_IDX 0x3F +#define V_TX_CPU_IDX(x) ((x) << S_TX_CPU_IDX) +#define G_TX_CPU_IDX(x) (((x) >> S_TX_CPU_IDX) & M_TX_CPU_IDX) + +#define S_TX_URG 16 +#define V_TX_URG(x) ((x) << S_TX_URG) +#define F_TX_URG V_TX_URG(1U) + +#define S_TX_CLOSE 17 +#define V_TX_CLOSE(x) ((x) << S_TX_CLOSE) +#define F_TX_CLOSE V_TX_CLOSE(1U) + +#define S_TX_INIT 18 +#define V_TX_INIT(x) ((x) << S_TX_INIT) +#define F_TX_INIT V_TX_INIT(1U) + +#define S_TX_IMM_ACK 19 +#define V_TX_IMM_ACK(x) ((x) << S_TX_IMM_ACK) +#define F_TX_IMM_ACK V_TX_IMM_ACK(1U) + +#define S_TX_IMM_DMA 20 +#define V_TX_IMM_DMA(x) ((x) << S_TX_IMM_DMA) +#define F_TX_IMM_DMA V_TX_IMM_DMA(1U) + +struct cpl_tx_data_ack { + RSS_HDR union opcode_tid ot; + __be32 ack_seq; +}; + +struct cpl_wr_ack { + RSS_HDR union opcode_tid ot; + __be16 credits; + __be16 rsvd; + __be32 snd_nxt; + __be32 snd_una; +}; + +struct cpl_rdma_ec_status { + RSS_HDR union opcode_tid ot; + __u8 rsvd[3]; + __u8 status; +}; + +struct mngt_pktsched_wr { + __be32 wr_hi; + __be32 wr_lo; + __u8 mngt_opcode; + __u8 rsvd[7]; + __u8 sched; + __u8 idx; + __u8 min; + __u8 max; + __u8 binding; + __u8 rsvd1[3]; +}; + +struct cpl_iscsi_hdr { + RSS_HDR union opcode_tid ot; + __be16 pdu_len_ddp; + __be16 len; + __be32 seq; + __be16 urg; + __u8 rsvd; + __u8 status; +}; + +/* cpl_iscsi_hdr.pdu_len_ddp fields */ +#define S_ISCSI_PDU_LEN 0 +#define M_ISCSI_PDU_LEN 0x7FFF +#define V_ISCSI_PDU_LEN(x) ((x) << S_ISCSI_PDU_LEN) +#define G_ISCSI_PDU_LEN(x) (((x) >> S_ISCSI_PDU_LEN) & M_ISCSI_PDU_LEN) + +#define S_ISCSI_DDP 15 +#define V_ISCSI_DDP(x) ((x) << S_ISCSI_DDP) +#define F_ISCSI_DDP V_ISCSI_DDP(1U) + +struct cpl_rx_data { + RSS_HDR union opcode_tid ot; + __be16 rsvd; + __be16 len; + __be32 seq; + __be16 urg; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 dack_mode:2; + __u8 psh:1; + __u8 heartbeat:1; + __u8:4; +#else + __u8:4; + __u8 heartbeat:1; + __u8 psh:1; + __u8 dack_mode:2; +#endif + __u8 status; +}; + +struct cpl_rx_data_ack { + WR_HDR; + union opcode_tid ot; + __be32 credit_dack; +}; + +/* cpl_rx_data_ack.ack_seq fields */ +#define S_RX_CREDITS 0 +#define M_RX_CREDITS 0x7FFFFFF +#define V_RX_CREDITS(x) ((x) << S_RX_CREDITS) +#define G_RX_CREDITS(x) (((x) >> S_RX_CREDITS) & M_RX_CREDITS) + +#define S_RX_MODULATE 27 +#define V_RX_MODULATE(x) ((x) << S_RX_MODULATE) +#define F_RX_MODULATE V_RX_MODULATE(1U) + +#define S_RX_FORCE_ACK 28 +#define V_RX_FORCE_ACK(x) ((x) << S_RX_FORCE_ACK) +#define F_RX_FORCE_ACK V_RX_FORCE_ACK(1U) + +#define S_RX_DACK_MODE 29 +#define M_RX_DACK_MODE 0x3 +#define V_RX_DACK_MODE(x) ((x) << S_RX_DACK_MODE) +#define G_RX_DACK_MODE(x) (((x) >> S_RX_DACK_MODE) & M_RX_DACK_MODE) + +#define S_RX_DACK_CHANGE 31 +#define V_RX_DACK_CHANGE(x) ((x) << S_RX_DACK_CHANGE) +#define F_RX_DACK_CHANGE V_RX_DACK_CHANGE(1U) + +struct cpl_rx_urg_notify { + RSS_HDR union opcode_tid ot; + __be32 seq; +}; + +struct cpl_rx_ddp_complete { + RSS_HDR union opcode_tid ot; + __be32 ddp_report; +}; + +struct cpl_rx_data_ddp { + RSS_HDR union opcode_tid ot; + __be16 urg; + __be16 len; + __be32 seq; + union { + __be32 nxt_seq; + __be32 ddp_report; + }; + __be32 ulp_crc; + __be32 ddpvld_status; +}; + +/* cpl_rx_data_ddp.ddpvld_status fields */ +#define S_DDP_STATUS 0 +#define M_DDP_STATUS 0xFF +#define V_DDP_STATUS(x) ((x) << S_DDP_STATUS) +#define G_DDP_STATUS(x) (((x) >> S_DDP_STATUS) & M_DDP_STATUS) + +#define S_DDP_VALID 15 +#define M_DDP_VALID 0x1FFFF +#define V_DDP_VALID(x) ((x) << S_DDP_VALID) +#define G_DDP_VALID(x) (((x) >> S_DDP_VALID) & M_DDP_VALID) + +#define S_DDP_PPOD_MISMATCH 15 +#define V_DDP_PPOD_MISMATCH(x) ((x) << S_DDP_PPOD_MISMATCH) +#define F_DDP_PPOD_MISMATCH V_DDP_PPOD_MISMATCH(1U) + +#define S_DDP_PDU 16 +#define V_DDP_PDU(x) ((x) << S_DDP_PDU) +#define F_DDP_PDU V_DDP_PDU(1U) + +#define S_DDP_LLIMIT_ERR 17 +#define V_DDP_LLIMIT_ERR(x) ((x) << S_DDP_LLIMIT_ERR) +#define F_DDP_LLIMIT_ERR V_DDP_LLIMIT_ERR(1U) + +#define S_DDP_PPOD_PARITY_ERR 18 +#define V_DDP_PPOD_PARITY_ERR(x) ((x) << S_DDP_PPOD_PARITY_ERR) +#define F_DDP_PPOD_PARITY_ERR V_DDP_PPOD_PARITY_ERR(1U) + +#define S_DDP_PADDING_ERR 19 +#define V_DDP_PADDING_ERR(x) ((x) << S_DDP_PADDING_ERR) +#define F_DDP_PADDING_ERR V_DDP_PADDING_ERR(1U) + +#define S_DDP_HDRCRC_ERR 20 +#define V_DDP_HDRCRC_ERR(x) ((x) << S_DDP_HDRCRC_ERR) +#define F_DDP_HDRCRC_ERR V_DDP_HDRCRC_ERR(1U) + +#define S_DDP_DATACRC_ERR 21 +#define V_DDP_DATACRC_ERR(x) ((x) << S_DDP_DATACRC_ERR) +#define F_DDP_DATACRC_ERR V_DDP_DATACRC_ERR(1U) + +#define S_DDP_INVALID_TAG 22 +#define V_DDP_INVALID_TAG(x) ((x) << S_DDP_INVALID_TAG) +#define F_DDP_INVALID_TAG V_DDP_INVALID_TAG(1U) + +#define S_DDP_ULIMIT_ERR 23 +#define V_DDP_ULIMIT_ERR(x) ((x) << S_DDP_ULIMIT_ERR) +#define F_DDP_ULIMIT_ERR V_DDP_ULIMIT_ERR(1U) + +#define S_DDP_OFFSET_ERR 24 +#define V_DDP_OFFSET_ERR(x) ((x) << S_DDP_OFFSET_ERR) +#define F_DDP_OFFSET_ERR V_DDP_OFFSET_ERR(1U) + +#define S_DDP_COLOR_ERR 25 +#define V_DDP_COLOR_ERR(x) ((x) << S_DDP_COLOR_ERR) +#define F_DDP_COLOR_ERR V_DDP_COLOR_ERR(1U) + +#define S_DDP_TID_MISMATCH 26 +#define V_DDP_TID_MISMATCH(x) ((x) << S_DDP_TID_MISMATCH) +#define F_DDP_TID_MISMATCH V_DDP_TID_MISMATCH(1U) + +#define S_DDP_INVALID_PPOD 27 +#define V_DDP_INVALID_PPOD(x) ((x) << S_DDP_INVALID_PPOD) +#define F_DDP_INVALID_PPOD V_DDP_INVALID_PPOD(1U) + +#define S_DDP_ULP_MODE 28 +#define M_DDP_ULP_MODE 0xF +#define V_DDP_ULP_MODE(x) ((x) << S_DDP_ULP_MODE) +#define G_DDP_ULP_MODE(x) (((x) >> S_DDP_ULP_MODE) & M_DDP_ULP_MODE) + +/* cpl_rx_data_ddp.ddp_report fields */ +#define S_DDP_OFFSET 0 +#define M_DDP_OFFSET 0x3FFFFF +#define V_DDP_OFFSET(x) ((x) << S_DDP_OFFSET) +#define G_DDP_OFFSET(x) (((x) >> S_DDP_OFFSET) & M_DDP_OFFSET) + +#define S_DDP_URG 24 +#define V_DDP_URG(x) ((x) << S_DDP_URG) +#define F_DDP_URG V_DDP_URG(1U) + +#define S_DDP_PSH 25 +#define V_DDP_PSH(x) ((x) << S_DDP_PSH) +#define F_DDP_PSH V_DDP_PSH(1U) + +#define S_DDP_BUF_COMPLETE 26 +#define V_DDP_BUF_COMPLETE(x) ((x) << S_DDP_BUF_COMPLETE) +#define F_DDP_BUF_COMPLETE V_DDP_BUF_COMPLETE(1U) + +#define S_DDP_BUF_TIMED_OUT 27 +#define V_DDP_BUF_TIMED_OUT(x) ((x) << S_DDP_BUF_TIMED_OUT) +#define F_DDP_BUF_TIMED_OUT V_DDP_BUF_TIMED_OUT(1U) + +#define S_DDP_BUF_IDX 28 +#define V_DDP_BUF_IDX(x) ((x) << S_DDP_BUF_IDX) +#define F_DDP_BUF_IDX V_DDP_BUF_IDX(1U) + +struct cpl_tx_pkt { + WR_HDR; + __be32 cntrl; + __be32 len; +}; + +struct cpl_tx_pkt_lso { + WR_HDR; + __be32 cntrl; + __be32 len; + + __be32 rsvd; + __be32 lso_info; +}; + +/* cpl_tx_pkt*.cntrl fields */ +#define S_TXPKT_VLAN 0 +#define M_TXPKT_VLAN 0xFFFF +#define V_TXPKT_VLAN(x) ((x) << S_TXPKT_VLAN) +#define G_TXPKT_VLAN(x) (((x) >> S_TXPKT_VLAN) & M_TXPKT_VLAN) + +#define S_TXPKT_INTF 16 +#define M_TXPKT_INTF 0xF +#define V_TXPKT_INTF(x) ((x) << S_TXPKT_INTF) +#define G_TXPKT_INTF(x) (((x) >> S_TXPKT_INTF) & M_TXPKT_INTF) + +#define S_TXPKT_IPCSUM_DIS 20 +#define V_TXPKT_IPCSUM_DIS(x) ((x) << S_TXPKT_IPCSUM_DIS) +#define F_TXPKT_IPCSUM_DIS V_TXPKT_IPCSUM_DIS(1U) + +#define S_TXPKT_L4CSUM_DIS 21 +#define V_TXPKT_L4CSUM_DIS(x) ((x) << S_TXPKT_L4CSUM_DIS) +#define F_TXPKT_L4CSUM_DIS V_TXPKT_L4CSUM_DIS(1U) + +#define S_TXPKT_VLAN_VLD 22 +#define V_TXPKT_VLAN_VLD(x) ((x) << S_TXPKT_VLAN_VLD) +#define F_TXPKT_VLAN_VLD V_TXPKT_VLAN_VLD(1U) + +#define S_TXPKT_LOOPBACK 23 +#define V_TXPKT_LOOPBACK(x) ((x) << S_TXPKT_LOOPBACK) +#define F_TXPKT_LOOPBACK V_TXPKT_LOOPBACK(1U) + +#define S_TXPKT_OPCODE 24 +#define M_TXPKT_OPCODE 0xFF +#define V_TXPKT_OPCODE(x) ((x) << S_TXPKT_OPCODE) +#define G_TXPKT_OPCODE(x) (((x) >> S_TXPKT_OPCODE) & M_TXPKT_OPCODE) + +/* cpl_tx_pkt_lso.lso_info fields */ +#define S_LSO_MSS 0 +#define M_LSO_MSS 0x3FFF +#define V_LSO_MSS(x) ((x) << S_LSO_MSS) +#define G_LSO_MSS(x) (((x) >> S_LSO_MSS) & M_LSO_MSS) + +#define S_LSO_ETH_TYPE 14 +#define M_LSO_ETH_TYPE 0x3 +#define V_LSO_ETH_TYPE(x) ((x) << S_LSO_ETH_TYPE) +#define G_LSO_ETH_TYPE(x) (((x) >> S_LSO_ETH_TYPE) & M_LSO_ETH_TYPE) + +#define S_LSO_TCPHDR_WORDS 16 +#define M_LSO_TCPHDR_WORDS 0xF +#define V_LSO_TCPHDR_WORDS(x) ((x) << S_LSO_TCPHDR_WORDS) +#define G_LSO_TCPHDR_WORDS(x) (((x) >> S_LSO_TCPHDR_WORDS) & M_LSO_TCPHDR_WORDS) + +#define S_LSO_IPHDR_WORDS 20 +#define M_LSO_IPHDR_WORDS 0xF +#define V_LSO_IPHDR_WORDS(x) ((x) << S_LSO_IPHDR_WORDS) +#define G_LSO_IPHDR_WORDS(x) (((x) >> S_LSO_IPHDR_WORDS) & M_LSO_IPHDR_WORDS) + +#define S_LSO_IPV6 24 +#define V_LSO_IPV6(x) ((x) << S_LSO_IPV6) +#define F_LSO_IPV6 V_LSO_IPV6(1U) + +struct cpl_trace_pkt { +#ifdef CHELSIO_FW + __u8 rss_opcode; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 err:1; + __u8:7; +#else + __u8:7; + __u8 err:1; +#endif + __u8 rsvd0; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 qid:4; + __u8:4; +#else + __u8:4; + __u8 qid:4; +#endif + __be32 tstamp; +#endif /* CHELSIO_FW */ + + __u8 opcode; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 iff:4; + __u8:4; +#else + __u8:4; + __u8 iff:4; +#endif + __u8 rsvd[4]; + __be16 len; +}; + +struct cpl_rx_pkt { + RSS_HDR __u8 opcode; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 iff:4; + __u8 csum_valid:1; + __u8 ipmi_pkt:1; + __u8 vlan_valid:1; + __u8 fragment:1; +#else + __u8 fragment:1; + __u8 vlan_valid:1; + __u8 ipmi_pkt:1; + __u8 csum_valid:1; + __u8 iff:4; +#endif + __be16 csum; + __be16 vlan; + __be16 len; +}; + +struct cpl_l2t_write_req { + WR_HDR; + union opcode_tid ot; + __be32 params; + __u8 rsvd[2]; + __u8 dst_mac[6]; +}; + +/* cpl_l2t_write_req.params fields */ +#define S_L2T_W_IDX 0 +#define M_L2T_W_IDX 0x7FF +#define V_L2T_W_IDX(x) ((x) << S_L2T_W_IDX) +#define G_L2T_W_IDX(x) (((x) >> S_L2T_W_IDX) & M_L2T_W_IDX) + +#define S_L2T_W_VLAN 11 +#define M_L2T_W_VLAN 0xFFF +#define V_L2T_W_VLAN(x) ((x) << S_L2T_W_VLAN) +#define G_L2T_W_VLAN(x) (((x) >> S_L2T_W_VLAN) & M_L2T_W_VLAN) + +#define S_L2T_W_IFF 23 +#define M_L2T_W_IFF 0xF +#define V_L2T_W_IFF(x) ((x) << S_L2T_W_IFF) +#define G_L2T_W_IFF(x) (((x) >> S_L2T_W_IFF) & M_L2T_W_IFF) + +#define S_L2T_W_PRIO 27 +#define M_L2T_W_PRIO 0x7 +#define V_L2T_W_PRIO(x) ((x) << S_L2T_W_PRIO) +#define G_L2T_W_PRIO(x) (((x) >> S_L2T_W_PRIO) & M_L2T_W_PRIO) + +struct cpl_l2t_write_rpl { + RSS_HDR union opcode_tid ot; + __u8 status; + __u8 rsvd[3]; +}; + +struct cpl_l2t_read_req { + WR_HDR; + union opcode_tid ot; + __be16 rsvd; + __be16 l2t_idx; +}; + +struct cpl_l2t_read_rpl { + RSS_HDR union opcode_tid ot; + __be32 params; + __u8 rsvd[2]; + __u8 dst_mac[6]; +}; + +/* cpl_l2t_read_rpl.params fields */ +#define S_L2T_R_PRIO 0 +#define M_L2T_R_PRIO 0x7 +#define V_L2T_R_PRIO(x) ((x) << S_L2T_R_PRIO) +#define G_L2T_R_PRIO(x) (((x) >> S_L2T_R_PRIO) & M_L2T_R_PRIO) + +#define S_L2T_R_VLAN 8 +#define M_L2T_R_VLAN 0xFFF +#define V_L2T_R_VLAN(x) ((x) << S_L2T_R_VLAN) +#define G_L2T_R_VLAN(x) (((x) >> S_L2T_R_VLAN) & M_L2T_R_VLAN) + +#define S_L2T_R_IFF 20 +#define M_L2T_R_IFF 0xF +#define V_L2T_R_IFF(x) ((x) << S_L2T_R_IFF) +#define G_L2T_R_IFF(x) (((x) >> S_L2T_R_IFF) & M_L2T_R_IFF) + +#define S_L2T_STATUS 24 +#define M_L2T_STATUS 0xFF +#define V_L2T_STATUS(x) ((x) << S_L2T_STATUS) +#define G_L2T_STATUS(x) (((x) >> S_L2T_STATUS) & M_L2T_STATUS) + +struct cpl_smt_write_req { + WR_HDR; + union opcode_tid ot; + __u8 rsvd0; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 mtu_idx:4; + __u8 iff:4; +#else + __u8 iff:4; + __u8 mtu_idx:4; +#endif + __be16 rsvd2; + __be16 rsvd3; + __u8 src_mac1[6]; + __be16 rsvd4; + __u8 src_mac0[6]; +}; + +struct cpl_smt_write_rpl { + RSS_HDR union opcode_tid ot; + __u8 status; + __u8 rsvd[3]; +}; + +struct cpl_smt_read_req { + WR_HDR; + union opcode_tid ot; + __u8 rsvd0; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8:4; + __u8 iff:4; +#else + __u8 iff:4; + __u8:4; +#endif + __be16 rsvd2; +}; + +struct cpl_smt_read_rpl { + RSS_HDR union opcode_tid ot; + __u8 status; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 mtu_idx:4; + __u8:4; +#else + __u8:4; + __u8 mtu_idx:4; +#endif + __be16 rsvd2; + __be16 rsvd3; + __u8 src_mac1[6]; + __be16 rsvd4; + __u8 src_mac0[6]; +}; + +struct cpl_rte_delete_req { + WR_HDR; + union opcode_tid ot; + __be32 params; +}; + +/* { cpl_rte_delete_req, cpl_rte_read_req }.params fields */ +#define S_RTE_REQ_LUT_IX 8 +#define M_RTE_REQ_LUT_IX 0x7FF +#define V_RTE_REQ_LUT_IX(x) ((x) << S_RTE_REQ_LUT_IX) +#define G_RTE_REQ_LUT_IX(x) (((x) >> S_RTE_REQ_LUT_IX) & M_RTE_REQ_LUT_IX) + +#define S_RTE_REQ_LUT_BASE 19 +#define M_RTE_REQ_LUT_BASE 0x7FF +#define V_RTE_REQ_LUT_BASE(x) ((x) << S_RTE_REQ_LUT_BASE) +#define G_RTE_REQ_LUT_BASE(x) (((x) >> S_RTE_REQ_LUT_BASE) & M_RTE_REQ_LUT_BASE) + +#define S_RTE_READ_REQ_SELECT 31 +#define V_RTE_READ_REQ_SELECT(x) ((x) << S_RTE_READ_REQ_SELECT) +#define F_RTE_READ_REQ_SELECT V_RTE_READ_REQ_SELECT(1U) + +struct cpl_rte_delete_rpl { + RSS_HDR union opcode_tid ot; + __u8 status; + __u8 rsvd[3]; +}; + +struct cpl_rte_write_req { + WR_HDR; + union opcode_tid ot; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8:6; + __u8 write_tcam:1; + __u8 write_l2t_lut:1; +#else + __u8 write_l2t_lut:1; + __u8 write_tcam:1; + __u8:6; +#endif + __u8 rsvd[3]; + __be32 lut_params; + __be16 rsvd2; + __be16 l2t_idx; + __be32 netmask; + __be32 faddr; +}; + +/* cpl_rte_write_req.lut_params fields */ +#define S_RTE_WRITE_REQ_LUT_IX 10 +#define M_RTE_WRITE_REQ_LUT_IX 0x7FF +#define V_RTE_WRITE_REQ_LUT_IX(x) ((x) << S_RTE_WRITE_REQ_LUT_IX) +#define G_RTE_WRITE_REQ_LUT_IX(x) (((x) >> S_RTE_WRITE_REQ_LUT_IX) & M_RTE_WRITE_REQ_LUT_IX) + +#define S_RTE_WRITE_REQ_LUT_BASE 21 +#define M_RTE_WRITE_REQ_LUT_BASE 0x7FF +#define V_RTE_WRITE_REQ_LUT_BASE(x) ((x) << S_RTE_WRITE_REQ_LUT_BASE) +#define G_RTE_WRITE_REQ_LUT_BASE(x) (((x) >> S_RTE_WRITE_REQ_LUT_BASE) & M_RTE_WRITE_REQ_LUT_BASE) + +struct cpl_rte_write_rpl { + RSS_HDR union opcode_tid ot; + __u8 status; + __u8 rsvd[3]; +}; + +struct cpl_rte_read_req { + WR_HDR; + union opcode_tid ot; + __be32 params; +}; + +struct cpl_rte_read_rpl { + RSS_HDR union opcode_tid ot; + __u8 status; + __u8 rsvd0; + __be16 l2t_idx; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8:7; + __u8 select:1; +#else + __u8 select:1; + __u8:7; +#endif + __u8 rsvd2[3]; + __be32 addr; +}; + +struct cpl_tid_release { + WR_HDR; + union opcode_tid ot; + __be32 rsvd; +}; + +struct cpl_barrier { + WR_HDR; + __u8 opcode; + __u8 rsvd[7]; +}; + +struct cpl_rdma_read_req { + __u8 opcode; + __u8 rsvd[15]; +}; + +struct cpl_rdma_terminate { +#ifdef CHELSIO_FW + __u8 opcode; + __u8 rsvd[2]; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 rspq:3; + __u8:5; +#else + __u8:5; + __u8 rspq:3; +#endif + __be32 tid_len; +#endif + __be32 msn; + __be32 mo; + __u8 data[0]; +}; + +/* cpl_rdma_terminate.tid_len fields */ +#define S_FLIT_CNT 0 +#define M_FLIT_CNT 0xFF +#define V_FLIT_CNT(x) ((x) << S_FLIT_CNT) +#define G_FLIT_CNT(x) (((x) >> S_FLIT_CNT) & M_FLIT_CNT) + +#define S_TERM_TID 8 +#define M_TERM_TID 0xFFFFF +#define V_TERM_TID(x) ((x) << S_TERM_TID) +#define G_TERM_TID(x) (((x) >> S_TERM_TID) & M_TERM_TID) + +/* ULP_TX opcodes */ +enum { ULP_MEM_READ = 2, ULP_MEM_WRITE = 3, ULP_TXPKT = 4 }; + +#define S_ULPTX_CMD 28 +#define M_ULPTX_CMD 0xF +#define V_ULPTX_CMD(x) ((x) << S_ULPTX_CMD) + +#define S_ULPTX_NFLITS 0 +#define M_ULPTX_NFLITS 0xFF +#define V_ULPTX_NFLITS(x) ((x) << S_ULPTX_NFLITS) + +struct ulp_mem_io { + WR_HDR; + __be32 cmd_lock_addr; + __be32 len; +}; + +/* ulp_mem_io.cmd_lock_addr fields */ +#define S_ULP_MEMIO_ADDR 0 +#define M_ULP_MEMIO_ADDR 0x7FFFFFF +#define V_ULP_MEMIO_ADDR(x) ((x) << S_ULP_MEMIO_ADDR) +#define S_ULP_MEMIO_LOCK 27 +#define V_ULP_MEMIO_LOCK(x) ((x) << S_ULP_MEMIO_LOCK) +#define F_ULP_MEMIO_LOCK V_ULP_MEMIO_LOCK(1U) + +/* ulp_mem_io.len fields */ +#define S_ULP_MEMIO_DATA_LEN 28 +#define M_ULP_MEMIO_DATA_LEN 0xF +#define V_ULP_MEMIO_DATA_LEN(x) ((x) << S_ULP_MEMIO_DATA_LEN) + +#endif /* T3_CPL_H */ diff --git a/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c b/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c new file mode 100644 index 000000000000..44ac2f40b644 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c @@ -0,0 +1,3785 @@ +/* + * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "common.h" +#include "regs.h" +#include "sge_defs.h" +#include "firmware_exports.h" + +static void t3_port_intr_clear(struct adapter *adapter, int idx); + +/** + * t3_wait_op_done_val - wait until an operation is completed + * @adapter: the adapter performing the operation + * @reg: the register to check for completion + * @mask: a single-bit field within @reg that indicates completion + * @polarity: the value of the field when the operation is completed + * @attempts: number of check iterations + * @delay: delay in usecs between iterations + * @valp: where to store the value of the register at completion time + * + * Wait until an operation is completed by checking a bit in a register + * up to @attempts times. If @valp is not NULL the value of the register + * at the time it indicated completion is stored there. Returns 0 if the + * operation completes and -EAGAIN otherwise. + */ + +int t3_wait_op_done_val(struct adapter *adapter, int reg, u32 mask, + int polarity, int attempts, int delay, u32 *valp) +{ + while (1) { + u32 val = t3_read_reg(adapter, reg); + + if (!!(val & mask) == polarity) { + if (valp) + *valp = val; + return 0; + } + if (--attempts == 0) + return -EAGAIN; + if (delay) + udelay(delay); + } +} + +/** + * t3_write_regs - write a bunch of registers + * @adapter: the adapter to program + * @p: an array of register address/register value pairs + * @n: the number of address/value pairs + * @offset: register address offset + * + * Takes an array of register address/register value pairs and writes each + * value to the corresponding register. Register addresses are adjusted + * by the supplied offset. + */ +void t3_write_regs(struct adapter *adapter, const struct addr_val_pair *p, + int n, unsigned int offset) +{ + while (n--) { + t3_write_reg(adapter, p->reg_addr + offset, p->val); + p++; + } +} + +/** + * t3_set_reg_field - set a register field to a value + * @adapter: the adapter to program + * @addr: the register address + * @mask: specifies the portion of the register to modify + * @val: the new value for the register field + * + * Sets a register field specified by the supplied mask to the + * given value. + */ +void t3_set_reg_field(struct adapter *adapter, unsigned int addr, u32 mask, + u32 val) +{ + u32 v = t3_read_reg(adapter, addr) & ~mask; + + t3_write_reg(adapter, addr, v | val); + t3_read_reg(adapter, addr); /* flush */ +} + +/** + * t3_read_indirect - read indirectly addressed registers + * @adap: the adapter + * @addr_reg: register holding the indirect address + * @data_reg: register holding the value of the indirect register + * @vals: where the read register values are stored + * @start_idx: index of first indirect register to read + * @nregs: how many indirect registers to read + * + * Reads registers that are accessed indirectly through an address/data + * register pair. + */ +static void t3_read_indirect(struct adapter *adap, unsigned int addr_reg, + unsigned int data_reg, u32 *vals, + unsigned int nregs, unsigned int start_idx) +{ + while (nregs--) { + t3_write_reg(adap, addr_reg, start_idx); + *vals++ = t3_read_reg(adap, data_reg); + start_idx++; + } +} + +/** + * t3_mc7_bd_read - read from MC7 through backdoor accesses + * @mc7: identifies MC7 to read from + * @start: index of first 64-bit word to read + * @n: number of 64-bit words to read + * @buf: where to store the read result + * + * Read n 64-bit words from MC7 starting at word start, using backdoor + * accesses. + */ +int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n, + u64 *buf) +{ + static const int shift[] = { 0, 0, 16, 24 }; + static const int step[] = { 0, 32, 16, 8 }; + + unsigned int size64 = mc7->size / 8; /* # of 64-bit words */ + struct adapter *adap = mc7->adapter; + + if (start >= size64 || start + n > size64) + return -EINVAL; + + start *= (8 << mc7->width); + while (n--) { + int i; + u64 val64 = 0; + + for (i = (1 << mc7->width) - 1; i >= 0; --i) { + int attempts = 10; + u32 val; + + t3_write_reg(adap, mc7->offset + A_MC7_BD_ADDR, start); + t3_write_reg(adap, mc7->offset + A_MC7_BD_OP, 0); + val = t3_read_reg(adap, mc7->offset + A_MC7_BD_OP); + while ((val & F_BUSY) && attempts--) + val = t3_read_reg(adap, + mc7->offset + A_MC7_BD_OP); + if (val & F_BUSY) + return -EIO; + + val = t3_read_reg(adap, mc7->offset + A_MC7_BD_DATA1); + if (mc7->width == 0) { + val64 = t3_read_reg(adap, + mc7->offset + + A_MC7_BD_DATA0); + val64 |= (u64) val << 32; + } else { + if (mc7->width > 1) + val >>= shift[mc7->width]; + val64 |= (u64) val << (step[mc7->width] * i); + } + start += 8; + } + *buf++ = val64; + } + return 0; +} + +/* + * Initialize MI1. + */ +static void mi1_init(struct adapter *adap, const struct adapter_info *ai) +{ + u32 clkdiv = adap->params.vpd.cclk / (2 * adap->params.vpd.mdc) - 1; + u32 val = F_PREEN | V_CLKDIV(clkdiv); + + t3_write_reg(adap, A_MI1_CFG, val); +} + +#define MDIO_ATTEMPTS 20 + +/* + * MI1 read/write operations for clause 22 PHYs. + */ +static int t3_mi1_read(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + int ret; + u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr); + + mutex_lock(&adapter->mdio_lock); + t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), V_ST(1)); + 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, 10); + if (!ret) + ret = t3_read_reg(adapter, A_MI1_DATA); + mutex_unlock(&adapter->mdio_lock); + return ret; +} + +static int t3_mi1_write(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr, u16 val) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + int ret; + u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr); + + mutex_lock(&adapter->mdio_lock); + t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), V_ST(1)); + 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, 10); + mutex_unlock(&adapter->mdio_lock); + return ret; +} + +static const struct mdio_ops mi1_mdio_ops = { + .read = t3_mi1_read, + .write = t3_mi1_write, + .mode_support = MDIO_SUPPORTS_C22 +}; + +/* + * Performs the address cycle for clause 45 PHYs. + * Must be called with the MDIO_LOCK held. + */ +static int mi1_wr_addr(struct adapter *adapter, int phy_addr, int mmd_addr, + int reg_addr) +{ + u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr); + + t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), 0); + 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)); + return t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, + MDIO_ATTEMPTS, 10); +} + +/* + * MI1 read/write operations for indirect-addressed PHYs. + */ +static int mi1_ext_read(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + int ret; + + mutex_lock(&adapter->mdio_lock); + ret = mi1_wr_addr(adapter, phy_addr, mmd_addr, reg_addr); + 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, 10); + if (!ret) + ret = t3_read_reg(adapter, A_MI1_DATA); + } + mutex_unlock(&adapter->mdio_lock); + return ret; +} + +static int mi1_ext_write(struct net_device *dev, int phy_addr, int mmd_addr, + u16 reg_addr, u16 val) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + int ret; + + mutex_lock(&adapter->mdio_lock); + ret = mi1_wr_addr(adapter, phy_addr, mmd_addr, reg_addr); + 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, 10); + } + mutex_unlock(&adapter->mdio_lock); + return ret; +} + +static const struct mdio_ops mi1_mdio_ext_ops = { + .read = mi1_ext_read, + .write = mi1_ext_write, + .mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22 +}; + +/** + * t3_mdio_change_bits - modify the value of a PHY register + * @phy: the PHY to operate on + * @mmd: the device address + * @reg: the register address + * @clear: what part of the register value to mask off + * @set: what part of the register value to set + * + * Changes the value of a PHY register by applying a mask to its current + * value and ORing the result with a new value. + */ +int t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear, + unsigned int set) +{ + int ret; + unsigned int val; + + ret = t3_mdio_read(phy, mmd, reg, &val); + if (!ret) { + val &= ~clear; + ret = t3_mdio_write(phy, mmd, reg, val | set); + } + return ret; +} + +/** + * t3_phy_reset - reset a PHY block + * @phy: the PHY to operate on + * @mmd: the device address of the PHY block to reset + * @wait: how long to wait for the reset to complete in 1ms increments + * + * Resets a PHY block and optionally waits for the reset to complete. + * @mmd should be 0 for 10/100/1000 PHYs and the device address to reset + * for 10G PHYs. + */ +int t3_phy_reset(struct cphy *phy, int mmd, int wait) +{ + int err; + unsigned int ctl; + + err = t3_mdio_change_bits(phy, mmd, MDIO_CTRL1, MDIO_CTRL1_LPOWER, + MDIO_CTRL1_RESET); + if (err || !wait) + return err; + + do { + err = t3_mdio_read(phy, mmd, MDIO_CTRL1, &ctl); + if (err) + return err; + ctl &= MDIO_CTRL1_RESET; + if (ctl) + msleep(1); + } while (ctl && --wait); + + return ctl ? -1 : 0; +} + +/** + * t3_phy_advertise - set the PHY advertisement registers for autoneg + * @phy: the PHY to operate on + * @advert: bitmap of capabilities the PHY should advertise + * + * Sets a 10/100/1000 PHY's advertisement registers to advertise the + * requested capabilities. + */ +int t3_phy_advertise(struct cphy *phy, unsigned int advert) +{ + int err; + unsigned int val = 0; + + err = t3_mdio_read(phy, MDIO_DEVAD_NONE, MII_CTRL1000, &val); + if (err) + return err; + + val &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); + if (advert & ADVERTISED_1000baseT_Half) + val |= ADVERTISE_1000HALF; + if (advert & ADVERTISED_1000baseT_Full) + val |= ADVERTISE_1000FULL; + + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, MII_CTRL1000, val); + if (err) + return err; + + val = 1; + if (advert & ADVERTISED_10baseT_Half) + val |= ADVERTISE_10HALF; + if (advert & ADVERTISED_10baseT_Full) + val |= ADVERTISE_10FULL; + if (advert & ADVERTISED_100baseT_Half) + val |= ADVERTISE_100HALF; + if (advert & ADVERTISED_100baseT_Full) + val |= ADVERTISE_100FULL; + if (advert & ADVERTISED_Pause) + val |= ADVERTISE_PAUSE_CAP; + if (advert & ADVERTISED_Asym_Pause) + val |= ADVERTISE_PAUSE_ASYM; + return t3_mdio_write(phy, MDIO_DEVAD_NONE, MII_ADVERTISE, val); +} + +/** + * t3_phy_advertise_fiber - set fiber PHY advertisement register + * @phy: the PHY to operate on + * @advert: bitmap of capabilities the PHY should advertise + * + * Sets a fiber PHY's advertisement register to advertise the + * requested capabilities. + */ +int t3_phy_advertise_fiber(struct cphy *phy, unsigned int advert) +{ + unsigned int val = 0; + + if (advert & ADVERTISED_1000baseT_Half) + val |= ADVERTISE_1000XHALF; + if (advert & ADVERTISED_1000baseT_Full) + val |= ADVERTISE_1000XFULL; + if (advert & ADVERTISED_Pause) + val |= ADVERTISE_1000XPAUSE; + if (advert & ADVERTISED_Asym_Pause) + val |= ADVERTISE_1000XPSE_ASYM; + return t3_mdio_write(phy, MDIO_DEVAD_NONE, MII_ADVERTISE, val); +} + +/** + * t3_set_phy_speed_duplex - force PHY speed and duplex + * @phy: the PHY to operate on + * @speed: requested PHY speed + * @duplex: requested PHY duplex + * + * Force a 10/100/1000 PHY's speed and duplex. This also disables + * auto-negotiation except for GigE, where auto-negotiation is mandatory. + */ +int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex) +{ + int err; + unsigned int ctl; + + err = t3_mdio_read(phy, MDIO_DEVAD_NONE, MII_BMCR, &ctl); + if (err) + return err; + + if (speed >= 0) { + ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); + if (speed == SPEED_100) + ctl |= BMCR_SPEED100; + else if (speed == SPEED_1000) + ctl |= BMCR_SPEED1000; + } + if (duplex >= 0) { + ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE); + if (duplex == DUPLEX_FULL) + ctl |= BMCR_FULLDPLX; + } + if (ctl & BMCR_SPEED1000) /* auto-negotiation required for GigE */ + ctl |= BMCR_ANENABLE; + return t3_mdio_write(phy, MDIO_DEVAD_NONE, MII_BMCR, ctl); +} + +int t3_phy_lasi_intr_enable(struct cphy *phy) +{ + return t3_mdio_write(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, + MDIO_PMA_LASI_LSALARM); +} + +int t3_phy_lasi_intr_disable(struct cphy *phy) +{ + return t3_mdio_write(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, 0); +} + +int t3_phy_lasi_intr_clear(struct cphy *phy) +{ + u32 val; + + return t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT, &val); +} + +int t3_phy_lasi_intr_handler(struct cphy *phy) +{ + unsigned int status; + int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT, + &status); + + if (err) + return err; + return (status & MDIO_PMA_LASI_LSALARM) ? cphy_cause_link_change : 0; +} + +static const struct adapter_info t3_adap_info[] = { + {1, 1, 0, + F_GPIO2_OEN | F_GPIO4_OEN | + F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, { S_GPIO3, S_GPIO5 }, 0, + &mi1_mdio_ops, "Chelsio PE9000"}, + {1, 1, 0, + F_GPIO2_OEN | F_GPIO4_OEN | + F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, { S_GPIO3, S_GPIO5 }, 0, + &mi1_mdio_ops, "Chelsio T302"}, + {1, 0, 0, + F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN | + F_GPIO11_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"}, + {1, 1, 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, + { S_GPIO9, S_GPIO3 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, + &mi1_mdio_ext_ops, "Chelsio T320"}, + {}, + {}, + {1, 0, 0, + F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO6_OEN | F_GPIO7_OEN | + F_GPIO10_OEN | F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, + { S_GPIO9 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, + &mi1_mdio_ext_ops, "Chelsio T310" }, + {1, 0, 0, + F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | + F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL, + { S_GPIO9 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI, + &mi1_mdio_ext_ops, "Chelsio N320E-G2" }, +}; + +/* + * Return the adapter_info structure with a given index. Out-of-range indices + * return NULL. + */ +const struct adapter_info *t3_get_adapter_info(unsigned int id) +{ + return id < ARRAY_SIZE(t3_adap_info) ? &t3_adap_info[id] : NULL; +} + +struct port_type_info { + int (*phy_prep)(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *ops); +}; + +static const struct port_type_info port_types[] = { + { NULL }, + { t3_ael1002_phy_prep }, + { t3_vsc8211_phy_prep }, + { NULL}, + { t3_xaui_direct_phy_prep }, + { t3_ael2005_phy_prep }, + { t3_qt2045_phy_prep }, + { t3_ael1006_phy_prep }, + { NULL }, + { t3_aq100x_phy_prep }, + { t3_ael2020_phy_prep }, +}; + +#define VPD_ENTRY(name, len) \ + u8 name##_kword[2]; u8 name##_len; u8 name##_data[len] + +/* + * Partial EEPROM Vital Product Data structure. Includes only the ID and + * VPD-R sections. + */ +struct t3_vpd { + u8 id_tag; + u8 id_len[2]; + u8 id_data[16]; + u8 vpdr_tag; + u8 vpdr_len[2]; + VPD_ENTRY(pn, 16); /* part number */ + VPD_ENTRY(ec, 16); /* EC level */ + VPD_ENTRY(sn, SERNUM_LEN); /* serial number */ + VPD_ENTRY(na, 12); /* MAC address base */ + VPD_ENTRY(cclk, 6); /* core clock */ + VPD_ENTRY(mclk, 6); /* mem clock */ + VPD_ENTRY(uclk, 6); /* uP clk */ + VPD_ENTRY(mdc, 6); /* MDIO clk */ + VPD_ENTRY(mt, 2); /* mem timing */ + VPD_ENTRY(xaui0cfg, 6); /* XAUI0 config */ + VPD_ENTRY(xaui1cfg, 6); /* XAUI1 config */ + VPD_ENTRY(port0, 2); /* PHY0 complex */ + VPD_ENTRY(port1, 2); /* PHY1 complex */ + VPD_ENTRY(port2, 2); /* PHY2 complex */ + VPD_ENTRY(port3, 2); /* PHY3 complex */ + VPD_ENTRY(rv, 1); /* csum */ + u32 pad; /* for multiple-of-4 sizing and alignment */ +}; + +#define EEPROM_MAX_POLL 40 +#define EEPROM_STAT_ADDR 0x4000 +#define VPD_BASE 0xc00 + +/** + * t3_seeprom_read - read a VPD EEPROM location + * @adapter: adapter to read + * @addr: EEPROM address + * @data: where to store the read data + * + * Read a 32-bit word from a location in VPD EEPROM using the card's PCI + * VPD ROM capability. A zero is written to the flag bit when the + * address is written to the control register. The hardware device will + * set the flag to 1 when 4 bytes have been read into the data register. + */ +int t3_seeprom_read(struct adapter *adapter, u32 addr, __le32 *data) +{ + u16 val; + int attempts = EEPROM_MAX_POLL; + u32 v; + unsigned int base = adapter->params.pci.vpd_cap_addr; + + if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3)) + return -EINVAL; + + pci_write_config_word(adapter->pdev, base + PCI_VPD_ADDR, addr); + do { + udelay(10); + pci_read_config_word(adapter->pdev, base + PCI_VPD_ADDR, &val); + } while (!(val & PCI_VPD_ADDR_F) && --attempts); + + if (!(val & PCI_VPD_ADDR_F)) { + CH_ERR(adapter, "reading EEPROM address 0x%x failed\n", addr); + return -EIO; + } + pci_read_config_dword(adapter->pdev, base + PCI_VPD_DATA, &v); + *data = cpu_to_le32(v); + return 0; +} + +/** + * t3_seeprom_write - write a VPD EEPROM location + * @adapter: adapter to write + * @addr: EEPROM address + * @data: value to write + * + * Write a 32-bit word to a location in VPD EEPROM using the card's PCI + * VPD ROM capability. + */ +int t3_seeprom_write(struct adapter *adapter, u32 addr, __le32 data) +{ + u16 val; + int attempts = EEPROM_MAX_POLL; + unsigned int base = adapter->params.pci.vpd_cap_addr; + + if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3)) + return -EINVAL; + + pci_write_config_dword(adapter->pdev, base + PCI_VPD_DATA, + le32_to_cpu(data)); + pci_write_config_word(adapter->pdev,base + PCI_VPD_ADDR, + addr | PCI_VPD_ADDR_F); + do { + msleep(1); + pci_read_config_word(adapter->pdev, base + PCI_VPD_ADDR, &val); + } while ((val & PCI_VPD_ADDR_F) && --attempts); + + if (val & PCI_VPD_ADDR_F) { + CH_ERR(adapter, "write to EEPROM address 0x%x failed\n", addr); + return -EIO; + } + return 0; +} + +/** + * t3_seeprom_wp - enable/disable EEPROM write protection + * @adapter: the adapter + * @enable: 1 to enable write protection, 0 to disable it + * + * Enables or disables write protection on the serial EEPROM. + */ +int t3_seeprom_wp(struct adapter *adapter, int enable) +{ + return t3_seeprom_write(adapter, EEPROM_STAT_ADDR, enable ? 0xc : 0); +} + +/** + * get_vpd_params - read VPD parameters from VPD EEPROM + * @adapter: adapter to read + * @p: where to store the parameters + * + * Reads card parameters stored in VPD EEPROM. + */ +static int get_vpd_params(struct adapter *adapter, struct vpd_params *p) +{ + int i, addr, ret; + struct t3_vpd vpd; + + /* + * Card information is normally at VPD_BASE but some early cards had + * it at 0. + */ + ret = t3_seeprom_read(adapter, VPD_BASE, (__le32 *)&vpd); + if (ret) + return ret; + addr = vpd.id_tag == 0x82 ? VPD_BASE : 0; + + for (i = 0; i < sizeof(vpd); i += 4) { + ret = t3_seeprom_read(adapter, addr + i, + (__le32 *)((u8 *)&vpd + i)); + if (ret) + return ret; + } + + 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); + memcpy(p->sn, vpd.sn_data, SERNUM_LEN); + + /* Old eeproms didn't have port information */ + if (adapter->params.rev == 0 && !vpd.port0_data[0]) { + p->port_type[0] = uses_xaui(adapter) ? 1 : 2; + p->port_type[1] = uses_xaui(adapter) ? 6 : 2; + } else { + p->port_type[0] = hex_to_bin(vpd.port0_data[0]); + p->port_type[1] = hex_to_bin(vpd.port1_data[0]); + 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++) + p->eth_base[i] = hex_to_bin(vpd.na_data[2 * i]) * 16 + + hex_to_bin(vpd.na_data[2 * i + 1]); + return 0; +} + +/* serial flash and firmware constants */ +enum { + SF_ATTEMPTS = 5, /* max retries for SF1 operations */ + SF_SEC_SIZE = 64 * 1024, /* serial flash sector size */ + SF_SIZE = SF_SEC_SIZE * 8, /* serial flash size */ + + /* flash command opcodes */ + SF_PROG_PAGE = 2, /* program page */ + SF_WR_DISABLE = 4, /* disable writes */ + SF_RD_STATUS = 5, /* read status register */ + SF_WR_ENABLE = 6, /* enable writes */ + SF_RD_DATA_FAST = 0xb, /* read flash */ + SF_ERASE_SECTOR = 0xd8, /* erase sector */ + + FW_FLASH_BOOT_ADDR = 0x70000, /* start address of FW in flash */ + FW_VERS_ADDR = 0x7fffc, /* flash address holding FW version */ + FW_MIN_SIZE = 8 /* at least version and csum */ +}; + +/** + * sf1_read - read data from the serial flash + * @adapter: the adapter + * @byte_cnt: number of bytes to read + * @cont: whether another operation will be chained + * @valp: where to store the read data + * + * Reads up to 4 bytes of data from the serial flash. The location of + * the read needs to be specified prior to calling this by issuing the + * appropriate commands to the serial flash. + */ +static int sf1_read(struct adapter *adapter, unsigned int byte_cnt, int cont, + u32 *valp) +{ + int ret; + + if (!byte_cnt || byte_cnt > 4) + return -EINVAL; + if (t3_read_reg(adapter, A_SF_OP) & F_BUSY) + return -EBUSY; + t3_write_reg(adapter, A_SF_OP, V_CONT(cont) | V_BYTECNT(byte_cnt - 1)); + ret = t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10); + if (!ret) + *valp = t3_read_reg(adapter, A_SF_DATA); + return ret; +} + +/** + * sf1_write - write data to the serial flash + * @adapter: the adapter + * @byte_cnt: number of bytes to write + * @cont: whether another operation will be chained + * @val: value to write + * + * Writes up to 4 bytes of data to the serial flash. The location of + * the write needs to be specified prior to calling this by issuing the + * appropriate commands to the serial flash. + */ +static int sf1_write(struct adapter *adapter, unsigned int byte_cnt, int cont, + u32 val) +{ + if (!byte_cnt || byte_cnt > 4) + return -EINVAL; + if (t3_read_reg(adapter, A_SF_OP) & F_BUSY) + return -EBUSY; + t3_write_reg(adapter, A_SF_DATA, val); + t3_write_reg(adapter, A_SF_OP, + V_CONT(cont) | V_BYTECNT(byte_cnt - 1) | V_OP(1)); + return t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10); +} + +/** + * flash_wait_op - wait for a flash operation to complete + * @adapter: the adapter + * @attempts: max number of polls of the status register + * @delay: delay between polls in ms + * + * Wait for a flash operation to complete by polling the status register. + */ +static int flash_wait_op(struct adapter *adapter, int attempts, int delay) +{ + int ret; + u32 status; + + while (1) { + if ((ret = sf1_write(adapter, 1, 1, SF_RD_STATUS)) != 0 || + (ret = sf1_read(adapter, 1, 0, &status)) != 0) + return ret; + if (!(status & 1)) + return 0; + if (--attempts == 0) + return -EAGAIN; + if (delay) + msleep(delay); + } +} + +/** + * t3_read_flash - read words from serial flash + * @adapter: the adapter + * @addr: the start address for the read + * @nwords: how many 32-bit words to read + * @data: where to store the read data + * @byte_oriented: whether to store data as bytes or as words + * + * Read the specified number of 32-bit words from the serial flash. + * If @byte_oriented is set the read data is stored as a byte array + * (i.e., big-endian), otherwise as 32-bit words in the platform's + * natural endianess. + */ +static int t3_read_flash(struct adapter *adapter, unsigned int addr, + unsigned int nwords, u32 *data, int byte_oriented) +{ + int ret; + + if (addr + nwords * sizeof(u32) > SF_SIZE || (addr & 3)) + return -EINVAL; + + addr = swab32(addr) | SF_RD_DATA_FAST; + + if ((ret = sf1_write(adapter, 4, 1, addr)) != 0 || + (ret = sf1_read(adapter, 1, 1, data)) != 0) + return ret; + + for (; nwords; nwords--, data++) { + ret = sf1_read(adapter, 4, nwords > 1, data); + if (ret) + return ret; + if (byte_oriented) + *data = htonl(*data); + } + return 0; +} + +/** + * t3_write_flash - write up to a page of data to the serial flash + * @adapter: the adapter + * @addr: the start address to write + * @n: length of data to write + * @data: the data to write + * + * Writes up to a page of data (256 bytes) to the serial flash starting + * at the given address. + */ +static int t3_write_flash(struct adapter *adapter, unsigned int addr, + unsigned int n, const u8 *data) +{ + int ret; + u32 buf[64]; + unsigned int i, c, left, val, offset = addr & 0xff; + + if (addr + n > SF_SIZE || offset + n > 256) + return -EINVAL; + + val = swab32(addr) | SF_PROG_PAGE; + + if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 || + (ret = sf1_write(adapter, 4, 1, val)) != 0) + return ret; + + for (left = n; left; left -= c) { + c = min(left, 4U); + for (val = 0, i = 0; i < c; ++i) + val = (val << 8) + *data++; + + ret = sf1_write(adapter, c, c != left, val); + if (ret) + return ret; + } + if ((ret = flash_wait_op(adapter, 5, 1)) != 0) + return ret; + + /* Read the page to verify the write succeeded */ + ret = t3_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf, 1); + if (ret) + return ret; + + if (memcmp(data - n, (u8 *) buf + offset, n)) + return -EIO; + return 0; +} + +/** + * 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(struct adapter *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 flash. + */ +int t3_check_tpsram_version(struct adapter *adapter) +{ + int ret; + u32 vers; + unsigned int major, minor; + + if (adapter->params.rev == T3_REV_A) + return 0; + + + ret = t3_get_tp_version(adapter, &vers); + if (ret) + return ret; + + major = G_TP_VERSION_MAJOR(vers); + minor = G_TP_VERSION_MINOR(vers); + + if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR) + return 0; + else { + CH_ERR(adapter, "found wrong TP version (%u.%u), " + "driver compiled for version %d.%d\n", major, minor, + TP_VERSION_MAJOR, TP_VERSION_MINOR); + } + 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(struct adapter *adapter, const u8 *tp_sram, + unsigned int size) +{ + u32 csum; + unsigned int i; + const __be32 *p = (const __be32 *)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 +}; + +/** + * t3_get_fw_version - read the firmware version + * @adapter: the adapter + * @vers: where to place the version + * + * Reads the FW version from flash. + */ +int t3_get_fw_version(struct adapter *adapter, u32 *vers) +{ + return t3_read_flash(adapter, FW_VERS_ADDR, 1, vers, 0); +} + +/** + * t3_check_fw_version - check if the FW is compatible with this driver + * @adapter: the adapter + * + * Checks if an adapter's FW is compatible with the driver. Returns 0 + * if the versions are compatible, a negative error otherwise. + */ +int t3_check_fw_version(struct adapter *adapter) +{ + int ret; + u32 vers; + unsigned int type, major, minor; + + ret = t3_get_fw_version(adapter, &vers); + if (ret) + return ret; + + type = G_FW_VERSION_TYPE(vers); + major = G_FW_VERSION_MAJOR(vers); + minor = G_FW_VERSION_MINOR(vers); + + if (type == FW_VERSION_T3 && major == FW_VERSION_MAJOR && + minor == FW_VERSION_MINOR) + return 0; + else if (major != FW_VERSION_MAJOR || minor < FW_VERSION_MINOR) + CH_WARN(adapter, "found old FW minor version(%u.%u), " + "driver compiled for version %u.%u\n", major, minor, + FW_VERSION_MAJOR, FW_VERSION_MINOR); + else { + CH_WARN(adapter, "found newer FW version(%u.%u), " + "driver compiled for version %u.%u\n", major, minor, + FW_VERSION_MAJOR, FW_VERSION_MINOR); + return 0; + } + return -EINVAL; +} + +/** + * t3_flash_erase_sectors - erase a range of flash sectors + * @adapter: the adapter + * @start: the first sector to erase + * @end: the last sector to erase + * + * Erases the sectors in the given range. + */ +static int t3_flash_erase_sectors(struct adapter *adapter, int start, int end) +{ + while (start <= end) { + int ret; + + if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 || + (ret = sf1_write(adapter, 4, 0, + SF_ERASE_SECTOR | (start << 8))) != 0 || + (ret = flash_wait_op(adapter, 5, 500)) != 0) + return ret; + start++; + } + return 0; +} + +/* + * t3_load_fw - download firmware + * @adapter: the adapter + * @fw_data: the firmware image to write + * @size: image size + * + * Write the supplied firmware image to the card's serial flash. + * The FW image has the following sections: @size - 8 bytes of code and + * data, followed by 4 bytes of FW version, followed by the 32-bit + * 1's complement checksum of the whole image. + */ +int t3_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size) +{ + u32 csum; + unsigned int i; + const __be32 *p = (const __be32 *)fw_data; + int ret, addr, fw_sector = FW_FLASH_BOOT_ADDR >> 16; + + if ((size & 3) || size < FW_MIN_SIZE) + return -EINVAL; + if (size > FW_VERS_ADDR + 8 - FW_FLASH_BOOT_ADDR) + return -EFBIG; + + for (csum = 0, i = 0; i < size / sizeof(csum); i++) + csum += ntohl(p[i]); + if (csum != 0xffffffff) { + CH_ERR(adapter, "corrupted firmware image, checksum %u\n", + csum); + return -EINVAL; + } + + ret = t3_flash_erase_sectors(adapter, fw_sector, fw_sector); + if (ret) + goto out; + + size -= 8; /* trim off version and checksum */ + for (addr = FW_FLASH_BOOT_ADDR; size;) { + unsigned int chunk_size = min(size, 256U); + + ret = t3_write_flash(adapter, addr, chunk_size, fw_data); + if (ret) + goto out; + + addr += chunk_size; + fw_data += chunk_size; + size -= chunk_size; + } + + ret = t3_write_flash(adapter, FW_VERS_ADDR, 4, fw_data); +out: + if (ret) + CH_ERR(adapter, "firmware download failed, error %d\n", ret); + return ret; +} + +#define CIM_CTL_BASE 0x2000 + +/** + * t3_cim_ctl_blk_read - read a block from CIM control region + * + * @adap: the adapter + * @addr: the start address within the CIM control region + * @n: number of words to read + * @valp: where to store the result + * + * Reads a block of 4-byte words from the CIM control region. + */ +int t3_cim_ctl_blk_read(struct adapter *adap, unsigned int addr, + unsigned int n, unsigned int *valp) +{ + int ret = 0; + + if (t3_read_reg(adap, A_CIM_HOST_ACC_CTRL) & F_HOSTBUSY) + return -EBUSY; + + for ( ; !ret && n--; addr += 4) { + t3_write_reg(adap, A_CIM_HOST_ACC_CTRL, CIM_CTL_BASE + addr); + ret = t3_wait_op_done(adap, A_CIM_HOST_ACC_CTRL, F_HOSTBUSY, + 0, 5, 2); + if (!ret) + *valp++ = t3_read_reg(adap, A_CIM_HOST_ACC_DATA); + } + return ret; +} + +static void t3_gate_rx_traffic(struct cmac *mac, u32 *rx_cfg, + u32 *rx_hash_high, u32 *rx_hash_low) +{ + /* stop Rx unicast traffic */ + t3_mac_disable_exact_filters(mac); + + /* stop broadcast, multicast, promiscuous mode traffic */ + *rx_cfg = t3_read_reg(mac->adapter, A_XGM_RX_CFG); + t3_set_reg_field(mac->adapter, A_XGM_RX_CFG, + F_ENHASHMCAST | F_DISBCAST | F_COPYALLFRAMES, + F_DISBCAST); + + *rx_hash_high = t3_read_reg(mac->adapter, A_XGM_RX_HASH_HIGH); + t3_write_reg(mac->adapter, A_XGM_RX_HASH_HIGH, 0); + + *rx_hash_low = t3_read_reg(mac->adapter, A_XGM_RX_HASH_LOW); + t3_write_reg(mac->adapter, A_XGM_RX_HASH_LOW, 0); + + /* Leave time to drain max RX fifo */ + msleep(1); +} + +static void t3_open_rx_traffic(struct cmac *mac, u32 rx_cfg, + u32 rx_hash_high, u32 rx_hash_low) +{ + t3_mac_enable_exact_filters(mac); + t3_set_reg_field(mac->adapter, A_XGM_RX_CFG, + F_ENHASHMCAST | F_DISBCAST | F_COPYALLFRAMES, + rx_cfg); + t3_write_reg(mac->adapter, A_XGM_RX_HASH_HIGH, rx_hash_high); + t3_write_reg(mac->adapter, A_XGM_RX_HASH_LOW, rx_hash_low); +} + +/** + * t3_link_changed - handle interface link changes + * @adapter: the adapter + * @port_id: the port index that changed link state + * + * Called when a port's link settings change to propagate the new values + * to the associated PHY and MAC. After performing the common tasks it + * invokes an OS-specific handler. + */ +void t3_link_changed(struct adapter *adapter, int port_id) +{ + int link_ok, speed, duplex, fc; + 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); + + if (!lc->link_ok && link_ok) { + u32 rx_cfg, rx_hash_high, rx_hash_low; + u32 status; + + t3_xgm_intr_enable(adapter, port_id); + t3_gate_rx_traffic(mac, &rx_cfg, &rx_hash_high, &rx_hash_low); + t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, 0); + t3_mac_enable(mac, MAC_DIRECTION_RX); + + status = t3_read_reg(adapter, A_XGM_INT_STATUS + mac->offset); + if (status & F_LINKFAULTCHANGE) { + mac->stats.link_faults++; + pi->link_fault = 1; + } + t3_open_rx_traffic(mac, rx_cfg, rx_hash_high, rx_hash_low); + } + + if (lc->requested_fc & PAUSE_AUTONEG) + fc &= lc->requested_fc; + else + fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); + + if (link_ok == lc->link_ok && speed == lc->speed && + duplex == lc->duplex && fc == lc->fc) + return; /* nothing changed */ + + if (link_ok != lc->link_ok && adapter->params.rev > 0 && + uses_xaui(adapter)) { + if (link_ok) + t3b_pcs_reset(mac); + t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset, + link_ok ? F_TXACTENABLE | F_RXEN : 0); + } + lc->link_ok = link_ok; + lc->speed = speed < 0 ? SPEED_INVALID : speed; + lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex; + + if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE) { + /* Set MAC speed, duplex, and flow control to match PHY. */ + t3_mac_set_speed_duplex_fc(mac, speed, duplex, fc); + lc->fc = fc; + } + + t3_os_link_changed(adapter, port_id, link_ok && !pi->link_fault, + speed, duplex, fc); +} + +void t3_link_fault(struct adapter *adapter, int port_id) +{ + struct port_info *pi = adap2pinfo(adapter, port_id); + struct cmac *mac = &pi->mac; + struct cphy *phy = &pi->phy; + struct link_config *lc = &pi->link_config; + int link_ok, speed, duplex, fc, link_fault; + u32 rx_cfg, rx_hash_high, rx_hash_low; + + t3_gate_rx_traffic(mac, &rx_cfg, &rx_hash_high, &rx_hash_low); + + if (adapter->params.rev > 0 && uses_xaui(adapter)) + t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset, 0); + + t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, 0); + t3_mac_enable(mac, MAC_DIRECTION_RX); + + t3_open_rx_traffic(mac, rx_cfg, rx_hash_high, rx_hash_low); + + link_fault = t3_read_reg(adapter, + A_XGM_INT_STATUS + mac->offset); + link_fault &= F_LINKFAULTCHANGE; + + link_ok = lc->link_ok; + speed = lc->speed; + duplex = lc->duplex; + fc = lc->fc; + + phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc); + + if (link_fault) { + lc->link_ok = 0; + lc->speed = SPEED_INVALID; + lc->duplex = DUPLEX_INVALID; + + t3_os_link_fault(adapter, port_id, 0); + + /* Account link faults only when the phy reports a link up */ + if (link_ok) + mac->stats.link_faults++; + } else { + if (link_ok) + t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset, + F_TXACTENABLE | F_RXEN); + + pi->link_fault = 0; + lc->link_ok = (unsigned char)link_ok; + lc->speed = speed < 0 ? SPEED_INVALID : speed; + lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex; + t3_os_link_fault(adapter, port_id, link_ok); + } +} + +/** + * t3_link_start - apply link configuration to MAC/PHY + * @phy: the PHY to setup + * @mac: the MAC to setup + * @lc: the requested link configuration + * + * Set up a port's MAC and PHY according to a desired link configuration. + * - If the PHY can auto-negotiate first decide what to advertise, then + * enable/disable auto-negotiation as desired, and reset. + * - If the PHY does not auto-negotiate just reset it. + * - If auto-negotiation is off set the MAC to the proper speed/duplex/FC, + * otherwise do it later based on the outcome of auto-negotiation. + */ +int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc) +{ + unsigned int fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); + + lc->link_ok = 0; + if (lc->supported & SUPPORTED_Autoneg) { + lc->advertising &= ~(ADVERTISED_Asym_Pause | ADVERTISED_Pause); + if (fc) { + lc->advertising |= ADVERTISED_Asym_Pause; + if (fc & PAUSE_RX) + lc->advertising |= ADVERTISED_Pause; + } + phy->ops->advertise(phy, lc->advertising); + + if (lc->autoneg == AUTONEG_DISABLE) { + lc->speed = lc->requested_speed; + lc->duplex = lc->requested_duplex; + lc->fc = (unsigned char)fc; + t3_mac_set_speed_duplex_fc(mac, lc->speed, lc->duplex, + fc); + /* Also disables autoneg */ + phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex); + } else + phy->ops->autoneg_enable(phy); + } else { + t3_mac_set_speed_duplex_fc(mac, -1, -1, fc); + lc->fc = (unsigned char)fc; + phy->ops->reset(phy, 0); + } + return 0; +} + +/** + * t3_set_vlan_accel - control HW VLAN extraction + * @adapter: the adapter + * @ports: bitmap of adapter ports to operate on + * @on: enable (1) or disable (0) HW VLAN extraction + * + * Enables or disables HW extraction of VLAN tags for the given port. + */ +void t3_set_vlan_accel(struct adapter *adapter, unsigned int ports, int on) +{ + t3_set_reg_field(adapter, A_TP_OUT_CONFIG, + ports << S_VLANEXTRACTIONENABLE, + on ? (ports << S_VLANEXTRACTIONENABLE) : 0); +} + +struct intr_info { + unsigned int mask; /* bits to check in interrupt status */ + const char *msg; /* message to print or NULL */ + short stat_idx; /* stat counter to increment or -1 */ + unsigned short fatal; /* whether the condition reported is fatal */ +}; + +/** + * t3_handle_intr_status - table driven interrupt handler + * @adapter: the adapter that generated the interrupt + * @reg: the interrupt status register to process + * @mask: a mask to apply to the interrupt status + * @acts: table of interrupt actions + * @stats: statistics counters tracking interrupt occurrences + * + * A table driven interrupt handler that applies a set of masks to an + * interrupt status word and performs the corresponding actions if the + * interrupts described by the mask have occurred. The actions include + * optionally printing a warning or alert message, and optionally + * incrementing a stat counter. The table is terminated by an entry + * specifying mask 0. Returns the number of fatal interrupt conditions. + */ +static int t3_handle_intr_status(struct adapter *adapter, unsigned int reg, + unsigned int mask, + const struct intr_info *acts, + unsigned long *stats) +{ + int fatal = 0; + unsigned int status = t3_read_reg(adapter, reg) & mask; + + for (; acts->mask; ++acts) { + if (!(status & acts->mask)) + continue; + if (acts->fatal) { + fatal++; + CH_ALERT(adapter, "%s (0x%x)\n", + acts->msg, status & acts->mask); + status &= ~acts->mask; + } else if (acts->msg) + CH_WARN(adapter, "%s (0x%x)\n", + acts->msg, status & acts->mask); + if (acts->stat_idx >= 0) + stats[acts->stat_idx]++; + } + if (status) /* clear processed interrupts */ + t3_write_reg(adapter, reg, status); + return fatal; +} + +#define SGE_INTR_MASK (F_RSPQDISABLED | \ + F_UC_REQ_FRAMINGERROR | F_R_REQ_FRAMINGERROR | \ + F_CPPARITYERROR | F_OCPARITYERROR | F_RCPARITYERROR | \ + F_IRPARITYERROR | V_ITPARITYERROR(M_ITPARITYERROR) | \ + V_FLPARITYERROR(M_FLPARITYERROR) | F_LODRBPARITYERROR | \ + F_HIDRBPARITYERROR | F_LORCQPARITYERROR | \ + F_HIRCQPARITYERROR | F_LOPRIORITYDBFULL | \ + F_HIPRIORITYDBFULL | F_LOPRIORITYDBEMPTY | \ + F_HIPRIORITYDBEMPTY | F_HIPIODRBDROPERR | \ + F_LOPIODRBDROPERR) +#define MC5_INTR_MASK (F_PARITYERR | F_ACTRGNFULL | F_UNKNOWNCMD | \ + F_REQQPARERR | F_DISPQPARERR | F_DELACTEMPTY | \ + F_NFASRCHFAIL) +#define MC7_INTR_MASK (F_AE | F_UE | F_CE | V_PE(M_PE)) +#define XGM_INTR_MASK (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \ + V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR) | \ + F_TXFIFO_UNDERRUN) +#define PCIX_INTR_MASK (F_MSTDETPARERR | F_SIGTARABT | F_RCVTARABT | \ + F_RCVMSTABT | F_SIGSYSERR | F_DETPARERR | \ + F_SPLCMPDIS | F_UNXSPLCMP | F_RCVSPLCMPERR | \ + F_DETCORECCERR | F_DETUNCECCERR | F_PIOPARERR | \ + V_WFPARERR(M_WFPARERR) | V_RFPARERR(M_RFPARERR) | \ + V_CFPARERR(M_CFPARERR) /* | V_MSIXPARERR(M_MSIXPARERR) */) +#define PCIE_INTR_MASK (F_UNXSPLCPLERRR | F_UNXSPLCPLERRC | F_PCIE_PIOPARERR |\ + F_PCIE_WFPARERR | F_PCIE_RFPARERR | F_PCIE_CFPARERR | \ + /* V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR) | */ \ + F_RETRYBUFPARERR | F_RETRYLUTPARERR | F_RXPARERR | \ + F_TXPARERR | V_BISTERR(M_BISTERR)) +#define ULPRX_INTR_MASK (F_PARERRDATA | F_PARERRPCMD | F_ARBPF1PERR | \ + F_ARBPF0PERR | F_ARBFPERR | F_PCMDMUXPERR | \ + F_DATASELFRAMEERR1 | F_DATASELFRAMEERR0) +#define ULPTX_INTR_MASK 0xfc +#define CPLSW_INTR_MASK (F_CIM_OP_MAP_PERR | F_TP_FRAMING_ERROR | \ + F_SGE_FRAMING_ERROR | F_CIM_FRAMING_ERROR | \ + F_ZERO_SWITCH_ERROR) +#define CIM_INTR_MASK (F_BLKWRPLINT | F_BLKRDPLINT | F_BLKWRCTLINT | \ + F_BLKRDCTLINT | F_BLKWRFLASHINT | F_BLKRDFLASHINT | \ + F_SGLWRFLASHINT | F_WRBLKFLASHINT | F_BLKWRBOOTINT | \ + F_FLASHRANGEINT | F_SDRAMRANGEINT | F_RSVDSPACEINT | \ + F_DRAMPARERR | F_ICACHEPARERR | F_DCACHEPARERR | \ + F_OBQSGEPARERR | F_OBQULPHIPARERR | F_OBQULPLOPARERR | \ + F_IBQSGELOPARERR | F_IBQSGEHIPARERR | F_IBQULPPARERR | \ + F_IBQTPPARERR | F_ITAGPARERR | F_DTAGPARERR) +#define PMTX_INTR_MASK (F_ZERO_C_CMD_ERROR | ICSPI_FRM_ERR | OESPI_FRM_ERR | \ + V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR) | \ + V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR)) +#define PMRX_INTR_MASK (F_ZERO_E_CMD_ERROR | IESPI_FRM_ERR | OCSPI_FRM_ERR | \ + V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR) | \ + V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR)) +#define MPS_INTR_MASK (V_TX0TPPARERRENB(M_TX0TPPARERRENB) | \ + V_TX1TPPARERRENB(M_TX1TPPARERRENB) | \ + V_RXTPPARERRENB(M_RXTPPARERRENB) | \ + V_MCAPARERRENB(M_MCAPARERRENB)) +#define XGM_EXTRA_INTR_MASK (F_LINKFAULTCHANGE) +#define PL_INTR_MASK (F_T3DBG | F_XGMAC0_0 | F_XGMAC0_1 | F_MC5A | F_PM1_TX | \ + F_PM1_RX | F_ULP2_TX | F_ULP2_RX | F_TP1 | F_CIM | \ + F_MC7_CM | F_MC7_PMTX | F_MC7_PMRX | F_SGE3 | F_PCIM0 | \ + F_MPS0 | F_CPL_SWITCH) +/* + * Interrupt handler for the PCIX1 module. + */ +static void pci_intr_handler(struct adapter *adapter) +{ + static const struct intr_info pcix1_intr_info[] = { + {F_MSTDETPARERR, "PCI master detected parity error", -1, 1}, + {F_SIGTARABT, "PCI signaled target abort", -1, 1}, + {F_RCVTARABT, "PCI received target abort", -1, 1}, + {F_RCVMSTABT, "PCI received master abort", -1, 1}, + {F_SIGSYSERR, "PCI signaled system error", -1, 1}, + {F_DETPARERR, "PCI detected parity error", -1, 1}, + {F_SPLCMPDIS, "PCI split completion discarded", -1, 1}, + {F_UNXSPLCMP, "PCI unexpected split completion error", -1, 1}, + {F_RCVSPLCMPERR, "PCI received split completion error", -1, + 1}, + {F_DETCORECCERR, "PCI correctable ECC error", + STAT_PCI_CORR_ECC, 0}, + {F_DETUNCECCERR, "PCI uncorrectable ECC error", -1, 1}, + {F_PIOPARERR, "PCI PIO FIFO parity error", -1, 1}, + {V_WFPARERR(M_WFPARERR), "PCI write FIFO parity error", -1, + 1}, + {V_RFPARERR(M_RFPARERR), "PCI read FIFO parity error", -1, + 1}, + {V_CFPARERR(M_CFPARERR), "PCI command FIFO parity error", -1, + 1}, + {V_MSIXPARERR(M_MSIXPARERR), "PCI MSI-X table/PBA parity " + "error", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_PCIX_INT_CAUSE, PCIX_INTR_MASK, + pcix1_intr_info, adapter->irq_stats)) + t3_fatal_err(adapter); +} + +/* + * Interrupt handler for the PCIE module. + */ +static void pcie_intr_handler(struct adapter *adapter) +{ + static const struct intr_info pcie_intr_info[] = { + {F_PEXERR, "PCI PEX error", -1, 1}, + {F_UNXSPLCPLERRR, + "PCI unexpected split completion DMA read error", -1, 1}, + {F_UNXSPLCPLERRC, + "PCI unexpected split completion DMA command error", -1, 1}, + {F_PCIE_PIOPARERR, "PCI PIO FIFO parity error", -1, 1}, + {F_PCIE_WFPARERR, "PCI write FIFO parity error", -1, 1}, + {F_PCIE_RFPARERR, "PCI read FIFO parity error", -1, 1}, + {F_PCIE_CFPARERR, "PCI command FIFO parity error", -1, 1}, + {V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR), + "PCI MSI-X table/PBA parity error", -1, 1}, + {F_RETRYBUFPARERR, "PCI retry buffer parity error", -1, 1}, + {F_RETRYLUTPARERR, "PCI retry LUT parity error", -1, 1}, + {F_RXPARERR, "PCI Rx parity error", -1, 1}, + {F_TXPARERR, "PCI Tx parity error", -1, 1}, + {V_BISTERR(M_BISTERR), "PCI BIST error", -1, 1}, + {0} + }; + + if (t3_read_reg(adapter, A_PCIE_INT_CAUSE) & F_PEXERR) + CH_ALERT(adapter, "PEX error code 0x%x\n", + t3_read_reg(adapter, A_PCIE_PEX_ERR)); + + if (t3_handle_intr_status(adapter, A_PCIE_INT_CAUSE, PCIE_INTR_MASK, + pcie_intr_info, adapter->irq_stats)) + t3_fatal_err(adapter); +} + +/* + * TP interrupt handler. + */ +static void tp_intr_handler(struct adapter *adapter) +{ + static const struct intr_info tp_intr_info[] = { + {0xffffff, "TP parity error", -1, 1}, + {0x1000000, "TP out of Rx pages", -1, 1}, + {0x2000000, "TP out of Tx pages", -1, 1}, + {0} + }; + + static const struct intr_info tp_intr_info_t3c[] = { + {0x1fffffff, "TP parity error", -1, 1}, + {F_FLMRXFLSTEMPTY, "TP out of Rx pages", -1, 1}, + {F_FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_TP_INT_CAUSE, 0xffffffff, + adapter->params.rev < T3_REV_C ? + tp_intr_info : tp_intr_info_t3c, NULL)) + t3_fatal_err(adapter); +} + +/* + * CIM interrupt handler. + */ +static void cim_intr_handler(struct adapter *adapter) +{ + static const struct intr_info cim_intr_info[] = { + {F_RSVDSPACEINT, "CIM reserved space write", -1, 1}, + {F_SDRAMRANGEINT, "CIM SDRAM address out of range", -1, 1}, + {F_FLASHRANGEINT, "CIM flash address out of range", -1, 1}, + {F_BLKWRBOOTINT, "CIM block write to boot space", -1, 1}, + {F_WRBLKFLASHINT, "CIM write to cached flash space", -1, 1}, + {F_SGLWRFLASHINT, "CIM single write to flash space", -1, 1}, + {F_BLKRDFLASHINT, "CIM block read from flash space", -1, 1}, + {F_BLKWRFLASHINT, "CIM block write to flash space", -1, 1}, + {F_BLKRDCTLINT, "CIM block read from CTL space", -1, 1}, + {F_BLKWRCTLINT, "CIM block write to CTL space", -1, 1}, + {F_BLKRDPLINT, "CIM block read from PL space", -1, 1}, + {F_BLKWRPLINT, "CIM block write to PL space", -1, 1}, + {F_DRAMPARERR, "CIM DRAM parity error", -1, 1}, + {F_ICACHEPARERR, "CIM icache parity error", -1, 1}, + {F_DCACHEPARERR, "CIM dcache parity error", -1, 1}, + {F_OBQSGEPARERR, "CIM OBQ SGE parity error", -1, 1}, + {F_OBQULPHIPARERR, "CIM OBQ ULPHI parity error", -1, 1}, + {F_OBQULPLOPARERR, "CIM OBQ ULPLO parity error", -1, 1}, + {F_IBQSGELOPARERR, "CIM IBQ SGELO parity error", -1, 1}, + {F_IBQSGEHIPARERR, "CIM IBQ SGEHI parity error", -1, 1}, + {F_IBQULPPARERR, "CIM IBQ ULP parity error", -1, 1}, + {F_IBQTPPARERR, "CIM IBQ TP parity error", -1, 1}, + {F_ITAGPARERR, "CIM itag parity error", -1, 1}, + {F_DTAGPARERR, "CIM dtag parity error", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_CIM_HOST_INT_CAUSE, 0xffffffff, + cim_intr_info, NULL)) + t3_fatal_err(adapter); +} + +/* + * ULP RX interrupt handler. + */ +static void ulprx_intr_handler(struct adapter *adapter) +{ + static const struct intr_info ulprx_intr_info[] = { + {F_PARERRDATA, "ULP RX data parity error", -1, 1}, + {F_PARERRPCMD, "ULP RX command parity error", -1, 1}, + {F_ARBPF1PERR, "ULP RX ArbPF1 parity error", -1, 1}, + {F_ARBPF0PERR, "ULP RX ArbPF0 parity error", -1, 1}, + {F_ARBFPERR, "ULP RX ArbF parity error", -1, 1}, + {F_PCMDMUXPERR, "ULP RX PCMDMUX parity error", -1, 1}, + {F_DATASELFRAMEERR1, "ULP RX frame error", -1, 1}, + {F_DATASELFRAMEERR0, "ULP RX frame error", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_ULPRX_INT_CAUSE, 0xffffffff, + ulprx_intr_info, NULL)) + t3_fatal_err(adapter); +} + +/* + * ULP TX interrupt handler. + */ +static void ulptx_intr_handler(struct adapter *adapter) +{ + static const struct intr_info ulptx_intr_info[] = { + {F_PBL_BOUND_ERR_CH0, "ULP TX channel 0 PBL out of bounds", + STAT_ULP_CH0_PBL_OOB, 0}, + {F_PBL_BOUND_ERR_CH1, "ULP TX channel 1 PBL out of bounds", + STAT_ULP_CH1_PBL_OOB, 0}, + {0xfc, "ULP TX parity error", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_ULPTX_INT_CAUSE, 0xffffffff, + ulptx_intr_info, adapter->irq_stats)) + t3_fatal_err(adapter); +} + +#define ICSPI_FRM_ERR (F_ICSPI0_FIFO2X_RX_FRAMING_ERROR | \ + F_ICSPI1_FIFO2X_RX_FRAMING_ERROR | F_ICSPI0_RX_FRAMING_ERROR | \ + F_ICSPI1_RX_FRAMING_ERROR | F_ICSPI0_TX_FRAMING_ERROR | \ + F_ICSPI1_TX_FRAMING_ERROR) +#define OESPI_FRM_ERR (F_OESPI0_RX_FRAMING_ERROR | \ + F_OESPI1_RX_FRAMING_ERROR | F_OESPI0_TX_FRAMING_ERROR | \ + F_OESPI1_TX_FRAMING_ERROR | F_OESPI0_OFIFO2X_TX_FRAMING_ERROR | \ + F_OESPI1_OFIFO2X_TX_FRAMING_ERROR) + +/* + * PM TX interrupt handler. + */ +static void pmtx_intr_handler(struct adapter *adapter) +{ + static const struct intr_info pmtx_intr_info[] = { + {F_ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1}, + {ICSPI_FRM_ERR, "PMTX ispi framing error", -1, 1}, + {OESPI_FRM_ERR, "PMTX ospi framing error", -1, 1}, + {V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR), + "PMTX ispi parity error", -1, 1}, + {V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR), + "PMTX ospi parity error", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_PM1_TX_INT_CAUSE, 0xffffffff, + pmtx_intr_info, NULL)) + t3_fatal_err(adapter); +} + +#define IESPI_FRM_ERR (F_IESPI0_FIFO2X_RX_FRAMING_ERROR | \ + F_IESPI1_FIFO2X_RX_FRAMING_ERROR | F_IESPI0_RX_FRAMING_ERROR | \ + F_IESPI1_RX_FRAMING_ERROR | F_IESPI0_TX_FRAMING_ERROR | \ + F_IESPI1_TX_FRAMING_ERROR) +#define OCSPI_FRM_ERR (F_OCSPI0_RX_FRAMING_ERROR | \ + F_OCSPI1_RX_FRAMING_ERROR | F_OCSPI0_TX_FRAMING_ERROR | \ + F_OCSPI1_TX_FRAMING_ERROR | F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR | \ + F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR) + +/* + * PM RX interrupt handler. + */ +static void pmrx_intr_handler(struct adapter *adapter) +{ + static const struct intr_info pmrx_intr_info[] = { + {F_ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1}, + {IESPI_FRM_ERR, "PMRX ispi framing error", -1, 1}, + {OCSPI_FRM_ERR, "PMRX ospi framing error", -1, 1}, + {V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR), + "PMRX ispi parity error", -1, 1}, + {V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR), + "PMRX ospi parity error", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_PM1_RX_INT_CAUSE, 0xffffffff, + pmrx_intr_info, NULL)) + t3_fatal_err(adapter); +} + +/* + * CPL switch interrupt handler. + */ +static void cplsw_intr_handler(struct adapter *adapter) +{ + static const struct intr_info cplsw_intr_info[] = { + {F_CIM_OP_MAP_PERR, "CPL switch CIM parity error", -1, 1}, + {F_CIM_OVFL_ERROR, "CPL switch CIM overflow", -1, 1}, + {F_TP_FRAMING_ERROR, "CPL switch TP framing error", -1, 1}, + {F_SGE_FRAMING_ERROR, "CPL switch SGE framing error", -1, 1}, + {F_CIM_FRAMING_ERROR, "CPL switch CIM framing error", -1, 1}, + {F_ZERO_SWITCH_ERROR, "CPL switch no-switch error", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_CPL_INTR_CAUSE, 0xffffffff, + cplsw_intr_info, NULL)) + t3_fatal_err(adapter); +} + +/* + * MPS interrupt handler. + */ +static void mps_intr_handler(struct adapter *adapter) +{ + static const struct intr_info mps_intr_info[] = { + {0x1ff, "MPS parity error", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_MPS_INT_CAUSE, 0xffffffff, + mps_intr_info, NULL)) + t3_fatal_err(adapter); +} + +#define MC7_INTR_FATAL (F_UE | V_PE(M_PE) | F_AE) + +/* + * MC7 interrupt handler. + */ +static void mc7_intr_handler(struct mc7 *mc7) +{ + struct adapter *adapter = mc7->adapter; + u32 cause = t3_read_reg(adapter, mc7->offset + A_MC7_INT_CAUSE); + + if (cause & F_CE) { + mc7->stats.corr_err++; + CH_WARN(adapter, "%s MC7 correctable error at addr 0x%x, " + "data 0x%x 0x%x 0x%x\n", mc7->name, + t3_read_reg(adapter, mc7->offset + A_MC7_CE_ADDR), + t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA0), + t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA1), + t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA2)); + } + + if (cause & F_UE) { + mc7->stats.uncorr_err++; + CH_ALERT(adapter, "%s MC7 uncorrectable error at addr 0x%x, " + "data 0x%x 0x%x 0x%x\n", mc7->name, + t3_read_reg(adapter, mc7->offset + A_MC7_UE_ADDR), + t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA0), + t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA1), + t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA2)); + } + + if (G_PE(cause)) { + mc7->stats.parity_err++; + CH_ALERT(adapter, "%s MC7 parity error 0x%x\n", + mc7->name, G_PE(cause)); + } + + if (cause & F_AE) { + u32 addr = 0; + + if (adapter->params.rev > 0) + addr = t3_read_reg(adapter, + mc7->offset + A_MC7_ERR_ADDR); + mc7->stats.addr_err++; + CH_ALERT(adapter, "%s MC7 address error: 0x%x\n", + mc7->name, addr); + } + + if (cause & MC7_INTR_FATAL) + t3_fatal_err(adapter); + + t3_write_reg(adapter, mc7->offset + A_MC7_INT_CAUSE, cause); +} + +#define XGM_INTR_FATAL (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \ + V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR)) +/* + * XGMAC interrupt handler. + */ +static int mac_intr_handler(struct adapter *adap, unsigned int idx) +{ + struct cmac *mac = &adap2pinfo(adap, idx)->mac; + /* + * We mask out interrupt causes for which we're not taking interrupts. + * This allows us to use polling logic to monitor some of the other + * conditions when taking interrupts would impose too much load on the + * system. + */ + u32 cause = t3_read_reg(adap, A_XGM_INT_CAUSE + mac->offset) & + ~F_RXFIFO_OVERFLOW; + + if (cause & V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR)) { + mac->stats.tx_fifo_parity_err++; + CH_ALERT(adap, "port%d: MAC TX FIFO parity error\n", idx); + } + if (cause & V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR)) { + mac->stats.rx_fifo_parity_err++; + CH_ALERT(adap, "port%d: MAC RX FIFO parity error\n", idx); + } + if (cause & F_TXFIFO_UNDERRUN) + mac->stats.tx_fifo_urun++; + if (cause & F_RXFIFO_OVERFLOW) + mac->stats.rx_fifo_ovfl++; + if (cause & V_SERDES_LOS(M_SERDES_LOS)) + mac->stats.serdes_signal_loss++; + if (cause & F_XAUIPCSCTCERR) + mac->stats.xaui_pcs_ctc_err++; + if (cause & F_XAUIPCSALIGNCHANGE) + mac->stats.xaui_pcs_align_change++; + if (cause & F_XGM_INT) { + t3_set_reg_field(adap, + A_XGM_INT_ENABLE + mac->offset, + F_XGM_INT, 0); + mac->stats.link_faults++; + + t3_os_link_fault_handler(adap, idx); + } + + if (cause & XGM_INTR_FATAL) + t3_fatal_err(adap); + + t3_write_reg(adap, A_XGM_INT_CAUSE + mac->offset, cause); + return cause != 0; +} + +/* + * Interrupt handler for PHY events. + */ +int t3_phy_intr_handler(struct adapter *adapter) +{ + u32 i, cause = t3_read_reg(adapter, A_T3DBG_INT_CAUSE); + + for_each_port(adapter, i) { + struct port_info *p = adap2pinfo(adapter, i); + + if (!(p->phy.caps & SUPPORTED_IRQ)) + continue; + + if (cause & (1 << adapter_info(adapter)->gpio_intr[i])) { + int phy_cause = p->phy.ops->intr_handler(&p->phy); + + if (phy_cause & cphy_cause_link_change) + t3_link_changed(adapter, i); + if (phy_cause & cphy_cause_fifo_error) + p->phy.fifo_errors++; + if (phy_cause & cphy_cause_module_change) + t3_os_phymod_changed(adapter, i); + } + } + + t3_write_reg(adapter, A_T3DBG_INT_CAUSE, cause); + return 0; +} + +/* + * T3 slow path (non-data) interrupt handler. + */ +int t3_slow_intr_handler(struct adapter *adapter) +{ + u32 cause = t3_read_reg(adapter, A_PL_INT_CAUSE0); + + cause &= adapter->slow_intr_mask; + if (!cause) + return 0; + if (cause & F_PCIM0) { + if (is_pcie(adapter)) + pcie_intr_handler(adapter); + else + pci_intr_handler(adapter); + } + if (cause & F_SGE3) + t3_sge_err_intr_handler(adapter); + if (cause & F_MC7_PMRX) + mc7_intr_handler(&adapter->pmrx); + if (cause & F_MC7_PMTX) + mc7_intr_handler(&adapter->pmtx); + if (cause & F_MC7_CM) + mc7_intr_handler(&adapter->cm); + if (cause & F_CIM) + cim_intr_handler(adapter); + if (cause & F_TP1) + tp_intr_handler(adapter); + if (cause & F_ULP2_RX) + ulprx_intr_handler(adapter); + if (cause & F_ULP2_TX) + ulptx_intr_handler(adapter); + if (cause & F_PM1_RX) + pmrx_intr_handler(adapter); + if (cause & F_PM1_TX) + pmtx_intr_handler(adapter); + if (cause & F_CPL_SWITCH) + cplsw_intr_handler(adapter); + if (cause & F_MPS0) + mps_intr_handler(adapter); + if (cause & F_MC5A) + t3_mc5_intr_handler(&adapter->mc5); + if (cause & F_XGMAC0_0) + mac_intr_handler(adapter, 0); + if (cause & F_XGMAC0_1) + mac_intr_handler(adapter, 1); + if (cause & F_T3DBG) + t3_os_ext_intr_handler(adapter); + + /* Clear the interrupts just processed. */ + t3_write_reg(adapter, A_PL_INT_CAUSE0, cause); + t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */ + return 1; +} + +static unsigned int calc_gpio_intr(struct adapter *adap) +{ + unsigned int i, gpi_intr = 0; + + for_each_port(adap, i) + if ((adap2pinfo(adap, i)->phy.caps & SUPPORTED_IRQ) && + adapter_info(adap)->gpio_intr[i]) + gpi_intr |= 1 << adapter_info(adap)->gpio_intr[i]; + return gpi_intr; +} + +/** + * t3_intr_enable - enable interrupts + * @adapter: the adapter whose interrupts should be enabled + * + * Enable interrupts by setting the interrupt enable registers of the + * various HW modules and then enabling the top-level interrupt + * concentrator. + */ +void t3_intr_enable(struct adapter *adapter) +{ + static const struct addr_val_pair intr_en_avp[] = { + {A_SG_INT_ENABLE, SGE_INTR_MASK}, + {A_MC7_INT_ENABLE, MC7_INTR_MASK}, + {A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR, + MC7_INTR_MASK}, + {A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR, + MC7_INTR_MASK}, + {A_MC5_DB_INT_ENABLE, MC5_INTR_MASK}, + {A_ULPRX_INT_ENABLE, ULPRX_INTR_MASK}, + {A_PM1_TX_INT_ENABLE, PMTX_INTR_MASK}, + {A_PM1_RX_INT_ENABLE, PMRX_INTR_MASK}, + {A_CIM_HOST_INT_ENABLE, CIM_INTR_MASK}, + {A_MPS_INT_ENABLE, MPS_INTR_MASK}, + }; + + adapter->slow_intr_mask = PL_INTR_MASK; + + t3_write_regs(adapter, intr_en_avp, ARRAY_SIZE(intr_en_avp), 0); + t3_write_reg(adapter, A_TP_INT_ENABLE, + adapter->params.rev >= T3_REV_C ? 0x2bfffff : 0x3bfffff); + + if (adapter->params.rev > 0) { + t3_write_reg(adapter, A_CPL_INTR_ENABLE, + CPLSW_INTR_MASK | F_CIM_OVFL_ERROR); + t3_write_reg(adapter, A_ULPTX_INT_ENABLE, + ULPTX_INTR_MASK | F_PBL_BOUND_ERR_CH0 | + F_PBL_BOUND_ERR_CH1); + } else { + t3_write_reg(adapter, A_CPL_INTR_ENABLE, CPLSW_INTR_MASK); + t3_write_reg(adapter, A_ULPTX_INT_ENABLE, ULPTX_INTR_MASK); + } + + t3_write_reg(adapter, A_T3DBG_INT_ENABLE, calc_gpio_intr(adapter)); + + if (is_pcie(adapter)) + t3_write_reg(adapter, A_PCIE_INT_ENABLE, PCIE_INTR_MASK); + else + t3_write_reg(adapter, A_PCIX_INT_ENABLE, PCIX_INTR_MASK); + t3_write_reg(adapter, A_PL_INT_ENABLE0, adapter->slow_intr_mask); + t3_read_reg(adapter, A_PL_INT_ENABLE0); /* flush */ +} + +/** + * t3_intr_disable - disable a card's interrupts + * @adapter: the adapter whose interrupts should be disabled + * + * Disable interrupts. We only disable the top-level interrupt + * concentrator and the SGE data interrupts. + */ +void t3_intr_disable(struct adapter *adapter) +{ + t3_write_reg(adapter, A_PL_INT_ENABLE0, 0); + t3_read_reg(adapter, A_PL_INT_ENABLE0); /* flush */ + adapter->slow_intr_mask = 0; +} + +/** + * t3_intr_clear - clear all interrupts + * @adapter: the adapter whose interrupts should be cleared + * + * Clears all interrupts. + */ +void t3_intr_clear(struct adapter *adapter) +{ + static const unsigned int cause_reg_addr[] = { + A_SG_INT_CAUSE, + A_SG_RSPQ_FL_STATUS, + A_PCIX_INT_CAUSE, + A_MC7_INT_CAUSE, + A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR, + A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR, + A_CIM_HOST_INT_CAUSE, + A_TP_INT_CAUSE, + A_MC5_DB_INT_CAUSE, + A_ULPRX_INT_CAUSE, + A_ULPTX_INT_CAUSE, + A_CPL_INTR_CAUSE, + A_PM1_TX_INT_CAUSE, + A_PM1_RX_INT_CAUSE, + A_MPS_INT_CAUSE, + A_T3DBG_INT_CAUSE, + }; + unsigned int i; + + /* Clear PHY and MAC interrupts for each port. */ + for_each_port(adapter, i) + t3_port_intr_clear(adapter, i); + + for (i = 0; i < ARRAY_SIZE(cause_reg_addr); ++i) + t3_write_reg(adapter, cause_reg_addr[i], 0xffffffff); + + if (is_pcie(adapter)) + t3_write_reg(adapter, A_PCIE_PEX_ERR, 0xffffffff); + t3_write_reg(adapter, A_PL_INT_CAUSE0, 0xffffffff); + t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */ +} + +void t3_xgm_intr_enable(struct adapter *adapter, int idx) +{ + struct port_info *pi = adap2pinfo(adapter, idx); + + t3_write_reg(adapter, A_XGM_XGM_INT_ENABLE + pi->mac.offset, + XGM_EXTRA_INTR_MASK); +} + +void t3_xgm_intr_disable(struct adapter *adapter, int idx) +{ + struct port_info *pi = adap2pinfo(adapter, idx); + + t3_write_reg(adapter, A_XGM_XGM_INT_DISABLE + pi->mac.offset, + 0x7ff); +} + +/** + * t3_port_intr_enable - enable port-specific interrupts + * @adapter: associated adapter + * @idx: index of port whose interrupts should be enabled + * + * Enable port-specific (i.e., MAC and PHY) interrupts for the given + * adapter port. + */ +void t3_port_intr_enable(struct adapter *adapter, int idx) +{ + struct cphy *phy = &adap2pinfo(adapter, idx)->phy; + + t3_write_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx), XGM_INTR_MASK); + t3_read_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx)); /* flush */ + phy->ops->intr_enable(phy); +} + +/** + * t3_port_intr_disable - disable port-specific interrupts + * @adapter: associated adapter + * @idx: index of port whose interrupts should be disabled + * + * Disable port-specific (i.e., MAC and PHY) interrupts for the given + * adapter port. + */ +void t3_port_intr_disable(struct adapter *adapter, int idx) +{ + struct cphy *phy = &adap2pinfo(adapter, idx)->phy; + + t3_write_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx), 0); + t3_read_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx)); /* flush */ + phy->ops->intr_disable(phy); +} + +/** + * t3_port_intr_clear - clear port-specific interrupts + * @adapter: associated adapter + * @idx: index of port whose interrupts to clear + * + * Clear port-specific (i.e., MAC and PHY) interrupts for the given + * adapter port. + */ +static void t3_port_intr_clear(struct adapter *adapter, int idx) +{ + struct cphy *phy = &adap2pinfo(adapter, idx)->phy; + + t3_write_reg(adapter, XGM_REG(A_XGM_INT_CAUSE, idx), 0xffffffff); + t3_read_reg(adapter, XGM_REG(A_XGM_INT_CAUSE, idx)); /* flush */ + phy->ops->intr_clear(phy); +} + +#define SG_CONTEXT_CMD_ATTEMPTS 100 + +/** + * t3_sge_write_context - write an SGE context + * @adapter: the adapter + * @id: the context id + * @type: the context type + * + * Program an SGE context with the values already loaded in the + * CONTEXT_DATA? registers. + */ +static int t3_sge_write_context(struct adapter *adapter, unsigned int id, + unsigned int type) +{ + if (type == F_RESPONSEQ) { + /* + * Can't write the Response Queue Context bits for + * Interrupt Armed or the Reserve bits after the chip + * has been initialized out of reset. Writing to these + * bits can confuse the hardware. + */ + t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0xffffffff); + t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0xffffffff); + t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0x17ffffff); + t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0xffffffff); + } else { + t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0xffffffff); + t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0xffffffff); + t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0xffffffff); + t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0xffffffff); + } + t3_write_reg(adapter, A_SG_CONTEXT_CMD, + V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id)); + return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, + 0, SG_CONTEXT_CMD_ATTEMPTS, 1); +} + +/** + * clear_sge_ctxt - completely clear an SGE context + * @adapter: the adapter + * @id: the context id + * @type: the context type + * + * Completely clear an SGE context. Used predominantly at post-reset + * initialization. Note in particular that we don't skip writing to any + * "sensitive bits" in the contexts the way that t3_sge_write_context() + * does ... + */ +static int clear_sge_ctxt(struct adapter *adap, unsigned int id, + unsigned int type) +{ + t3_write_reg(adap, A_SG_CONTEXT_DATA0, 0); + t3_write_reg(adap, A_SG_CONTEXT_DATA1, 0); + t3_write_reg(adap, A_SG_CONTEXT_DATA2, 0); + t3_write_reg(adap, A_SG_CONTEXT_DATA3, 0); + t3_write_reg(adap, A_SG_CONTEXT_MASK0, 0xffffffff); + t3_write_reg(adap, A_SG_CONTEXT_MASK1, 0xffffffff); + t3_write_reg(adap, A_SG_CONTEXT_MASK2, 0xffffffff); + t3_write_reg(adap, A_SG_CONTEXT_MASK3, 0xffffffff); + t3_write_reg(adap, A_SG_CONTEXT_CMD, + V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id)); + return t3_wait_op_done(adap, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, + 0, SG_CONTEXT_CMD_ATTEMPTS, 1); +} + +/** + * t3_sge_init_ecntxt - initialize an SGE egress context + * @adapter: the adapter to configure + * @id: the context id + * @gts_enable: whether to enable GTS for the context + * @type: the egress context type + * @respq: associated response queue + * @base_addr: base address of queue + * @size: number of queue entries + * @token: uP token + * @gen: initial generation value for the context + * @cidx: consumer pointer + * + * Initialize an SGE egress context and make it ready for use. If the + * platform allows concurrent context operations, the caller is + * responsible for appropriate locking. + */ +int t3_sge_init_ecntxt(struct adapter *adapter, unsigned int id, int gts_enable, + enum sge_context_type type, int respq, u64 base_addr, + unsigned int size, unsigned int token, int gen, + unsigned int cidx) +{ + unsigned int credits = type == SGE_CNTXT_OFLD ? 0 : FW_WR_NUM; + + if (base_addr & 0xfff) /* must be 4K aligned */ + return -EINVAL; + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + base_addr >>= 12; + t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_EC_INDEX(cidx) | + V_EC_CREDITS(credits) | V_EC_GTS(gts_enable)); + t3_write_reg(adapter, A_SG_CONTEXT_DATA1, V_EC_SIZE(size) | + V_EC_BASE_LO(base_addr & 0xffff)); + base_addr >>= 16; + t3_write_reg(adapter, A_SG_CONTEXT_DATA2, base_addr); + base_addr >>= 32; + t3_write_reg(adapter, A_SG_CONTEXT_DATA3, + V_EC_BASE_HI(base_addr & 0xf) | V_EC_RESPQ(respq) | + V_EC_TYPE(type) | V_EC_GEN(gen) | V_EC_UP_TOKEN(token) | + F_EC_VALID); + return t3_sge_write_context(adapter, id, F_EGRESS); +} + +/** + * t3_sge_init_flcntxt - initialize an SGE free-buffer list context + * @adapter: the adapter to configure + * @id: the context id + * @gts_enable: whether to enable GTS for the context + * @base_addr: base address of queue + * @size: number of queue entries + * @bsize: size of each buffer for this queue + * @cong_thres: threshold to signal congestion to upstream producers + * @gen: initial generation value for the context + * @cidx: consumer pointer + * + * Initialize an SGE free list context and make it ready for use. The + * caller is responsible for ensuring only one context operation occurs + * at a time. + */ +int t3_sge_init_flcntxt(struct adapter *adapter, unsigned int id, + int gts_enable, u64 base_addr, unsigned int size, + unsigned int bsize, unsigned int cong_thres, int gen, + unsigned int cidx) +{ + if (base_addr & 0xfff) /* must be 4K aligned */ + return -EINVAL; + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + base_addr >>= 12; + t3_write_reg(adapter, A_SG_CONTEXT_DATA0, base_addr); + base_addr >>= 32; + t3_write_reg(adapter, A_SG_CONTEXT_DATA1, + V_FL_BASE_HI((u32) base_addr) | + V_FL_INDEX_LO(cidx & M_FL_INDEX_LO)); + t3_write_reg(adapter, A_SG_CONTEXT_DATA2, V_FL_SIZE(size) | + V_FL_GEN(gen) | V_FL_INDEX_HI(cidx >> 12) | + V_FL_ENTRY_SIZE_LO(bsize & M_FL_ENTRY_SIZE_LO)); + t3_write_reg(adapter, A_SG_CONTEXT_DATA3, + V_FL_ENTRY_SIZE_HI(bsize >> (32 - S_FL_ENTRY_SIZE_LO)) | + V_FL_CONG_THRES(cong_thres) | V_FL_GTS(gts_enable)); + return t3_sge_write_context(adapter, id, F_FREELIST); +} + +/** + * t3_sge_init_rspcntxt - initialize an SGE response queue context + * @adapter: the adapter to configure + * @id: the context id + * @irq_vec_idx: MSI-X interrupt vector index, 0 if no MSI-X, -1 if no IRQ + * @base_addr: base address of queue + * @size: number of queue entries + * @fl_thres: threshold for selecting the normal or jumbo free list + * @gen: initial generation value for the context + * @cidx: consumer pointer + * + * Initialize an SGE response queue context and make it ready for use. + * The caller is responsible for ensuring only one context operation + * occurs at a time. + */ +int t3_sge_init_rspcntxt(struct adapter *adapter, unsigned int id, + int irq_vec_idx, u64 base_addr, unsigned int size, + unsigned int fl_thres, int gen, unsigned int cidx) +{ + unsigned int intr = 0; + + if (base_addr & 0xfff) /* must be 4K aligned */ + return -EINVAL; + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + base_addr >>= 12; + t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size) | + V_CQ_INDEX(cidx)); + t3_write_reg(adapter, A_SG_CONTEXT_DATA1, base_addr); + base_addr >>= 32; + if (irq_vec_idx >= 0) + intr = V_RQ_MSI_VEC(irq_vec_idx) | F_RQ_INTR_EN; + t3_write_reg(adapter, A_SG_CONTEXT_DATA2, + V_CQ_BASE_HI((u32) base_addr) | intr | V_RQ_GEN(gen)); + t3_write_reg(adapter, A_SG_CONTEXT_DATA3, fl_thres); + return t3_sge_write_context(adapter, id, F_RESPONSEQ); +} + +/** + * t3_sge_init_cqcntxt - initialize an SGE completion queue context + * @adapter: the adapter to configure + * @id: the context id + * @base_addr: base address of queue + * @size: number of queue entries + * @rspq: response queue for async notifications + * @ovfl_mode: CQ overflow mode + * @credits: completion queue credits + * @credit_thres: the credit threshold + * + * Initialize an SGE completion queue context and make it ready for use. + * The caller is responsible for ensuring only one context operation + * occurs at a time. + */ +int t3_sge_init_cqcntxt(struct adapter *adapter, unsigned int id, u64 base_addr, + unsigned int size, int rspq, int ovfl_mode, + unsigned int credits, unsigned int credit_thres) +{ + if (base_addr & 0xfff) /* must be 4K aligned */ + return -EINVAL; + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + base_addr >>= 12; + t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size)); + t3_write_reg(adapter, A_SG_CONTEXT_DATA1, base_addr); + base_addr >>= 32; + t3_write_reg(adapter, A_SG_CONTEXT_DATA2, + V_CQ_BASE_HI((u32) base_addr) | V_CQ_RSPQ(rspq) | + V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode) | + V_CQ_ERR(ovfl_mode)); + t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_CQ_CREDITS(credits) | + V_CQ_CREDIT_THRES(credit_thres)); + return t3_sge_write_context(adapter, id, F_CQ); +} + +/** + * t3_sge_enable_ecntxt - enable/disable an SGE egress context + * @adapter: the adapter + * @id: the egress context id + * @enable: enable (1) or disable (0) the context + * + * Enable or disable an SGE egress context. The caller is responsible for + * ensuring only one context operation occurs at a time. + */ +int t3_sge_enable_ecntxt(struct adapter *adapter, unsigned int id, int enable) +{ + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK3, F_EC_VALID); + t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_EC_VALID(enable)); + t3_write_reg(adapter, A_SG_CONTEXT_CMD, + V_CONTEXT_CMD_OPCODE(1) | F_EGRESS | V_CONTEXT(id)); + return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, + 0, SG_CONTEXT_CMD_ATTEMPTS, 1); +} + +/** + * t3_sge_disable_fl - disable an SGE free-buffer list + * @adapter: the adapter + * @id: the free list context id + * + * Disable an SGE free-buffer list. The caller is responsible for + * ensuring only one context operation occurs at a time. + */ +int t3_sge_disable_fl(struct adapter *adapter, unsigned int id) +{ + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK2, V_FL_SIZE(M_FL_SIZE)); + t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0); + t3_write_reg(adapter, A_SG_CONTEXT_DATA2, 0); + t3_write_reg(adapter, A_SG_CONTEXT_CMD, + V_CONTEXT_CMD_OPCODE(1) | F_FREELIST | V_CONTEXT(id)); + return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, + 0, SG_CONTEXT_CMD_ATTEMPTS, 1); +} + +/** + * t3_sge_disable_rspcntxt - disable an SGE response queue + * @adapter: the adapter + * @id: the response queue context id + * + * Disable an SGE response queue. The caller is responsible for + * ensuring only one context operation occurs at a time. + */ +int t3_sge_disable_rspcntxt(struct adapter *adapter, unsigned int id) +{ + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE)); + t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0); + t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0); + t3_write_reg(adapter, A_SG_CONTEXT_CMD, + V_CONTEXT_CMD_OPCODE(1) | F_RESPONSEQ | V_CONTEXT(id)); + return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, + 0, SG_CONTEXT_CMD_ATTEMPTS, 1); +} + +/** + * t3_sge_disable_cqcntxt - disable an SGE completion queue + * @adapter: the adapter + * @id: the completion queue context id + * + * Disable an SGE completion queue. The caller is responsible for + * ensuring only one context operation occurs at a time. + */ +int t3_sge_disable_cqcntxt(struct adapter *adapter, unsigned int id) +{ + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE)); + t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0); + t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0); + t3_write_reg(adapter, A_SG_CONTEXT_CMD, + V_CONTEXT_CMD_OPCODE(1) | F_CQ | V_CONTEXT(id)); + return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, + 0, SG_CONTEXT_CMD_ATTEMPTS, 1); +} + +/** + * t3_sge_cqcntxt_op - perform an operation on a completion queue context + * @adapter: the adapter + * @id: the context id + * @op: the operation to perform + * + * Perform the selected operation on an SGE completion queue context. + * The caller is responsible for ensuring only one context operation + * occurs at a time. + */ +int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op, + unsigned int credits) +{ + u32 val; + + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + t3_write_reg(adapter, A_SG_CONTEXT_DATA0, credits << 16); + t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(op) | + V_CONTEXT(id) | F_CQ); + if (t3_wait_op_done_val(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, + 0, SG_CONTEXT_CMD_ATTEMPTS, 1, &val)) + return -EIO; + + if (op >= 2 && op < 7) { + if (adapter->params.rev > 0) + return G_CQ_INDEX(val); + + t3_write_reg(adapter, A_SG_CONTEXT_CMD, + V_CONTEXT_CMD_OPCODE(0) | F_CQ | V_CONTEXT(id)); + if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, + F_CONTEXT_CMD_BUSY, 0, + SG_CONTEXT_CMD_ATTEMPTS, 1)) + return -EIO; + return G_CQ_INDEX(t3_read_reg(adapter, A_SG_CONTEXT_DATA0)); + } + return 0; +} + +/** + * t3_config_rss - configure Rx packet steering + * @adapter: the adapter + * @rss_config: RSS settings (written to TP_RSS_CONFIG) + * @cpus: values for the CPU lookup table (0xff terminated) + * @rspq: values for the response queue lookup table (0xffff terminated) + * + * Programs the receive packet steering logic. @cpus and @rspq provide + * the values for the CPU and response queue lookup tables. If they + * provide fewer values than the size of the tables the supplied values + * are used repeatedly until the tables are fully populated. + */ +void t3_config_rss(struct adapter *adapter, unsigned int rss_config, + const u8 * cpus, const u16 *rspq) +{ + int i, j, cpu_idx = 0, q_idx = 0; + + if (cpus) + for (i = 0; i < RSS_TABLE_SIZE; ++i) { + u32 val = i << 16; + + for (j = 0; j < 2; ++j) { + val |= (cpus[cpu_idx++] & 0x3f) << (8 * j); + if (cpus[cpu_idx] == 0xff) + cpu_idx = 0; + } + t3_write_reg(adapter, A_TP_RSS_LKP_TABLE, val); + } + + if (rspq) + for (i = 0; i < RSS_TABLE_SIZE; ++i) { + t3_write_reg(adapter, A_TP_RSS_MAP_TABLE, + (i << 16) | rspq[q_idx++]); + if (rspq[q_idx] == 0xffff) + q_idx = 0; + } + + t3_write_reg(adapter, A_TP_RSS_CONFIG, rss_config); +} + +/** + * t3_tp_set_offload_mode - put TP in NIC/offload mode + * @adap: the adapter + * @enable: 1 to select offload mode, 0 for regular NIC + * + * Switches TP to NIC/offload mode. + */ +void t3_tp_set_offload_mode(struct adapter *adap, int enable) +{ + if (is_offload(adap) || !enable) + t3_set_reg_field(adap, A_TP_IN_CONFIG, F_NICMODE, + V_NICMODE(!enable)); +} + +/** + * pm_num_pages - calculate the number of pages of the payload memory + * @mem_size: the size of the payload memory + * @pg_size: the size of each payload memory page + * + * Calculate the number of pages, each of the given size, that fit in a + * memory of the specified size, respecting the HW requirement that the + * number of pages must be a multiple of 24. + */ +static inline unsigned int pm_num_pages(unsigned int mem_size, + unsigned int pg_size) +{ + unsigned int n = mem_size / pg_size; + + return n - n % 24; +} + +#define mem_region(adap, start, size, reg) \ + t3_write_reg((adap), A_ ## reg, (start)); \ + start += size + +/** + * partition_mem - partition memory and configure TP memory settings + * @adap: the adapter + * @p: the TP parameters + * + * Partitions context and payload memory and configures TP's memory + * registers. + */ +static void partition_mem(struct adapter *adap, const struct tp_params *p) +{ + unsigned int m, pstructs, tids = t3_mc5_size(&adap->mc5); + unsigned int timers = 0, timers_shift = 22; + + if (adap->params.rev > 0) { + if (tids <= 16 * 1024) { + timers = 1; + timers_shift = 16; + } else if (tids <= 64 * 1024) { + timers = 2; + timers_shift = 18; + } else if (tids <= 256 * 1024) { + timers = 3; + timers_shift = 20; + } + } + + t3_write_reg(adap, A_TP_PMM_SIZE, + p->chan_rx_size | (p->chan_tx_size >> 16)); + + t3_write_reg(adap, A_TP_PMM_TX_BASE, 0); + t3_write_reg(adap, A_TP_PMM_TX_PAGE_SIZE, p->tx_pg_size); + t3_write_reg(adap, A_TP_PMM_TX_MAX_PAGE, p->tx_num_pgs); + t3_set_reg_field(adap, A_TP_PARA_REG3, V_TXDATAACKIDX(M_TXDATAACKIDX), + V_TXDATAACKIDX(fls(p->tx_pg_size) - 12)); + + t3_write_reg(adap, A_TP_PMM_RX_BASE, 0); + t3_write_reg(adap, A_TP_PMM_RX_PAGE_SIZE, p->rx_pg_size); + t3_write_reg(adap, A_TP_PMM_RX_MAX_PAGE, p->rx_num_pgs); + + pstructs = p->rx_num_pgs + p->tx_num_pgs; + /* Add a bit of headroom and make multiple of 24 */ + pstructs += 48; + pstructs -= pstructs % 24; + t3_write_reg(adap, A_TP_CMM_MM_MAX_PSTRUCT, pstructs); + + m = tids * TCB_SIZE; + mem_region(adap, m, (64 << 10) * 64, SG_EGR_CNTX_BADDR); + mem_region(adap, m, (64 << 10) * 64, SG_CQ_CONTEXT_BADDR); + t3_write_reg(adap, A_TP_CMM_TIMER_BASE, V_CMTIMERMAXNUM(timers) | m); + m += ((p->ntimer_qs - 1) << timers_shift) + (1 << 22); + mem_region(adap, m, pstructs * 64, TP_CMM_MM_BASE); + mem_region(adap, m, 64 * (pstructs / 24), TP_CMM_MM_PS_FLST_BASE); + mem_region(adap, m, 64 * (p->rx_num_pgs / 24), TP_CMM_MM_RX_FLST_BASE); + mem_region(adap, m, 64 * (p->tx_num_pgs / 24), TP_CMM_MM_TX_FLST_BASE); + + m = (m + 4095) & ~0xfff; + t3_write_reg(adap, A_CIM_SDRAM_BASE_ADDR, m); + t3_write_reg(adap, A_CIM_SDRAM_ADDR_SIZE, p->cm_size - m); + + tids = (p->cm_size - m - (3 << 20)) / 3072 - 32; + m = t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers - + adap->params.mc5.nfilters - adap->params.mc5.nroutes; + if (tids < m) + adap->params.mc5.nservers += m - tids; +} + +static inline void tp_wr_indirect(struct adapter *adap, unsigned int addr, + u32 val) +{ + t3_write_reg(adap, A_TP_PIO_ADDR, addr); + t3_write_reg(adap, A_TP_PIO_DATA, val); +} + +static void tp_config(struct adapter *adap, const struct tp_params *p) +{ + t3_write_reg(adap, A_TP_GLOBAL_CONFIG, F_TXPACINGENABLE | F_PATHMTU | + F_IPCHECKSUMOFFLOAD | F_UDPCHECKSUMOFFLOAD | + F_TCPCHECKSUMOFFLOAD | V_IPTTL(64)); + t3_write_reg(adap, A_TP_TCP_OPTIONS, V_MTUDEFAULT(576) | + F_MTUENABLE | V_WINDOWSCALEMODE(1) | + V_TIMESTAMPSMODE(1) | V_SACKMODE(1) | V_SACKRX(1)); + t3_write_reg(adap, A_TP_DACK_CONFIG, V_AUTOSTATE3(1) | + V_AUTOSTATE2(1) | V_AUTOSTATE1(0) | + V_BYTETHRESHOLD(26880) | V_MSSTHRESHOLD(2) | + F_AUTOCAREFUL | F_AUTOENABLE | V_DACK_MODE(1)); + t3_set_reg_field(adap, A_TP_IN_CONFIG, F_RXFBARBPRIO | F_TXFBARBPRIO, + 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, 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); + t3_set_reg_field(adap, A_TP_PC_CONFIG2, F_CHDRAFULL, + F_ENABLEIPV6RSS | F_ENABLENONOFDTNLSYN | + F_ENABLEARPMISS | F_DISBLEDAPARBIT0); + 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); + t3_set_reg_field(adap, A_TP_PARA_REG3, F_TXPACEAUTO, + F_TXPACEAUTO); + 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); + } else + t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEFIXED); + + if (adap->params.rev == T3_REV_C) + t3_set_reg_field(adap, A_TP_PC_CONFIG, + V_TABLELATENCYDELTA(M_TABLELATENCYDELTA), + V_TABLELATENCYDELTA(4)); + + 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, 0xf2200000); +} + +/* Desired TP timer resolution in usec */ +#define TP_TMR_RES 50 + +/* TCP timer values in ms */ +#define TP_DACK_TIMER 50 +#define TP_RTO_MIN 250 + +/** + * tp_set_timers - set TP timing parameters + * @adap: the adapter to set + * @core_clk: the core clock frequency in Hz + * + * Set TP's timing parameters, such as the various timer resolutions and + * the TCP timer values. + */ +static void tp_set_timers(struct adapter *adap, unsigned int core_clk) +{ + unsigned int tre = fls(core_clk / (1000000 / TP_TMR_RES)) - 1; + unsigned int dack_re = fls(core_clk / 5000) - 1; /* 200us */ + unsigned int tstamp_re = fls(core_clk / 1000); /* 1ms, at least */ + unsigned int tps = core_clk >> tre; + + t3_write_reg(adap, A_TP_TIMER_RESOLUTION, V_TIMERRESOLUTION(tre) | + V_DELAYEDACKRESOLUTION(dack_re) | + V_TIMESTAMPRESOLUTION(tstamp_re)); + t3_write_reg(adap, A_TP_DACK_TIMER, + (core_clk >> dack_re) / (1000 / TP_DACK_TIMER)); + t3_write_reg(adap, A_TP_TCP_BACKOFF_REG0, 0x3020100); + t3_write_reg(adap, A_TP_TCP_BACKOFF_REG1, 0x7060504); + t3_write_reg(adap, A_TP_TCP_BACKOFF_REG2, 0xb0a0908); + t3_write_reg(adap, A_TP_TCP_BACKOFF_REG3, 0xf0e0d0c); + t3_write_reg(adap, A_TP_SHIFT_CNT, V_SYNSHIFTMAX(6) | + V_RXTSHIFTMAXR1(4) | V_RXTSHIFTMAXR2(15) | + V_PERSHIFTBACKOFFMAX(8) | V_PERSHIFTMAX(8) | + V_KEEPALIVEMAX(9)); + +#define SECONDS * tps + + t3_write_reg(adap, A_TP_MSL, adap->params.rev > 0 ? 0 : 2 SECONDS); + t3_write_reg(adap, A_TP_RXT_MIN, tps / (1000 / TP_RTO_MIN)); + t3_write_reg(adap, A_TP_RXT_MAX, 64 SECONDS); + t3_write_reg(adap, A_TP_PERS_MIN, 5 SECONDS); + t3_write_reg(adap, A_TP_PERS_MAX, 64 SECONDS); + t3_write_reg(adap, A_TP_KEEP_IDLE, 7200 SECONDS); + t3_write_reg(adap, A_TP_KEEP_INTVL, 75 SECONDS); + t3_write_reg(adap, A_TP_INIT_SRTT, 3 SECONDS); + t3_write_reg(adap, A_TP_FINWAIT2_TIMER, 600 SECONDS); + +#undef SECONDS +} + +/** + * t3_tp_set_coalescing_size - set receive coalescing size + * @adap: the adapter + * @size: the receive coalescing size + * @psh: whether a set PSH bit should deliver coalesced data + * + * Set the receive coalescing size and PSH bit handling. + */ +static int t3_tp_set_coalescing_size(struct adapter *adap, + unsigned int size, int psh) +{ + u32 val; + + if (size > MAX_RX_COALESCING_LEN) + return -EINVAL; + + val = t3_read_reg(adap, A_TP_PARA_REG3); + val &= ~(F_RXCOALESCEENABLE | F_RXCOALESCEPSHEN); + + if (size) { + 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)); + } + t3_write_reg(adap, A_TP_PARA_REG3, val); + return 0; +} + +/** + * t3_tp_set_max_rxsize - set the max receive size + * @adap: the adapter + * @size: the max receive size + * + * Set TP's max receive size. This is the limit that applies when + * receive coalescing is disabled. + */ +static void t3_tp_set_max_rxsize(struct adapter *adap, unsigned int size) +{ + t3_write_reg(adap, A_TP_PARA_REG7, + V_PMMAXXFERLEN0(size) | V_PMMAXXFERLEN1(size)); +} + +static void init_mtus(unsigned short mtus[]) +{ + /* + * See draft-mathis-plpmtud-00.txt for the values. The min is 88 so + * it can accommodate max size TCP/IP headers when SACK and timestamps + * are enabled and still have at least 8 bytes of payload. + */ + mtus[0] = 88; + mtus[1] = 88; + mtus[2] = 256; + mtus[3] = 512; + mtus[4] = 576; + mtus[5] = 1024; + mtus[6] = 1280; + mtus[7] = 1492; + mtus[8] = 1500; + mtus[9] = 2002; + mtus[10] = 2048; + mtus[11] = 4096; + mtus[12] = 4352; + mtus[13] = 8192; + mtus[14] = 9000; + mtus[15] = 9600; +} + +/* + * Initial congestion control parameters. + */ +static void init_cong_ctrl(unsigned short *a, unsigned short *b) +{ + a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1; + a[9] = 2; + a[10] = 3; + a[11] = 4; + a[12] = 5; + a[13] = 6; + a[14] = 7; + a[15] = 8; + a[16] = 9; + a[17] = 10; + a[18] = 14; + a[19] = 17; + a[20] = 21; + a[21] = 25; + a[22] = 30; + a[23] = 35; + a[24] = 45; + a[25] = 60; + a[26] = 80; + a[27] = 100; + a[28] = 200; + a[29] = 300; + a[30] = 400; + a[31] = 500; + + b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0; + b[9] = b[10] = 1; + b[11] = b[12] = 2; + b[13] = b[14] = b[15] = b[16] = 3; + b[17] = b[18] = b[19] = b[20] = b[21] = 4; + b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5; + b[28] = b[29] = 6; + b[30] = b[31] = 7; +} + +/* The minimum additive increment value for the congestion control table */ +#define CC_MIN_INCR 2U + +/** + * t3_load_mtus - write the MTU and congestion control HW tables + * @adap: the adapter + * @mtus: the unrestricted values for the MTU table + * @alphs: the values for the congestion control alpha parameter + * @beta: the values for the congestion control beta parameter + * @mtu_cap: the maximum permitted effective MTU + * + * Write the MTU table with the supplied MTUs capping each at &mtu_cap. + * Update the high-speed congestion control table with the supplied alpha, + * beta, and MTUs. + */ +void t3_load_mtus(struct adapter *adap, unsigned short mtus[NMTUS], + unsigned short alpha[NCCTRL_WIN], + unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap) +{ + static const unsigned int avg_pkts[NCCTRL_WIN] = { + 2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640, + 896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480, + 28672, 40960, 57344, 81920, 114688, 163840, 229376 + }; + + unsigned int i, w; + + for (i = 0; i < NMTUS; ++i) { + unsigned int mtu = min(mtus[i], mtu_cap); + unsigned int log2 = fls(mtu); + + if (!(mtu & ((1 << log2) >> 2))) /* round */ + log2--; + t3_write_reg(adap, A_TP_MTU_TABLE, + (i << 24) | (log2 << 16) | mtu); + + for (w = 0; w < NCCTRL_WIN; ++w) { + unsigned int inc; + + inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w], + CC_MIN_INCR); + + t3_write_reg(adap, A_TP_CCTRL_TABLE, (i << 21) | + (w << 16) | (beta[w] << 13) | inc); + } + } +} + +/** + * t3_tp_get_mib_stats - read TP's MIB counters + * @adap: the adapter + * @tps: holds the returned counter values + * + * Returns the values of TP's MIB counters. + */ +void t3_tp_get_mib_stats(struct adapter *adap, struct tp_mib_stats *tps) +{ + t3_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_RDATA, (u32 *) tps, + sizeof(*tps) / sizeof(u32), 0); +} + +#define ulp_region(adap, name, start, len) \ + t3_write_reg((adap), A_ULPRX_ ## name ## _LLIMIT, (start)); \ + t3_write_reg((adap), A_ULPRX_ ## name ## _ULIMIT, \ + (start) + (len) - 1); \ + start += len + +#define ulptx_region(adap, name, start, len) \ + t3_write_reg((adap), A_ULPTX_ ## name ## _LLIMIT, (start)); \ + t3_write_reg((adap), A_ULPTX_ ## name ## _ULIMIT, \ + (start) + (len) - 1) + +static void ulp_config(struct adapter *adap, const struct tp_params *p) +{ + unsigned int m = p->chan_rx_size; + + ulp_region(adap, ISCSI, m, p->chan_rx_size / 8); + ulp_region(adap, TDDP, m, p->chan_rx_size / 8); + ulptx_region(adap, TPT, m, p->chan_rx_size / 4); + ulp_region(adap, STAG, m, p->chan_rx_size / 4); + ulp_region(adap, RQ, m, p->chan_rx_size / 4); + ulptx_region(adap, PBL, m, p->chan_rx_size / 4); + 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(struct adapter *adap, const u8 *data) +{ + int i; + const __be32 *buf = (const __be32 *)data; + + for (i = 0; i < PROTO_SRAM_LINES; i++) { + t3_write_reg(adap, A_TP_EMBED_OP_FIELD5, be32_to_cpu(*buf++)); + t3_write_reg(adap, A_TP_EMBED_OP_FIELD4, be32_to_cpu(*buf++)); + t3_write_reg(adap, A_TP_EMBED_OP_FIELD3, be32_to_cpu(*buf++)); + t3_write_reg(adap, A_TP_EMBED_OP_FIELD2, be32_to_cpu(*buf++)); + t3_write_reg(adap, A_TP_EMBED_OP_FIELD1, be32_to_cpu(*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; + } + t3_write_reg(adap, A_TP_EMBED_OP_FIELD0, 0); + + return 0; +} + +void t3_config_trace_filter(struct adapter *adapter, + const struct trace_params *tp, int filter_index, + int invert, int enable) +{ + u32 addr, key[4], mask[4]; + + key[0] = tp->sport | (tp->sip << 16); + key[1] = (tp->sip >> 16) | (tp->dport << 16); + key[2] = tp->dip; + key[3] = tp->proto | (tp->vlan << 8) | (tp->intf << 20); + + mask[0] = tp->sport_mask | (tp->sip_mask << 16); + mask[1] = (tp->sip_mask >> 16) | (tp->dport_mask << 16); + mask[2] = tp->dip_mask; + mask[3] = tp->proto_mask | (tp->vlan_mask << 8) | (tp->intf_mask << 20); + + if (invert) + key[3] |= (1 << 29); + if (enable) + key[3] |= (1 << 28); + + addr = filter_index ? A_TP_RX_TRC_KEY0 : A_TP_TX_TRC_KEY0; + tp_wr_indirect(adapter, addr++, key[0]); + tp_wr_indirect(adapter, addr++, mask[0]); + tp_wr_indirect(adapter, addr++, key[1]); + tp_wr_indirect(adapter, addr++, mask[1]); + tp_wr_indirect(adapter, addr++, key[2]); + tp_wr_indirect(adapter, addr++, mask[2]); + tp_wr_indirect(adapter, addr++, key[3]); + tp_wr_indirect(adapter, addr, mask[3]); + t3_read_reg(adapter, A_TP_PIO_DATA); +} + +/** + * t3_config_sched - configure a HW traffic scheduler + * @adap: the adapter + * @kbps: target rate in Kbps + * @sched: the scheduler index + * + * Configure a HW scheduler for the target rate + */ +int t3_config_sched(struct adapter *adap, unsigned int kbps, int sched) +{ + unsigned int v, tps, cpt, bpt, delta, mindelta = ~0; + unsigned int clk = adap->params.vpd.cclk * 1000; + unsigned int selected_cpt = 0, selected_bpt = 0; + + if (kbps > 0) { + kbps *= 125; /* -> bytes */ + for (cpt = 1; cpt <= 255; cpt++) { + tps = clk / cpt; + bpt = (kbps + tps / 2) / tps; + if (bpt > 0 && bpt <= 255) { + v = bpt * tps; + delta = v >= kbps ? v - kbps : kbps - v; + if (delta <= mindelta) { + mindelta = delta; + selected_cpt = cpt; + selected_bpt = bpt; + } + } else if (selected_cpt) + break; + } + if (!selected_cpt) + return -EINVAL; + } + t3_write_reg(adap, A_TP_TM_PIO_ADDR, + A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2); + v = t3_read_reg(adap, A_TP_TM_PIO_DATA); + if (sched & 1) + v = (v & 0xffff) | (selected_cpt << 16) | (selected_bpt << 24); + else + v = (v & 0xffff0000) | selected_cpt | (selected_bpt << 8); + t3_write_reg(adap, A_TP_TM_PIO_DATA, v); + return 0; +} + +static int tp_init(struct adapter *adap, const struct tp_params *p) +{ + int busy = 0; + + tp_config(adap, p); + t3_set_vlan_accel(adap, 3, 0); + + if (is_offload(adap)) { + tp_set_timers(adap, adap->params.vpd.cclk * 1000); + t3_write_reg(adap, A_TP_RESET, F_FLSTINITENABLE); + busy = t3_wait_op_done(adap, A_TP_RESET, F_FLSTINITENABLE, + 0, 1000, 5); + if (busy) + CH_ERR(adap, "TP initialization timed out\n"); + } + + if (!busy) + t3_write_reg(adap, A_TP_RESET, F_TPRESET); + return busy; +} + +/* + * Perform the bits of HW initialization that are dependent on the Tx + * channels being used. + */ +static void chan_init_hw(struct adapter *adap, unsigned int chan_map) +{ + int i; + + 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_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, + V_D1_WEIGHT(16) | V_D0_WEIGHT(16)); + t3_write_reg(adap, A_MPS_CFG, F_TPTXPORT0EN | F_TPTXPORT1EN | + F_TPRXPORTEN | F_PORT0ACTIVE | F_PORT1ACTIVE | + F_ENFORCEPKT); + t3_write_reg(adap, A_PM1_TX_CFG, 0x80008000); + t3_set_reg_field(adap, A_TP_PC_CONFIG, 0, F_TXTOSQUEUEMAPMODE); + t3_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP, + V_TX_MOD_QUEUE_REQ_MAP(0xaa)); + for (i = 0; i < 16; i++) + t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, + (i << 16) | 0x1010); + } +} + +static int calibrate_xgm(struct adapter *adapter) +{ + if (uses_xaui(adapter)) { + unsigned int v, i; + + for (i = 0; i < 5; ++i) { + t3_write_reg(adapter, A_XGM_XAUI_IMP, 0); + t3_read_reg(adapter, A_XGM_XAUI_IMP); + 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, + V_XAUIIMP(G_CALIMP(v) >> 2)); + return 0; + } + } + CH_ERR(adapter, "MAC calibration failed\n"); + return -1; + } else { + t3_write_reg(adapter, A_XGM_RGMII_IMP, + V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3)); + t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE, + F_XGM_IMPSETUPDATE); + } + return 0; +} + +static void calibrate_xgm_t3b(struct adapter *adapter) +{ + if (!uses_xaui(adapter)) { + t3_write_reg(adapter, A_XGM_RGMII_IMP, F_CALRESET | + F_CALUPDATE | V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3)); + t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALRESET, 0); + t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0, + F_XGM_IMPSETUPDATE); + t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE, + 0); + t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALUPDATE, 0); + t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0, F_CALUPDATE); + } +} + +struct mc7_timing_params { + unsigned char ActToPreDly; + unsigned char ActToRdWrDly; + unsigned char PreCyc; + unsigned char RefCyc[5]; + unsigned char BkCyc; + unsigned char WrToRdDly; + unsigned char RdToWrDly; +}; + +/* + * Write a value to a register and check that the write completed. These + * writes normally complete in a cycle or two, so one read should suffice. + * The very first read exists to flush the posted write to the device. + */ +static int wrreg_wait(struct adapter *adapter, unsigned int addr, u32 val) +{ + t3_write_reg(adapter, addr, val); + t3_read_reg(adapter, addr); /* flush */ + if (!(t3_read_reg(adapter, addr) & F_BUSY)) + return 0; + CH_ERR(adapter, "write to MC7 register 0x%x timed out\n", addr); + return -EIO; +} + +static int mc7_init(struct mc7 *mc7, unsigned int mc7_clock, int mem_type) +{ + static const unsigned int mc7_mode[] = { + 0x632, 0x642, 0x652, 0x432, 0x442 + }; + static const struct mc7_timing_params mc7_timings[] = { + {12, 3, 4, {20, 28, 34, 52, 0}, 15, 6, 4}, + {12, 4, 5, {20, 28, 34, 52, 0}, 16, 7, 4}, + {12, 5, 6, {20, 28, 34, 52, 0}, 17, 8, 4}, + {9, 3, 4, {15, 21, 26, 39, 0}, 12, 6, 4}, + {9, 4, 5, {15, 21, 26, 39, 0}, 13, 7, 4} + }; + + u32 val; + unsigned int width, density, slow, attempts; + struct adapter *adapter = mc7->adapter; + const struct mc7_timing_params *p = &mc7_timings[mem_type]; + + if (!mc7->size) + return 0; + + val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); + slow = val & F_SLOW; + width = G_WIDTH(val); + density = G_DEN(val); + + t3_write_reg(adapter, mc7->offset + A_MC7_CFG, val | F_IFEN); + val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); /* flush */ + msleep(1); + + if (!slow) { + t3_write_reg(adapter, mc7->offset + A_MC7_CAL, F_SGL_CAL_EN); + t3_read_reg(adapter, mc7->offset + A_MC7_CAL); + 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", + mc7->name); + goto out_fail; + } + } + + t3_write_reg(adapter, mc7->offset + A_MC7_PARM, + V_ACTTOPREDLY(p->ActToPreDly) | + V_ACTTORDWRDLY(p->ActToRdWrDly) | V_PRECYC(p->PreCyc) | + V_REFCYC(p->RefCyc[density]) | V_BKCYC(p->BkCyc) | + V_WRTORDDLY(p->WrToRdDly) | V_RDTOWRDLY(p->RdToWrDly)); + + t3_write_reg(adapter, mc7->offset + A_MC7_CFG, + val | F_CLKEN | F_TERM150); + t3_read_reg(adapter, mc7->offset + A_MC7_CFG); /* flush */ + + if (!slow) + t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLENB, + F_DLLENB); + udelay(1); + + val = slow ? 3 : 6; + if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) || + wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE2, 0) || + wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE3, 0) || + wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val)) + goto out_fail; + + if (!slow) { + t3_write_reg(adapter, mc7->offset + A_MC7_MODE, 0x100); + t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLRST, 0); + udelay(5); + } + + if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) || + wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) || + wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) || + wrreg_wait(adapter, mc7->offset + A_MC7_MODE, + mc7_mode[mem_type]) || + wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val | 0x380) || + wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val)) + goto out_fail; + + /* clock value is in KHz */ + mc7_clock = mc7_clock * 7812 + mc7_clock / 2; /* ns */ + mc7_clock /= 1000000; /* KHz->MHz, ns->us */ + + t3_write_reg(adapter, mc7->offset + A_MC7_REF, + F_PERREFEN | V_PREREFDIV(mc7_clock)); + t3_read_reg(adapter, mc7->offset + A_MC7_REF); /* flush */ + + t3_write_reg(adapter, mc7->offset + A_MC7_ECC, F_ECCGENEN | F_ECCCHKEN); + t3_write_reg(adapter, mc7->offset + A_MC7_BIST_DATA, 0); + t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_BEG, 0); + t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_END, + (mc7->size << width) - 1); + t3_write_reg(adapter, mc7->offset + A_MC7_BIST_OP, V_OP(1)); + t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP); /* flush */ + + attempts = 50; + do { + msleep(250); + val = t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP); + } while ((val & F_BUSY) && --attempts); + if (val & F_BUSY) { + CH_ERR(adapter, "%s MC7 BIST timed out\n", mc7->name); + goto out_fail; + } + + /* Enable normal memory accesses. */ + t3_set_reg_field(adapter, mc7->offset + A_MC7_CFG, 0, F_RDY); + return 0; + +out_fail: + return -1; +} + +static void config_pcie(struct adapter *adap) +{ + static const u16 ack_lat[4][6] = { + {237, 416, 559, 1071, 2095, 4143}, + {128, 217, 289, 545, 1057, 2081}, + {73, 118, 154, 282, 538, 1050}, + {67, 107, 86, 150, 278, 534} + }; + static const u16 rpl_tmr[4][6] = { + {711, 1248, 1677, 3213, 6285, 12429}, + {384, 651, 867, 1635, 3171, 6243}, + {219, 354, 462, 846, 1614, 3150}, + {201, 321, 258, 450, 834, 1602} + }; + + u16 val, devid; + unsigned int log2_width, pldsize; + unsigned int fst_trn_rx, fst_trn_tx, acklat, rpllmt; + + pci_read_config_word(adap->pdev, + adap->pdev->pcie_cap + PCI_EXP_DEVCTL, + &val); + pldsize = (val & PCI_EXP_DEVCTL_PAYLOAD) >> 5; + + pci_read_config_word(adap->pdev, 0x2, &devid); + if (devid == 0x37) { + pci_write_config_word(adap->pdev, + adap->pdev->pcie_cap + PCI_EXP_DEVCTL, + val & ~PCI_EXP_DEVCTL_READRQ & + ~PCI_EXP_DEVCTL_PAYLOAD); + pldsize = 0; + } + + pci_read_config_word(adap->pdev, adap->pdev->pcie_cap + PCI_EXP_LNKCTL, + &val); + + fst_trn_tx = G_NUMFSTTRNSEQ(t3_read_reg(adap, A_PCIE_PEX_CTRL0)); + fst_trn_rx = adap->params.rev == 0 ? fst_trn_tx : + G_NUMFSTTRNSEQRX(t3_read_reg(adap, A_PCIE_MODE)); + log2_width = fls(adap->params.pci.width) - 1; + acklat = ack_lat[log2_width][pldsize]; + if (val & 1) /* check LOsEnable */ + acklat += fst_trn_tx * 4; + rpllmt = rpl_tmr[log2_width][pldsize] + fst_trn_rx * 4; + + if (adap->params.rev == 0) + t3_set_reg_field(adap, A_PCIE_PEX_CTRL1, + V_T3A_ACKLAT(M_T3A_ACKLAT), + V_T3A_ACKLAT(acklat)); + else + t3_set_reg_field(adap, A_PCIE_PEX_CTRL1, V_ACKLAT(M_ACKLAT), + V_ACKLAT(acklat)); + + t3_set_reg_field(adap, A_PCIE_PEX_CTRL0, V_REPLAYLMT(M_REPLAYLMT), + V_REPLAYLMT(rpllmt)); + + t3_write_reg(adap, A_PCIE_PEX_ERR, 0xffffffff); + t3_set_reg_field(adap, A_PCIE_CFG, 0, + F_ENABLELINKDWNDRST | F_ENABLELINKDOWNRST | + F_PCIE_DMASTOPEN | F_PCIE_CLIDECEN); +} + +/* + * Initialize and configure T3 HW modules. This performs the + * initialization steps that need to be done once after a card is reset. + * MAC and PHY initialization is handled separarely whenever a port is enabled. + * + * fw_params are passed to FW and their value is platform dependent. Only the + * top 8 bits are available for use, the rest must be 0. + */ +int t3_init_hw(struct adapter *adapter, u32 fw_params) +{ + int err = -EIO, attempts, i; + const struct vpd_params *vpd = &adapter->params.vpd; + + if (adapter->params.rev > 0) + calibrate_xgm_t3b(adapter); + else if (calibrate_xgm(adapter)) + goto out_err; + + if (vpd->mclk) { + partition_mem(adapter, &adapter->params.tp); + + if (mc7_init(&adapter->pmrx, vpd->mclk, vpd->mem_timing) || + mc7_init(&adapter->pmtx, vpd->mclk, vpd->mem_timing) || + mc7_init(&adapter->cm, vpd->mclk, vpd->mem_timing) || + t3_mc5_init(&adapter->mc5, adapter->params.mc5.nservers, + adapter->params.mc5.nfilters, + adapter->params.mc5.nroutes)) + goto out_err; + + for (i = 0; i < 32; i++) + if (clear_sge_ctxt(adapter, i, F_CQ)) + goto out_err; + } + + if (tp_init(adapter, &adapter->params.tp)) + goto out_err; + + t3_tp_set_coalescing_size(adapter, + min(adapter->params.sge.max_pkt_size, + MAX_RX_COALESCING_LEN), 1); + t3_tp_set_max_rxsize(adapter, + min(adapter->params.sge.max_pkt_size, 16384U)); + ulp_config(adapter, &adapter->params.tp); + + if (is_pcie(adapter)) + config_pcie(adapter); + else + t3_set_reg_field(adapter, A_PCIX_CFG, 0, + F_DMASTOPEN | F_CLIDECEN); + + if (adapter->params.rev == T3_REV_C) + t3_set_reg_field(adapter, A_ULPTX_CONFIG, 0, + F_CFG_CQE_SOP_MASK); + + t3_write_reg(adapter, A_PM1_RX_CFG, 0xffffffff); + t3_write_reg(adapter, A_PM1_RX_MODE, 0); + t3_write_reg(adapter, A_PM1_TX_MODE, 0); + chan_init_hw(adapter, adapter->params.chan_map); + t3_sge_init(adapter, &adapter->params.sge); + t3_set_reg_field(adapter, A_PL_RST, 0, F_FATALPERREN); + + t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW, calc_gpio_intr(adapter)); + + t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, vpd->uclk | fw_params); + t3_write_reg(adapter, A_CIM_BOOT_CFG, + V_BOOTADDR(FW_FLASH_BOOT_ADDR >> 2)); + t3_read_reg(adapter, A_CIM_BOOT_CFG); /* flush */ + + attempts = 100; + do { /* wait for uP to initialize */ + msleep(20); + } while (t3_read_reg(adapter, A_CIM_HOST_ACC_DATA) && --attempts); + if (!attempts) { + CH_ERR(adapter, "uP initialization timed out\n"); + goto out_err; + } + + err = 0; +out_err: + return err; +} + +/** + * get_pci_mode - determine a card's PCI mode + * @adapter: the adapter + * @p: where to store the PCI settings + * + * Determines a card's PCI mode and associated parameters, such as speed + * and width. + */ +static void get_pci_mode(struct adapter *adapter, struct pci_params *p) +{ + static unsigned short speed_map[] = { 33, 66, 100, 133 }; + u32 pci_mode, pcie_cap; + + pcie_cap = pci_pcie_cap(adapter->pdev); + if (pcie_cap) { + u16 val; + + p->variant = PCI_VARIANT_PCIE; + pci_read_config_word(adapter->pdev, pcie_cap + PCI_EXP_LNKSTA, + &val); + p->width = (val >> 4) & 0x3f; + return; + } + + pci_mode = t3_read_reg(adapter, A_PCIX_MODE); + p->speed = speed_map[G_PCLKRANGE(pci_mode)]; + p->width = (pci_mode & F_64BIT) ? 64 : 32; + pci_mode = G_PCIXINITPAT(pci_mode); + if (pci_mode == 0) + p->variant = PCI_VARIANT_PCI; + else if (pci_mode < 4) + p->variant = PCI_VARIANT_PCIX_MODE1_PARITY; + else if (pci_mode < 8) + p->variant = PCI_VARIANT_PCIX_MODE1_ECC; + else + p->variant = PCI_VARIANT_PCIX_266_MODE2; +} + +/** + * init_link_config - initialize a link's SW state + * @lc: structure holding the link state + * @ai: information about the current card + * + * Initializes the SW state maintained for each link, including the link's + * capabilities and default speed/duplex/flow-control/autonegotiation + * settings. + */ +static void init_link_config(struct link_config *lc, unsigned int caps) +{ + lc->supported = caps; + lc->requested_speed = lc->speed = SPEED_INVALID; + lc->requested_duplex = lc->duplex = DUPLEX_INVALID; + lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX; + if (lc->supported & SUPPORTED_Autoneg) { + lc->advertising = lc->supported; + lc->autoneg = AUTONEG_ENABLE; + lc->requested_fc |= PAUSE_AUTONEG; + } else { + lc->advertising = 0; + lc->autoneg = AUTONEG_DISABLE; + } +} + +/** + * mc7_calc_size - calculate MC7 memory size + * @cfg: the MC7 configuration + * + * Calculates the size of an MC7 memory in bytes from the value of its + * configuration register. + */ +static unsigned int mc7_calc_size(u32 cfg) +{ + unsigned int width = G_WIDTH(cfg); + unsigned int banks = !!(cfg & F_BKS) + 1; + unsigned int org = !!(cfg & F_ORG) + 1; + unsigned int density = G_DEN(cfg); + unsigned int MBs = ((256 << density) * banks) / (org << width); + + return MBs << 20; +} + +static void mc7_prep(struct adapter *adapter, struct mc7 *mc7, + unsigned int base_addr, const char *name) +{ + u32 cfg; + + mc7->adapter = adapter; + mc7->name = name; + mc7->offset = base_addr - MC7_PMRX_BASE_ADDR; + cfg = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); + mc7->size = G_DEN(cfg) == M_DEN ? 0 : mc7_calc_size(cfg); + mc7->width = G_WIDTH(cfg); +} + +static void mac_prep(struct cmac *mac, struct adapter *adapter, int index) +{ + u16 devid; + + mac->adapter = adapter; + pci_read_config_word(adapter->pdev, 0x2, &devid); + + if (devid == 0x37 && !adapter->params.vpd.xauicfg[1]) + index = 0; + 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, + is_10G(adapter) ? 0x2901c04 : 0x2301c04); + t3_set_reg_field(adapter, A_XGM_PORT_CFG + mac->offset, + F_ENRGMII, 0); + } +} + +static void early_hw_init(struct adapter *adapter, + const struct adapter_info *ai) +{ + u32 val = V_PORTSPEED(is_10G(adapter) ? 3 : 2); + + mi1_init(adapter, ai); + t3_write_reg(adapter, A_I2C_CFG, /* set for 80KHz */ + V_I2C_CLKDIV(adapter->params.vpd.cclk / 80 - 1)); + t3_write_reg(adapter, A_T3DBG_GPIO_EN, + ai->gpio_out | F_GPIO0_OEN | F_GPIO0_OUT_VAL); + t3_write_reg(adapter, A_MC5_DB_SERVER_INDEX, 0); + t3_write_reg(adapter, A_SG_OCO_BASE, V_BASE1(0xfff)); + + if (adapter->params.rev == 0 || !uses_xaui(adapter)) + val |= F_ENRGMII; + + /* Enable MAC clocks so we can access the registers */ + t3_write_reg(adapter, A_XGM_PORT_CFG, val); + t3_read_reg(adapter, A_XGM_PORT_CFG); + + val |= F_CLKDIVRESET_; + t3_write_reg(adapter, A_XGM_PORT_CFG, val); + t3_read_reg(adapter, A_XGM_PORT_CFG); + t3_write_reg(adapter, XGM_REG(A_XGM_PORT_CFG, 1), val); + t3_read_reg(adapter, A_XGM_PORT_CFG); +} + +/* + * Reset the adapter. + * Older PCIe cards lose their config space during reset, PCI-X + * ones don't. + */ +int t3_reset_adapter(struct adapter *adapter) +{ + int i, save_and_restore_pcie = + adapter->params.rev < T3_REV_B2 && is_pcie(adapter); + uint16_t devid = 0; + + if (save_and_restore_pcie) + pci_save_state(adapter->pdev); + t3_write_reg(adapter, A_PL_RST, F_CRSTWRM | F_CRSTWRMMODE); + + /* + * Delay. Give Some time to device to reset fully. + * XXX The delay time should be modified. + */ + for (i = 0; i < 10; i++) { + msleep(50); + pci_read_config_word(adapter->pdev, 0x00, &devid); + if (devid == 0x1425) + break; + } + + if (devid != 0x1425) + return -1; + + if (save_and_restore_pcie) + pci_restore_state(adapter->pdev); + return 0; +} + +static int init_parity(struct adapter *adap) +{ + int i, err, addr; + + if (t3_read_reg(adap, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + for (err = i = 0; !err && i < 16; i++) + err = clear_sge_ctxt(adap, i, F_EGRESS); + for (i = 0xfff0; !err && i <= 0xffff; i++) + err = clear_sge_ctxt(adap, i, F_EGRESS); + for (i = 0; !err && i < SGE_QSETS; i++) + err = clear_sge_ctxt(adap, i, F_RESPONSEQ); + if (err) + return err; + + t3_write_reg(adap, A_CIM_IBQ_DBG_DATA, 0); + for (i = 0; i < 4; i++) + for (addr = 0; addr <= M_IBQDBGADDR; addr++) { + t3_write_reg(adap, A_CIM_IBQ_DBG_CFG, F_IBQDBGEN | + F_IBQDBGWR | V_IBQDBGQID(i) | + V_IBQDBGADDR(addr)); + err = t3_wait_op_done(adap, A_CIM_IBQ_DBG_CFG, + F_IBQDBGBUSY, 0, 2, 1); + if (err) + return err; + } + return 0; +} + +/* + * Initialize adapter SW state for the various HW modules, set initial values + * for some adapter tunables, take PHYs out of reset, and initialize the MDIO + * interface. + */ +int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai, + int reset) +{ + int ret; + unsigned int i, j = -1; + + get_pci_mode(adapter, &adapter->params.pci); + + adapter->params.info = ai; + 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); + /* + * We used to only run the "adapter check task" once a second if + * we had PHYs which didn't support interrupts (we would check + * their link status once a second). Now we check other conditions + * in that routine which could potentially impose a very high + * interrupt load on the system. As such, we now always scan the + * adapter state once a second ... + */ + adapter->params.linkpoll_period = 10; + adapter->params.stats_update_period = is_10G(adapter) ? + MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10); + adapter->params.pci.vpd_cap_addr = + pci_find_capability(adapter->pdev, PCI_CAP_ID_VPD); + ret = get_vpd_params(adapter, &adapter->params.vpd); + if (ret < 0) + return ret; + + if (reset && t3_reset_adapter(adapter)) + return -1; + + t3_sge_prep(adapter, &adapter->params.sge); + + if (adapter->params.vpd.mclk) { + struct tp_params *p = &adapter->params.tp; + + mc7_prep(adapter, &adapter->pmrx, MC7_PMRX_BASE_ADDR, "PMRX"); + mc7_prep(adapter, &adapter->pmtx, MC7_PMTX_BASE_ADDR, "PMTX"); + mc7_prep(adapter, &adapter->cm, MC7_CM_BASE_ADDR, "CM"); + + 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); + p->chan_rx_size = p->pmrx_size / 2; /* only 1 Rx channel */ + p->chan_tx_size = p->pmtx_size / p->nchan; + p->rx_pg_size = 64 * 1024; + p->tx_pg_size = is_10G(adapter) ? 64 * 1024 : 16 * 1024; + p->rx_num_pgs = pm_num_pages(p->chan_rx_size, p->rx_pg_size); + 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; + } + + adapter->params.offload = t3_mc7_size(&adapter->pmrx) && + t3_mc7_size(&adapter->pmtx) && + t3_mc7_size(&adapter->cm); + + if (is_offload(adapter)) { + adapter->params.mc5.nservers = DEFAULT_NSERVERS; + adapter->params.mc5.nfilters = adapter->params.rev > 0 ? + DEFAULT_NFILTERS : 0; + adapter->params.mc5.nroutes = 0; + t3_mc5_prep(adapter, &adapter->mc5, MC5_MODE_144_BIT); + + init_mtus(adapter->params.mtus); + init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd); + } + + early_hw_init(adapter, ai); + ret = init_parity(adapter); + if (ret) + return ret; + + for_each_port(adapter, i) { + u8 hw_addr[6]; + const struct port_type_info *pti; + struct port_info *p = adap2pinfo(adapter, i); + + while (!adapter->params.vpd.port_type[++j]) + ; + + pti = &port_types[adapter->params.vpd.port_type[j]]; + if (!pti->phy_prep) { + CH_ALERT(adapter, "Invalid port type index %d\n", + adapter->params.vpd.port_type[j]); + return -EINVAL; + } + + p->phy.mdio.dev = adapter->port[i]; + ret = pti->phy_prep(&p->phy, adapter, ai->phy_base_addr + j, + ai->mdio_ops); + if (ret) + return ret; + mac_prep(&p->mac, adapter, j); + + /* + * The VPD EEPROM stores the base Ethernet address for the + * card. A port's address is derived from the base by adding + * the port's index to the base's low octet. + */ + memcpy(hw_addr, adapter->params.vpd.eth_base, 5); + hw_addr[5] = adapter->params.vpd.eth_base[5] + i; + + memcpy(adapter->port[i]->dev_addr, hw_addr, + ETH_ALEN); + memcpy(adapter->port[i]->perm_addr, hw_addr, + ETH_ALEN); + init_link_config(&p->link_config, p->phy.caps); + p->phy.ops->power_down(&p->phy, 1); + + /* + * If the PHY doesn't support interrupts for link status + * changes, schedule a scan of the adapter links at least + * once a second. + */ + if (!(p->phy.caps & SUPPORTED_IRQ) && + adapter->params.linkpoll_period > 10) + adapter->params.linkpoll_period = 10; + } + + return 0; +} + +void t3_led_ready(struct adapter *adapter) +{ + t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, + F_GPIO0_OUT_VAL); +} + +int t3_replay_prep_adapter(struct adapter *adapter) +{ + const struct adapter_info *ai = adapter->params.info; + unsigned int i, j = -1; + int ret; + + early_hw_init(adapter, ai); + ret = init_parity(adapter); + if (ret) + return ret; + + for_each_port(adapter, i) { + const struct port_type_info *pti; + struct port_info *p = adap2pinfo(adapter, i); + + while (!adapter->params.vpd.port_type[++j]) + ; + + pti = &port_types[adapter->params.vpd.port_type[j]]; + ret = pti->phy_prep(&p->phy, adapter, p->phy.mdio.prtad, NULL); + if (ret) + return ret; + p->phy.ops->power_down(&p->phy, 1); + } + +return 0; +} + diff --git a/drivers/net/ethernet/chelsio/cxgb3/t3cdev.h b/drivers/net/ethernet/chelsio/cxgb3/t3cdev.h new file mode 100644 index 000000000000..705713b56636 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb3/t3cdev.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2006-2008 Chelsio Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _T3CDEV_H_ +#define _T3CDEV_H_ + +#include +#include +#include +#include +#include +#include + +#define T3CNAMSIZ 16 + +struct cxgb3_client; + +enum t3ctype { + T3A = 0, + T3B, + T3C, +}; + +struct t3cdev { + char name[T3CNAMSIZ]; /* T3C device name */ + enum t3ctype type; + struct list_head ofld_dev_list; /* for list linking */ + struct net_device *lldev; /* LL dev associated with T3C messages */ + struct proc_dir_entry *proc_dir; /* root of proc dir for this T3C */ + int (*send)(struct t3cdev *dev, struct sk_buff *skb); + int (*recv)(struct t3cdev *dev, struct sk_buff **skb, int n); + int (*ctl)(struct t3cdev *dev, unsigned int req, void *data); + void (*neigh_update)(struct t3cdev *dev, struct neighbour *neigh); + void *priv; /* driver private data */ + void *l2opt; /* optional layer 2 data */ + void *l3opt; /* optional layer 3 data */ + void *l4opt; /* optional layer 4 data */ + void *ulp; /* ulp stuff */ + void *ulp_iscsi; /* ulp iscsi */ +}; + +#endif /* _T3CDEV_H_ */ diff --git a/drivers/net/ethernet/chelsio/cxgb3/version.h b/drivers/net/ethernet/chelsio/cxgb3/version.h new file mode 100644 index 000000000000..8bda06e366c8 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb3/version.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/* $Date: 2006/10/31 18:57:51 $ $RCSfile: version.h,v $ $Revision: 1.3 $ */ +#ifndef __CHELSIO_VERSION_H +#define __CHELSIO_VERSION_H +#define DRV_DESC "Chelsio T3 Network Driver" +#define DRV_NAME "cxgb3" +/* Driver version */ +#define DRV_VERSION "1.1.4-ko" + +/* Firmware version */ +#define FW_VERSION_MAJOR 7 +#define FW_VERSION_MINOR 10 +#define FW_VERSION_MICRO 0 +#endif /* __CHELSIO_VERSION_H */ diff --git a/drivers/net/ethernet/chelsio/cxgb3/vsc8211.c b/drivers/net/ethernet/chelsio/cxgb3/vsc8211.c new file mode 100644 index 000000000000..4f9a1c2724f4 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb3/vsc8211.c @@ -0,0 +1,416 @@ +/* + * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "common.h" + +/* VSC8211 PHY specific registers. */ +enum { + VSC8211_SIGDET_CTRL = 19, + VSC8211_EXT_CTRL = 23, + VSC8211_INTR_ENABLE = 25, + VSC8211_INTR_STATUS = 26, + VSC8211_LED_CTRL = 27, + VSC8211_AUX_CTRL_STAT = 28, + VSC8211_EXT_PAGE_AXS = 31, +}; + +enum { + VSC_INTR_RX_ERR = 1 << 0, + VSC_INTR_MS_ERR = 1 << 1, /* master/slave resolution error */ + VSC_INTR_CABLE = 1 << 2, /* cable impairment */ + VSC_INTR_FALSE_CARR = 1 << 3, /* false carrier */ + VSC_INTR_MEDIA_CHG = 1 << 4, /* AMS media change */ + VSC_INTR_RX_FIFO = 1 << 5, /* Rx FIFO over/underflow */ + VSC_INTR_TX_FIFO = 1 << 6, /* Tx FIFO over/underflow */ + VSC_INTR_DESCRAMBL = 1 << 7, /* descrambler lock-lost */ + VSC_INTR_SYMBOL_ERR = 1 << 8, /* symbol error */ + VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */ + VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */ + VSC_INTR_DPLX_CHG = 1 << 12, /* duplex change */ + VSC_INTR_LINK_CHG = 1 << 13, /* link change */ + VSC_INTR_SPD_CHG = 1 << 14, /* speed change */ + VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */ +}; + +enum { + VSC_CTRL_CLAUSE37_VIEW = 1 << 4, /* Switch to Clause 37 view */ + VSC_CTRL_MEDIA_MODE_HI = 0xf000 /* High part of media mode select */ +}; + +#define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \ + VSC_INTR_DPLX_CHG | VSC_INTR_SPD_CHG | \ + VSC_INTR_NEG_DONE) +#define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \ + VSC_INTR_ENABLE) + +/* PHY specific auxiliary control & status register fields */ +#define S_ACSR_ACTIPHY_TMR 0 +#define M_ACSR_ACTIPHY_TMR 0x3 +#define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR) + +#define S_ACSR_SPEED 3 +#define M_ACSR_SPEED 0x3 +#define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED) + +#define S_ACSR_DUPLEX 5 +#define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX) + +#define S_ACSR_ACTIPHY 6 +#define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY) + +/* + * Reset the PHY. This PHY completes reset immediately so we never wait. + */ +static int vsc8211_reset(struct cphy *cphy, int wait) +{ + return t3_phy_reset(cphy, MDIO_DEVAD_NONE, 0); +} + +static int vsc8211_intr_enable(struct cphy *cphy) +{ + return t3_mdio_write(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_ENABLE, + INTR_MASK); +} + +static int vsc8211_intr_disable(struct cphy *cphy) +{ + return t3_mdio_write(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_ENABLE, 0); +} + +static int vsc8211_intr_clear(struct cphy *cphy) +{ + u32 val; + + /* Clear PHY interrupts by reading the register. */ + return t3_mdio_read(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_STATUS, &val); +} + +static int vsc8211_autoneg_enable(struct cphy *cphy) +{ + return t3_mdio_change_bits(cphy, MDIO_DEVAD_NONE, MII_BMCR, + BMCR_PDOWN | BMCR_ISOLATE, + BMCR_ANENABLE | BMCR_ANRESTART); +} + +static int vsc8211_autoneg_restart(struct cphy *cphy) +{ + return t3_mdio_change_bits(cphy, MDIO_DEVAD_NONE, MII_BMCR, + BMCR_PDOWN | BMCR_ISOLATE, + BMCR_ANRESTART); +} + +static int vsc8211_get_link_status(struct cphy *cphy, int *link_ok, + int *speed, int *duplex, int *fc) +{ + unsigned int bmcr, status, lpa, adv; + int err, sp = -1, dplx = -1, pause = 0; + + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMCR, &bmcr); + if (!err) + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR, &status); + if (err) + return err; + + if (link_ok) { + /* + * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it + * once more to get the current link state. + */ + if (!(status & BMSR_LSTATUS)) + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR, + &status); + if (err) + return err; + *link_ok = (status & BMSR_LSTATUS) != 0; + } + if (!(bmcr & BMCR_ANENABLE)) { + dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; + if (bmcr & BMCR_SPEED1000) + sp = SPEED_1000; + else if (bmcr & BMCR_SPEED100) + sp = SPEED_100; + else + sp = SPEED_10; + } else if (status & BMSR_ANEGCOMPLETE) { + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, VSC8211_AUX_CTRL_STAT, + &status); + if (err) + return err; + + dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF; + sp = G_ACSR_SPEED(status); + if (sp == 0) + sp = SPEED_10; + else if (sp == 1) + sp = SPEED_100; + else + sp = SPEED_1000; + + if (fc && dplx == DUPLEX_FULL) { + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_LPA, + &lpa); + if (!err) + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, + MII_ADVERTISE, &adv); + if (err) + return err; + + if (lpa & adv & ADVERTISE_PAUSE_CAP) + pause = PAUSE_RX | PAUSE_TX; + else if ((lpa & ADVERTISE_PAUSE_CAP) && + (lpa & ADVERTISE_PAUSE_ASYM) && + (adv & ADVERTISE_PAUSE_ASYM)) + pause = PAUSE_TX; + else if ((lpa & ADVERTISE_PAUSE_ASYM) && + (adv & ADVERTISE_PAUSE_CAP)) + pause = PAUSE_RX; + } + } + if (speed) + *speed = sp; + if (duplex) + *duplex = dplx; + if (fc) + *fc = pause; + return 0; +} + +static int vsc8211_get_link_status_fiber(struct cphy *cphy, int *link_ok, + int *speed, int *duplex, int *fc) +{ + unsigned int bmcr, status, lpa, adv; + int err, sp = -1, dplx = -1, pause = 0; + + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMCR, &bmcr); + if (!err) + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR, &status); + if (err) + return err; + + if (link_ok) { + /* + * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it + * once more to get the current link state. + */ + if (!(status & BMSR_LSTATUS)) + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_BMSR, + &status); + if (err) + return err; + *link_ok = (status & BMSR_LSTATUS) != 0; + } + if (!(bmcr & BMCR_ANENABLE)) { + dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; + if (bmcr & BMCR_SPEED1000) + sp = SPEED_1000; + else if (bmcr & BMCR_SPEED100) + sp = SPEED_100; + else + sp = SPEED_10; + } else if (status & BMSR_ANEGCOMPLETE) { + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_LPA, &lpa); + if (!err) + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, MII_ADVERTISE, + &adv); + if (err) + return err; + + if (adv & lpa & ADVERTISE_1000XFULL) { + dplx = DUPLEX_FULL; + sp = SPEED_1000; + } else if (adv & lpa & ADVERTISE_1000XHALF) { + dplx = DUPLEX_HALF; + sp = SPEED_1000; + } + + if (fc && dplx == DUPLEX_FULL) { + if (lpa & adv & ADVERTISE_1000XPAUSE) + pause = PAUSE_RX | PAUSE_TX; + else if ((lpa & ADVERTISE_1000XPAUSE) && + (adv & lpa & ADVERTISE_1000XPSE_ASYM)) + pause = PAUSE_TX; + else if ((lpa & ADVERTISE_1000XPSE_ASYM) && + (adv & ADVERTISE_1000XPAUSE)) + pause = PAUSE_RX; + } + } + if (speed) + *speed = sp; + if (duplex) + *duplex = dplx; + if (fc) + *fc = pause; + return 0; +} + +#ifdef UNUSED +/* + * Enable/disable auto MDI/MDI-X in forced link speed mode. + */ +static int vsc8211_set_automdi(struct cphy *phy, int enable) +{ + int err; + + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 0x52b5); + if (err) + return err; + + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, 18, 0x12); + if (err) + return err; + + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, 17, enable ? 0x2803 : 0x3003); + if (err) + return err; + + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, 16, 0x87fa); + if (err) + return err; + + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 0); + if (err) + return err; + + return 0; +} + +int vsc8211_set_speed_duplex(struct cphy *phy, int speed, int duplex) +{ + int err; + + err = t3_set_phy_speed_duplex(phy, speed, duplex); + if (!err) + err = vsc8211_set_automdi(phy, 1); + return err; +} +#endif /* UNUSED */ + +static int vsc8211_power_down(struct cphy *cphy, int enable) +{ + return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN, + enable ? BMCR_PDOWN : 0); +} + +static int vsc8211_intr_handler(struct cphy *cphy) +{ + unsigned int cause; + int err, cphy_cause = 0; + + err = t3_mdio_read(cphy, MDIO_DEVAD_NONE, VSC8211_INTR_STATUS, &cause); + if (err) + return err; + + cause &= INTR_MASK; + if (cause & CFG_CHG_INTR_MASK) + cphy_cause |= cphy_cause_link_change; + if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO)) + cphy_cause |= cphy_cause_fifo_error; + return cphy_cause; +} + +static struct cphy_ops vsc8211_ops = { + .reset = vsc8211_reset, + .intr_enable = vsc8211_intr_enable, + .intr_disable = vsc8211_intr_disable, + .intr_clear = vsc8211_intr_clear, + .intr_handler = vsc8211_intr_handler, + .autoneg_enable = vsc8211_autoneg_enable, + .autoneg_restart = vsc8211_autoneg_restart, + .advertise = t3_phy_advertise, + .set_speed_duplex = t3_set_phy_speed_duplex, + .get_link_status = vsc8211_get_link_status, + .power_down = vsc8211_power_down, +}; + +static struct cphy_ops vsc8211_fiber_ops = { + .reset = vsc8211_reset, + .intr_enable = vsc8211_intr_enable, + .intr_disable = vsc8211_intr_disable, + .intr_clear = vsc8211_intr_clear, + .intr_handler = vsc8211_intr_handler, + .autoneg_enable = vsc8211_autoneg_enable, + .autoneg_restart = vsc8211_autoneg_restart, + .advertise = t3_phy_advertise_fiber, + .set_speed_duplex = t3_set_phy_speed_duplex, + .get_link_status = vsc8211_get_link_status_fiber, + .power_down = vsc8211_power_down, +}; + +int t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) +{ + int err; + unsigned int val; + + cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops, + SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII | + SUPPORTED_TP | SUPPORTED_IRQ, "10/100/1000BASE-T"); + msleep(20); /* PHY needs ~10ms to start responding to MDIO */ + + err = t3_mdio_read(phy, MDIO_DEVAD_NONE, VSC8211_EXT_CTRL, &val); + if (err) + return err; + if (val & VSC_CTRL_MEDIA_MODE_HI) { + /* copper interface, just need to configure the LEDs */ + return t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_LED_CTRL, + 0x100); + } + + phy->caps = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | + SUPPORTED_MII | SUPPORTED_FIBRE | SUPPORTED_IRQ; + phy->desc = "1000BASE-X"; + phy->ops = &vsc8211_fiber_ops; + + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 1); + if (err) + return err; + + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_SIGDET_CTRL, 1); + if (err) + return err; + + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_PAGE_AXS, 0); + if (err) + return err; + + err = t3_mdio_write(phy, MDIO_DEVAD_NONE, VSC8211_EXT_CTRL, + val | VSC_CTRL_CLAUSE37_VIEW); + if (err) + return err; + + err = vsc8211_reset(phy, 0); + if (err) + return err; + + udelay(5); /* delay after reset before next SMI */ + return 0; +} diff --git a/drivers/net/ethernet/chelsio/cxgb3/xgmac.c b/drivers/net/ethernet/chelsio/cxgb3/xgmac.c new file mode 100644 index 000000000000..3af19a550372 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb3/xgmac.c @@ -0,0 +1,657 @@ +/* + * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "common.h" +#include "regs.h" + +/* + * # of exact address filters. The first one is used for the station address, + * the rest are available for multicast addresses. + */ +#define EXACT_ADDR_FILTERS 8 + +static inline int macidx(const struct cmac *mac) +{ + return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR); +} + +static void xaui_serdes_reset(struct cmac *mac) +{ + static const unsigned int clear[] = { + F_PWRDN0 | F_PWRDN1, F_RESETPLL01, F_RESET0 | F_RESET1, + F_PWRDN2 | F_PWRDN3, F_RESETPLL23, F_RESET2 | F_RESET3 + }; + + int i; + struct adapter *adap = mac->adapter; + u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset; + + t3_write_reg(adap, ctrl, adap->params.vpd.xauicfg[macidx(mac)] | + F_RESET3 | F_RESET2 | F_RESET1 | F_RESET0 | + F_PWRDN3 | F_PWRDN2 | F_PWRDN1 | F_PWRDN0 | + F_RESETPLL23 | F_RESETPLL01); + t3_read_reg(adap, ctrl); + udelay(15); + + for (i = 0; i < ARRAY_SIZE(clear); i++) { + t3_set_reg_field(adap, ctrl, clear[i], 0); + udelay(15); + } +} + +void t3b_pcs_reset(struct cmac *mac) +{ + t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, + F_PCS_RESET_, 0); + udelay(20); + t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0, + F_PCS_RESET_); +} + +int t3_mac_reset(struct cmac *mac) +{ + static const struct addr_val_pair mac_reset_avp[] = { + {A_XGM_TX_CTRL, 0}, + {A_XGM_RX_CTRL, 0}, + {A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES | + F_RMFCS | F_ENJUMBO | F_ENHASHMCAST}, + {A_XGM_RX_HASH_LOW, 0}, + {A_XGM_RX_HASH_HIGH, 0}, + {A_XGM_RX_EXACT_MATCH_LOW_1, 0}, + {A_XGM_RX_EXACT_MATCH_LOW_2, 0}, + {A_XGM_RX_EXACT_MATCH_LOW_3, 0}, + {A_XGM_RX_EXACT_MATCH_LOW_4, 0}, + {A_XGM_RX_EXACT_MATCH_LOW_5, 0}, + {A_XGM_RX_EXACT_MATCH_LOW_6, 0}, + {A_XGM_RX_EXACT_MATCH_LOW_7, 0}, + {A_XGM_RX_EXACT_MATCH_LOW_8, 0}, + {A_XGM_STAT_CTRL, F_CLRSTATS} + }; + u32 val; + struct adapter *adap = mac->adapter; + unsigned int oft = mac->offset; + + t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_); + t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ + + t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft); + t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft, + F_RXSTRFRWRD | F_DISERRFRAMES, + uses_xaui(adap) ? 0 : F_RXSTRFRWRD); + t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0, F_UNDERUNFIX); + + if (uses_xaui(adap)) { + if (adap->params.rev == 0) { + t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0, + F_RXENABLE | F_TXENABLE); + if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft, + F_CMULOCK, 1, 5, 2)) { + CH_ERR(adap, + "MAC %d XAUI SERDES CMU lock failed\n", + macidx(mac)); + return -1; + } + t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0, + F_SERDESRESET_); + } else + xaui_serdes_reset(mac); + } + + t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + oft, + V_RXMAXFRAMERSIZE(M_RXMAXFRAMERSIZE), + V_RXMAXFRAMERSIZE(MAX_FRAME_SIZE) | F_RXENFRAMER); + val = F_MAC_RESET_ | F_XGMAC_STOP_EN; + + if (is_10G(adap)) + val |= F_PCS_RESET_; + else if (uses_xaui(adap)) + val |= F_PCS_RESET_ | F_XG2G_RESET_; + else + val |= F_RGMII_RESET_ | F_XG2G_RESET_; + t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val); + t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ + if ((val & F_PCS_RESET_) && adap->params.rev) { + msleep(1); + t3b_pcs_reset(mac); + } + + memset(&mac->stats, 0, sizeof(mac->stats)); + return 0; +} + +static int t3b2_mac_reset(struct cmac *mac) +{ + struct adapter *adap = mac->adapter; + unsigned int oft = mac->offset, store; + int idx = macidx(mac); + u32 val; + + if (!macidx(mac)) + t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0); + else + t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0); + + /* Stop NIC traffic to reduce the number of TXTOGGLES */ + t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 0); + /* Ensure TX drains */ + t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 0); + + t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_); + t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ + + /* Store A_TP_TX_DROP_CFG_CH0 */ + t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); + store = t3_read_reg(adap, A_TP_TX_DROP_CFG_CH0 + idx); + + msleep(10); + + /* Change DROP_CFG to 0xc0000011 */ + t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); + t3_write_reg(adap, A_TP_PIO_DATA, 0xc0000011); + + /* Check for xgm Rx fifo empty */ + /* Increased loop count to 1000 from 5 cover 1G and 100Mbps case */ + if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft, + 0x80000000, 1, 1000, 2)) { + CH_ERR(adap, "MAC %d Rx fifo drain failed\n", + macidx(mac)); + return -1; + } + + t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0); + t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ + + val = F_MAC_RESET_; + if (is_10G(adap)) + val |= F_PCS_RESET_; + else if (uses_xaui(adap)) + val |= F_PCS_RESET_ | F_XG2G_RESET_; + else + val |= F_RGMII_RESET_ | F_XG2G_RESET_; + t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val); + t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ + if ((val & F_PCS_RESET_) && adap->params.rev) { + msleep(1); + t3b_pcs_reset(mac); + } + t3_write_reg(adap, A_XGM_RX_CFG + oft, + F_DISPAUSEFRAMES | F_EN1536BFRAMES | + F_RMFCS | F_ENJUMBO | F_ENHASHMCAST); + + /* Restore the DROP_CFG */ + t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); + t3_write_reg(adap, A_TP_PIO_DATA, store); + + if (!idx) + t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT0ACTIVE); + else + t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT1ACTIVE); + + /* re-enable nic traffic */ + t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 1); + + /* Set: re-enable NIC traffic */ + t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 1); + + return 0; +} + +/* + * Set the exact match register 'idx' to recognize the given Ethernet address. + */ +static void set_addr_filter(struct cmac *mac, int idx, const u8 * addr) +{ + u32 addr_lo, addr_hi; + unsigned int oft = mac->offset + idx * 8; + + addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; + addr_hi = (addr[5] << 8) | addr[4]; + + t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo); + t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi); +} + +/* Set one of the station's unicast MAC addresses. */ +int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6]) +{ + if (idx >= mac->nucast) + return -EINVAL; + set_addr_filter(mac, idx, addr); + return 0; +} + +/* + * Specify the number of exact address filters that should be reserved for + * unicast addresses. Caller should reload the unicast and multicast addresses + * after calling this. + */ +int t3_mac_set_num_ucast(struct cmac *mac, int n) +{ + if (n > EXACT_ADDR_FILTERS) + return -EINVAL; + mac->nucast = n; + return 0; +} + +void t3_mac_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 */ +} + +void t3_mac_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) +{ + int hash = 0, octet, bit, i = 0, c; + + for (octet = 0; octet < 6; ++octet) + for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) { + hash ^= (c & 1) << i; + if (++i == 6) + i = 0; + } + return hash; +} + +int t3_mac_set_rx_mode(struct cmac *mac, struct net_device *dev) +{ + u32 val, hash_lo, hash_hi; + struct adapter *adap = mac->adapter; + unsigned int oft = mac->offset; + + val = t3_read_reg(adap, A_XGM_RX_CFG + oft) & ~F_COPYALLFRAMES; + if (dev->flags & IFF_PROMISC) + val |= F_COPYALLFRAMES; + t3_write_reg(adap, A_XGM_RX_CFG + oft, val); + + if (dev->flags & IFF_ALLMULTI) + hash_lo = hash_hi = 0xffffffff; + else { + struct netdev_hw_addr *ha; + int exact_addr_idx = mac->nucast; + + hash_lo = hash_hi = 0; + netdev_for_each_mc_addr(ha, dev) + if (exact_addr_idx < EXACT_ADDR_FILTERS) + set_addr_filter(mac, exact_addr_idx++, + ha->addr); + else { + int hash = hash_hw_addr(ha->addr); + + if (hash < 32) + hash_lo |= (1 << hash); + else + hash_hi |= (1 << (hash - 32)); + } + } + + t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo); + t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi); + return 0; +} + +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, divisor; + int ipg; + unsigned int thres, v, reg; + struct adapter *adap = mac->adapter; + + /* + * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't. The HW max + * packet size register includes header, but not FCS. + */ + mtu += 14; + if (mtu > 1536) + mtu += 4; + + if (mtu > MAX_FRAME_SIZE - 4) + return -EINVAL; + t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu); + + if (adap->params.rev >= T3_REV_B2 && + (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) { + t3_mac_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); + + reg = adap->params.rev == T3_REV_B2 ? + A_XGM_RX_MAX_PKT_SIZE_ERR_CNT : A_XGM_RXFIFO_CFG; + + /* drain RX FIFO */ + if (t3_wait_op_done(adap, reg + mac->offset, + F_RXFIFO_EMPTY, 1, 20, 5)) { + t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v); + t3_mac_enable_exact_filters(mac); + return -EIO; + } + t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, + V_RXMAXPKTSIZE(M_RXMAXPKTSIZE), + V_RXMAXPKTSIZE(mtu)); + t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v); + t3_mac_enable_exact_filters(mac); + } else + t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, + V_RXMAXPKTSIZE(M_RXMAXPKTSIZE), + V_RXMAXPKTSIZE(mtu)); + + /* + * Adjust the PAUSE frame watermarks. We always set the LWM, and the + * HWM only if flow-control is enabled. + */ + 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); + v |= V_RXFIFOPAUSELWM(lwm / 8); + 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 */ + thres = (adap->params.vpd.cclk * 1000) / 15625; + thres = (thres * mtu) / 1000; + if (is_10G(adap)) + thres /= 10; + thres = mtu > thres ? (mtu - thres + 7) / 8 : 0; + thres = max(thres, 8U); /* need at least 8 */ + ipg = (adap->params.rev == T3_REV_C) ? 0 : 1; + t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset, + V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG), + V_TXFIFOTHRESH(thres) | V_TXIPG(ipg)); + + if (adap->params.rev > 0) { + divisor = (adap->params.rev == T3_REV_C) ? 64 : 8; + t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset, + (hwm - lwm) * 4 / divisor); + } + t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset, + MAC_RXFIFO_SIZE * 4 * 8 / 512); + return 0; +} + +int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc) +{ + u32 val; + struct adapter *adap = mac->adapter; + unsigned int oft = mac->offset; + + if (duplex >= 0 && duplex != DUPLEX_FULL) + return -EINVAL; + if (speed >= 0) { + if (speed == SPEED_10) + val = V_PORTSPEED(0); + else if (speed == SPEED_100) + val = V_PORTSPEED(1); + else if (speed == SPEED_1000) + val = V_PORTSPEED(2); + else if (speed == SPEED_10000) + val = V_PORTSPEED(3); + else + return -EINVAL; + + t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, + V_PORTSPEED(M_PORTSPEED), val); + } + + val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft); + val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); + if (fc & PAUSE_TX) { + u32 rx_max_pkt_size = + G_RXMAXPKTSIZE(t3_read_reg(adap, + A_XGM_RX_MAX_PKT_SIZE + oft)); + val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8); + } + 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); + return 0; +} + +int t3_mac_enable(struct cmac *mac, int which) +{ + int idx = macidx(mac); + struct adapter *adap = mac->adapter; + unsigned int oft = mac->offset; + struct mac_stats *s = &mac->stats; + + if (which & MAC_DIRECTION_TX) { + t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); + t3_write_reg(adap, A_TP_PIO_DATA, + adap->params.rev == T3_REV_C ? + 0xc4ffff01 : 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, + adap->params.rev == T3_REV_C ? 0 : 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, + A_TP_PIO_DATA))); + mac->tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, + A_XGM_TX_SPI4_SOP_EOP_CNT + + oft))); + mac->rx_mcnt = s->rx_frames; + mac->rx_pause = s->rx_pause; + mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, + A_XGM_RX_SPI4_SOP_EOP_CNT + + oft))); + mac->rx_ocnt = s->rx_fifo_ovfl; + mac->txen = F_TXEN; + mac->toggle_cnt = 0; + } + if (which & MAC_DIRECTION_RX) + t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN); + return 0; +} + +int t3_mac_disable(struct cmac *mac, int which) +{ + struct adapter *adap = mac->adapter; + + if (which & MAC_DIRECTION_TX) { + t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0); + mac->txen = 0; + } + if (which & MAC_DIRECTION_RX) { + int val = F_MAC_RESET_; + + t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, + F_PCS_RESET_, 0); + msleep(100); + t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0); + if (is_10G(adap)) + val |= F_PCS_RESET_; + else if (uses_xaui(adap)) + val |= F_PCS_RESET_ | F_XG2G_RESET_; + else + val |= F_RGMII_RESET_ | F_XG2G_RESET_; + t3_write_reg(mac->adapter, A_XGM_RESET_CTRL + mac->offset, val); + } + return 0; +} + +int t3b2_mac_watchdog_task(struct cmac *mac) +{ + struct adapter *adap = mac->adapter; + struct mac_stats *s = &mac->stats; + unsigned int tx_tcnt, tx_xcnt; + u64 tx_mcnt = s->tx_frames; + int status; + + 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 */ + if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) { + tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap, + A_XGM_TX_SPI4_SOP_EOP_CNT + + mac->offset))); + if (tx_xcnt == 0) { + t3_write_reg(adap, A_TP_PIO_ADDR, + A_TP_TX_DROP_CNT_CH0 + macidx(mac)); + tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap, + A_TP_PIO_DATA))); + } else { + goto out; + } + } else { + mac->toggle_cnt = 0; + goto out; + } + + if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) { + if (mac->toggle_cnt > 4) { + status = 2; + goto out; + } else { + status = 1; + goto out; + } + } else { + mac->toggle_cnt = 0; + goto out; + } + +out: + mac->tx_tcnt = tx_tcnt; + mac->tx_xcnt = tx_xcnt; + mac->tx_mcnt = s->tx_frames; + mac->rx_pause = s->rx_pause; + if (status == 1) { + t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0); + t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */ + t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, mac->txen); + t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */ + mac->toggle_cnt++; + } else if (status == 2) { + t3b2_mac_reset(mac); + mac->toggle_cnt = 0; + } + return status; +} + +/* + * This function is called periodically to accumulate the current values of the + * RMON counters into the port statistics. Since the packet counters are only + * 32 bits they can overflow in ~286 secs at 10G, so the function should be + * called more frequently than that. The byte counters are 45-bit wide, they + * would overflow in ~7.8 hours. + */ +const struct mac_stats *t3_mac_update_stats(struct cmac *mac) +{ +#define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset) +#define RMON_UPDATE(mac, name, reg) \ + (mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg) +#define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \ + (mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \ + ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32) + + u32 v, lo; + + 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); + RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES); + RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES); + RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES); + RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES); + RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES); + RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES); + + RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES); + + v = RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT); + if (mac->adapter->params.rev == T3_REV_B2) + v &= 0x7fffffff; + mac->stats.rx_too_long += v; + + RMON_UPDATE(mac, rx_frames_64, RX_64B_FRAMES); + RMON_UPDATE(mac, rx_frames_65_127, RX_65_127B_FRAMES); + RMON_UPDATE(mac, rx_frames_128_255, RX_128_255B_FRAMES); + RMON_UPDATE(mac, rx_frames_256_511, RX_256_511B_FRAMES); + RMON_UPDATE(mac, rx_frames_512_1023, RX_512_1023B_FRAMES); + RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES); + RMON_UPDATE(mac, rx_frames_1519_max, RX_1519_MAXB_FRAMES); + + RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH); + RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH); + RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST); + RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST); + RMON_UPDATE(mac, tx_pause, TX_PAUSE); + /* This counts error frames in general (bad FCS, underrun, etc). */ + RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES); + + RMON_UPDATE(mac, tx_frames_64, TX_64B_FRAMES); + RMON_UPDATE(mac, tx_frames_65_127, TX_65_127B_FRAMES); + RMON_UPDATE(mac, tx_frames_128_255, TX_128_255B_FRAMES); + RMON_UPDATE(mac, tx_frames_256_511, TX_256_511B_FRAMES); + RMON_UPDATE(mac, tx_frames_512_1023, TX_512_1023B_FRAMES); + RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES); + RMON_UPDATE(mac, tx_frames_1519_max, TX_1519_MAXB_FRAMES); + + /* The next stat isn't clear-on-read. */ + t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50); + v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA); + lo = (u32) mac->stats.rx_cong_drops; + mac->stats.rx_cong_drops += (u64) (v - lo); + + return &mac->stats; +} diff --git a/drivers/net/ethernet/chelsio/cxgb4/Makefile b/drivers/net/ethernet/chelsio/cxgb4/Makefile new file mode 100644 index 000000000000..498667487f52 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/Makefile @@ -0,0 +1,7 @@ +# +# Chelsio T4 driver +# + +obj-$(CONFIG_CHELSIO_T4) += cxgb4.o + +cxgb4-objs := cxgb4_main.o l2t.o t4_hw.o sge.o diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h new file mode 100644 index 000000000000..223a7f72343b --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -0,0 +1,722 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __CXGB4_H__ +#define __CXGB4_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cxgb4_uld.h" +#include "t4_hw.h" + +#define FW_VERSION_MAJOR 1 +#define FW_VERSION_MINOR 1 +#define FW_VERSION_MICRO 0 + +enum { + MAX_NPORTS = 4, /* max # of ports */ + SERNUM_LEN = 24, /* Serial # length */ + EC_LEN = 16, /* E/C length */ + ID_LEN = 16, /* ID length */ +}; + +enum { + MEM_EDC0, + MEM_EDC1, + MEM_MC +}; + +enum dev_master { + MASTER_CANT, + MASTER_MAY, + MASTER_MUST +}; + +enum dev_state { + DEV_STATE_UNINIT, + DEV_STATE_INIT, + DEV_STATE_ERR +}; + +enum { + PAUSE_RX = 1 << 0, + PAUSE_TX = 1 << 1, + PAUSE_AUTONEG = 1 << 2 +}; + +struct port_stats { + u64 tx_octets; /* total # of octets in good frames */ + u64 tx_frames; /* all good frames */ + u64 tx_bcast_frames; /* all broadcast frames */ + u64 tx_mcast_frames; /* all multicast frames */ + u64 tx_ucast_frames; /* all unicast frames */ + u64 tx_error_frames; /* all error frames */ + + u64 tx_frames_64; /* # of Tx frames in a particular range */ + u64 tx_frames_65_127; + u64 tx_frames_128_255; + u64 tx_frames_256_511; + u64 tx_frames_512_1023; + u64 tx_frames_1024_1518; + u64 tx_frames_1519_max; + + u64 tx_drop; /* # of dropped Tx frames */ + u64 tx_pause; /* # of transmitted pause frames */ + u64 tx_ppp0; /* # of transmitted PPP prio 0 frames */ + u64 tx_ppp1; /* # of transmitted PPP prio 1 frames */ + u64 tx_ppp2; /* # of transmitted PPP prio 2 frames */ + u64 tx_ppp3; /* # of transmitted PPP prio 3 frames */ + u64 tx_ppp4; /* # of transmitted PPP prio 4 frames */ + u64 tx_ppp5; /* # of transmitted PPP prio 5 frames */ + u64 tx_ppp6; /* # of transmitted PPP prio 6 frames */ + u64 tx_ppp7; /* # of transmitted PPP prio 7 frames */ + + u64 rx_octets; /* total # of octets in good frames */ + u64 rx_frames; /* all good frames */ + u64 rx_bcast_frames; /* all broadcast frames */ + u64 rx_mcast_frames; /* all multicast frames */ + u64 rx_ucast_frames; /* all unicast frames */ + u64 rx_too_long; /* # of frames exceeding MTU */ + u64 rx_jabber; /* # of jabber frames */ + u64 rx_fcs_err; /* # of received frames with bad FCS */ + u64 rx_len_err; /* # of received frames with length error */ + u64 rx_symbol_err; /* symbol errors */ + u64 rx_runt; /* # of short frames */ + + u64 rx_frames_64; /* # of Rx frames in a particular range */ + u64 rx_frames_65_127; + u64 rx_frames_128_255; + u64 rx_frames_256_511; + u64 rx_frames_512_1023; + u64 rx_frames_1024_1518; + u64 rx_frames_1519_max; + + u64 rx_pause; /* # of received pause frames */ + u64 rx_ppp0; /* # of received PPP prio 0 frames */ + u64 rx_ppp1; /* # of received PPP prio 1 frames */ + u64 rx_ppp2; /* # of received PPP prio 2 frames */ + u64 rx_ppp3; /* # of received PPP prio 3 frames */ + u64 rx_ppp4; /* # of received PPP prio 4 frames */ + u64 rx_ppp5; /* # of received PPP prio 5 frames */ + u64 rx_ppp6; /* # of received PPP prio 6 frames */ + u64 rx_ppp7; /* # of received PPP prio 7 frames */ + + u64 rx_ovflow0; /* drops due to buffer-group 0 overflows */ + u64 rx_ovflow1; /* drops due to buffer-group 1 overflows */ + u64 rx_ovflow2; /* drops due to buffer-group 2 overflows */ + u64 rx_ovflow3; /* drops due to buffer-group 3 overflows */ + u64 rx_trunc0; /* buffer-group 0 truncated packets */ + u64 rx_trunc1; /* buffer-group 1 truncated packets */ + u64 rx_trunc2; /* buffer-group 2 truncated packets */ + u64 rx_trunc3; /* buffer-group 3 truncated packets */ +}; + +struct lb_port_stats { + u64 octets; + u64 frames; + u64 bcast_frames; + u64 mcast_frames; + u64 ucast_frames; + u64 error_frames; + + u64 frames_64; + u64 frames_65_127; + u64 frames_128_255; + u64 frames_256_511; + u64 frames_512_1023; + u64 frames_1024_1518; + u64 frames_1519_max; + + u64 drop; + + u64 ovflow0; + u64 ovflow1; + u64 ovflow2; + u64 ovflow3; + u64 trunc0; + u64 trunc1; + u64 trunc2; + u64 trunc3; +}; + +struct tp_tcp_stats { + u32 tcpOutRsts; + u64 tcpInSegs; + u64 tcpOutSegs; + u64 tcpRetransSegs; +}; + +struct tp_err_stats { + u32 macInErrs[4]; + u32 hdrInErrs[4]; + u32 tcpInErrs[4]; + u32 tnlCongDrops[4]; + u32 ofldChanDrops[4]; + u32 tnlTxDrops[4]; + u32 ofldVlanDrops[4]; + u32 tcp6InErrs[4]; + u32 ofldNoNeigh; + u32 ofldCongDefer; +}; + +struct tp_params { + unsigned int ntxchan; /* # of Tx channels */ + unsigned int tre; /* log2 of core clocks per TP tick */ +}; + +struct vpd_params { + unsigned int cclk; + u8 ec[EC_LEN + 1]; + u8 sn[SERNUM_LEN + 1]; + u8 id[ID_LEN + 1]; +}; + +struct pci_params { + unsigned char speed; + unsigned char width; +}; + +struct adapter_params { + struct tp_params tp; + struct vpd_params vpd; + struct pci_params pci; + + unsigned int sf_size; /* serial flash size in bytes */ + unsigned int sf_nsec; /* # of flash sectors */ + unsigned int sf_fw_start; /* start of FW image in flash */ + + unsigned int fw_vers; + unsigned int tp_vers; + u8 api_vers[7]; + + unsigned short mtus[NMTUS]; + unsigned short a_wnd[NCCTRL_WIN]; + unsigned short b_wnd[NCCTRL_WIN]; + + unsigned char nports; /* # of ethernet ports */ + unsigned char portvec; + unsigned char rev; /* chip revision */ + unsigned char offload; + + unsigned int ofldq_wr_cred; +}; + +struct trace_params { + u32 data[TRACE_LEN / 4]; + u32 mask[TRACE_LEN / 4]; + unsigned short snap_len; + unsigned short min_len; + unsigned char skip_ofst; + unsigned char skip_len; + unsigned char invert; + unsigned char port; +}; + +struct link_config { + unsigned short supported; /* link capabilities */ + unsigned short advertising; /* advertised capabilities */ + unsigned short requested_speed; /* speed user has requested */ + unsigned short speed; /* actual link speed */ + unsigned char requested_fc; /* flow control user has requested */ + unsigned char fc; /* actual link flow control */ + unsigned char autoneg; /* autonegotiating? */ + unsigned char link_ok; /* link up? */ +}; + +#define FW_LEN16(fw_struct) FW_CMD_LEN16(sizeof(fw_struct) / 16) + +enum { + MAX_ETH_QSETS = 32, /* # of Ethernet Tx/Rx queue sets */ + MAX_OFLD_QSETS = 16, /* # of offload Tx/Rx queue sets */ + MAX_CTRL_QUEUES = NCHAN, /* # of control Tx queues */ + MAX_RDMA_QUEUES = NCHAN, /* # of streaming RDMA Rx queues */ +}; + +enum { + MAX_EGRQ = 128, /* max # of egress queues, including FLs */ + MAX_INGQ = 64 /* max # of interrupt-capable ingress queues */ +}; + +struct adapter; +struct sge_rspq; + +struct port_info { + struct adapter *adapter; + u16 viid; + s16 xact_addr_filt; /* index of exact MAC address filter */ + u16 rss_size; /* size of VI's RSS table slice */ + s8 mdio_addr; + u8 port_type; + u8 mod_type; + u8 port_id; + u8 tx_chan; + u8 lport; /* associated offload logical port */ + u8 nqsets; /* # of qsets */ + u8 first_qset; /* index of first qset */ + u8 rss_mode; + struct link_config link_cfg; + u16 *rss; +}; + +struct dentry; +struct work_struct; + +enum { /* adapter flags */ + FULL_INIT_DONE = (1 << 0), + USING_MSI = (1 << 1), + USING_MSIX = (1 << 2), + FW_OK = (1 << 4), +}; + +struct rx_sw_desc; + +struct sge_fl { /* SGE free-buffer queue state */ + unsigned int avail; /* # of available Rx buffers */ + unsigned int pend_cred; /* new buffers since last FL DB ring */ + unsigned int cidx; /* consumer index */ + unsigned int pidx; /* producer index */ + unsigned long alloc_failed; /* # of times buffer allocation failed */ + unsigned long large_alloc_failed; + unsigned long starving; + /* RO fields */ + unsigned int cntxt_id; /* SGE context id for the free list */ + unsigned int size; /* capacity of free list */ + struct rx_sw_desc *sdesc; /* address of SW Rx descriptor ring */ + __be64 *desc; /* address of HW Rx descriptor ring */ + dma_addr_t addr; /* bus address of HW ring start */ +}; + +/* A packet gather list */ +struct pkt_gl { + skb_frag_t frags[MAX_SKB_FRAGS]; + void *va; /* virtual address of first byte */ + unsigned int nfrags; /* # of fragments */ + unsigned int tot_len; /* total length of fragments */ +}; + +typedef int (*rspq_handler_t)(struct sge_rspq *q, const __be64 *rsp, + const struct pkt_gl *gl); + +struct sge_rspq { /* state for an SGE response queue */ + struct napi_struct napi; + const __be64 *cur_desc; /* current descriptor in queue */ + unsigned int cidx; /* consumer index */ + u8 gen; /* current generation bit */ + u8 intr_params; /* interrupt holdoff parameters */ + u8 next_intr_params; /* holdoff params for next interrupt */ + u8 pktcnt_idx; /* interrupt packet threshold */ + u8 uld; /* ULD handling this queue */ + u8 idx; /* queue index within its group */ + int offset; /* offset into current Rx buffer */ + u16 cntxt_id; /* SGE context id for the response q */ + u16 abs_id; /* absolute SGE id for the response q */ + __be64 *desc; /* address of HW response ring */ + dma_addr_t phys_addr; /* physical address of the ring */ + unsigned int iqe_len; /* entry size */ + unsigned int size; /* capacity of response queue */ + struct adapter *adap; + struct net_device *netdev; /* associated net device */ + rspq_handler_t handler; +}; + +struct sge_eth_stats { /* Ethernet queue statistics */ + unsigned long pkts; /* # of ethernet packets */ + unsigned long lro_pkts; /* # of LRO super packets */ + unsigned long lro_merged; /* # of wire packets merged by LRO */ + unsigned long rx_cso; /* # of Rx checksum offloads */ + unsigned long vlan_ex; /* # of Rx VLAN extractions */ + unsigned long rx_drops; /* # of packets dropped due to no mem */ +}; + +struct sge_eth_rxq { /* SW Ethernet Rx queue */ + struct sge_rspq rspq; + struct sge_fl fl; + struct sge_eth_stats stats; +} ____cacheline_aligned_in_smp; + +struct sge_ofld_stats { /* offload queue statistics */ + unsigned long pkts; /* # of packets */ + unsigned long imm; /* # of immediate-data packets */ + unsigned long an; /* # of asynchronous notifications */ + unsigned long nomem; /* # of responses deferred due to no mem */ +}; + +struct sge_ofld_rxq { /* SW offload Rx queue */ + struct sge_rspq rspq; + struct sge_fl fl; + struct sge_ofld_stats stats; +} ____cacheline_aligned_in_smp; + +struct tx_desc { + __be64 flit[8]; +}; + +struct tx_sw_desc; + +struct sge_txq { + unsigned int in_use; /* # of in-use Tx descriptors */ + unsigned int size; /* # of descriptors */ + unsigned int cidx; /* SW consumer index */ + unsigned int pidx; /* producer index */ + unsigned long stops; /* # of times q has been stopped */ + unsigned long restarts; /* # of queue restarts */ + unsigned int cntxt_id; /* SGE context id for the Tx q */ + struct tx_desc *desc; /* address of HW Tx descriptor ring */ + struct tx_sw_desc *sdesc; /* address of SW Tx descriptor ring */ + struct sge_qstat *stat; /* queue status entry */ + dma_addr_t phys_addr; /* physical address of the ring */ +}; + +struct sge_eth_txq { /* state for an SGE Ethernet Tx queue */ + struct sge_txq q; + struct netdev_queue *txq; /* associated netdev TX queue */ + unsigned long tso; /* # of TSO requests */ + unsigned long tx_cso; /* # of Tx checksum offloads */ + unsigned long vlan_ins; /* # of Tx VLAN insertions */ + unsigned long mapping_err; /* # of I/O MMU packet mapping errors */ +} ____cacheline_aligned_in_smp; + +struct sge_ofld_txq { /* state for an SGE offload Tx queue */ + struct sge_txq q; + struct adapter *adap; + struct sk_buff_head sendq; /* list of backpressured packets */ + struct tasklet_struct qresume_tsk; /* restarts the queue */ + u8 full; /* the Tx ring is full */ + unsigned long mapping_err; /* # of I/O MMU packet mapping errors */ +} ____cacheline_aligned_in_smp; + +struct sge_ctrl_txq { /* state for an SGE control Tx queue */ + struct sge_txq q; + struct adapter *adap; + struct sk_buff_head sendq; /* list of backpressured packets */ + struct tasklet_struct qresume_tsk; /* restarts the queue */ + u8 full; /* the Tx ring is full */ +} ____cacheline_aligned_in_smp; + +struct sge { + struct sge_eth_txq ethtxq[MAX_ETH_QSETS]; + struct sge_ofld_txq ofldtxq[MAX_OFLD_QSETS]; + struct sge_ctrl_txq ctrlq[MAX_CTRL_QUEUES]; + + struct sge_eth_rxq ethrxq[MAX_ETH_QSETS]; + struct sge_ofld_rxq ofldrxq[MAX_OFLD_QSETS]; + struct sge_ofld_rxq rdmarxq[MAX_RDMA_QUEUES]; + struct sge_rspq fw_evtq ____cacheline_aligned_in_smp; + + struct sge_rspq intrq ____cacheline_aligned_in_smp; + spinlock_t intrq_lock; + + u16 max_ethqsets; /* # of available Ethernet queue sets */ + u16 ethqsets; /* # of active Ethernet queue sets */ + u16 ethtxq_rover; /* Tx queue to clean up next */ + u16 ofldqsets; /* # of active offload queue sets */ + u16 rdmaqs; /* # of available RDMA Rx queues */ + u16 ofld_rxq[MAX_OFLD_QSETS]; + u16 rdma_rxq[NCHAN]; + u16 timer_val[SGE_NTIMERS]; + u8 counter_val[SGE_NCOUNTERS]; + unsigned int starve_thres; + u8 idma_state[2]; + unsigned int egr_start; + unsigned int ingr_start; + void *egr_map[MAX_EGRQ]; /* qid->queue egress queue map */ + struct sge_rspq *ingr_map[MAX_INGQ]; /* qid->queue ingress queue map */ + DECLARE_BITMAP(starving_fl, MAX_EGRQ); + DECLARE_BITMAP(txq_maperr, MAX_EGRQ); + struct timer_list rx_timer; /* refills starving FLs */ + struct timer_list tx_timer; /* checks Tx queues */ +}; + +#define for_each_ethrxq(sge, i) for (i = 0; i < (sge)->ethqsets; i++) +#define for_each_ofldrxq(sge, i) for (i = 0; i < (sge)->ofldqsets; i++) +#define for_each_rdmarxq(sge, i) for (i = 0; i < (sge)->rdmaqs; i++) + +struct l2t_data; + +struct adapter { + void __iomem *regs; + struct pci_dev *pdev; + struct device *pdev_dev; + unsigned int fn; + unsigned int flags; + + int msg_enable; + + struct adapter_params params; + struct cxgb4_virt_res vres; + unsigned int swintr; + + unsigned int wol; + + struct { + unsigned short vec; + char desc[IFNAMSIZ + 10]; + } msix_info[MAX_INGQ + 1]; + + struct sge sge; + + struct net_device *port[MAX_NPORTS]; + u8 chan_map[NCHAN]; /* channel -> port map */ + + struct l2t_data *l2t; + void *uld_handle[CXGB4_ULD_MAX]; + struct list_head list_node; + + struct tid_info tids; + void **tid_release_head; + spinlock_t tid_release_lock; + struct work_struct tid_release_task; + bool tid_release_task_busy; + + struct dentry *debugfs_root; + + spinlock_t stats_lock; +}; + +static inline u32 t4_read_reg(struct adapter *adap, u32 reg_addr) +{ + return readl(adap->regs + reg_addr); +} + +static inline void t4_write_reg(struct adapter *adap, u32 reg_addr, u32 val) +{ + writel(val, adap->regs + reg_addr); +} + +#ifndef readq +static inline u64 readq(const volatile void __iomem *addr) +{ + return readl(addr) + ((u64)readl(addr + 4) << 32); +} + +static inline void writeq(u64 val, volatile void __iomem *addr) +{ + writel(val, addr); + writel(val >> 32, addr + 4); +} +#endif + +static inline u64 t4_read_reg64(struct adapter *adap, u32 reg_addr) +{ + return readq(adap->regs + reg_addr); +} + +static inline void t4_write_reg64(struct adapter *adap, u32 reg_addr, u64 val) +{ + writeq(val, adap->regs + reg_addr); +} + +/** + * netdev2pinfo - return the port_info structure associated with a net_device + * @dev: the netdev + * + * Return the struct port_info associated with a net_device + */ +static inline struct port_info *netdev2pinfo(const struct net_device *dev) +{ + return netdev_priv(dev); +} + +/** + * adap2pinfo - return the port_info of a port + * @adap: the adapter + * @idx: the port index + * + * Return the port_info structure for the port of the given index. + */ +static inline struct port_info *adap2pinfo(struct adapter *adap, int idx) +{ + return netdev_priv(adap->port[idx]); +} + +/** + * netdev2adap - return the adapter structure associated with a net_device + * @dev: the netdev + * + * Return the struct adapter associated with a net_device + */ +static inline struct adapter *netdev2adap(const struct net_device *dev) +{ + return netdev2pinfo(dev)->adapter; +} + +void t4_os_portmod_changed(const struct adapter *adap, int port_id); +void t4_os_link_changed(struct adapter *adap, int port_id, int link_stat); + +void *t4_alloc_mem(size_t size); + +void t4_free_sge_resources(struct adapter *adap); +irq_handler_t t4_intr_handler(struct adapter *adap); +netdev_tx_t t4_eth_xmit(struct sk_buff *skb, struct net_device *dev); +int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, + const struct pkt_gl *gl); +int t4_mgmt_tx(struct adapter *adap, struct sk_buff *skb); +int t4_ofld_send(struct adapter *adap, struct sk_buff *skb); +int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq, + struct net_device *dev, int intr_idx, + struct sge_fl *fl, rspq_handler_t hnd); +int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq, + struct net_device *dev, struct netdev_queue *netdevq, + unsigned int iqid); +int t4_sge_alloc_ctrl_txq(struct adapter *adap, struct sge_ctrl_txq *txq, + struct net_device *dev, unsigned int iqid, + unsigned int cmplqid); +int t4_sge_alloc_ofld_txq(struct adapter *adap, struct sge_ofld_txq *txq, + struct net_device *dev, unsigned int iqid); +irqreturn_t t4_sge_intr_msix(int irq, void *cookie); +void t4_sge_init(struct adapter *adap); +void t4_sge_start(struct adapter *adap); +void t4_sge_stop(struct adapter *adap); + +#define for_each_port(adapter, iter) \ + for (iter = 0; iter < (adapter)->params.nports; ++iter) + +static inline unsigned int core_ticks_per_usec(const struct adapter *adap) +{ + return adap->params.vpd.cclk / 1000; +} + +static inline unsigned int us_to_core_ticks(const struct adapter *adap, + unsigned int us) +{ + return (us * adap->params.vpd.cclk) / 1000; +} + +void t4_set_reg_field(struct adapter *adap, unsigned int addr, u32 mask, + u32 val); + +int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size, + void *rpl, bool sleep_ok); + +static inline int t4_wr_mbox(struct adapter *adap, int mbox, const void *cmd, + int size, void *rpl) +{ + return t4_wr_mbox_meat(adap, mbox, cmd, size, rpl, true); +} + +static inline int t4_wr_mbox_ns(struct adapter *adap, int mbox, const void *cmd, + int size, void *rpl) +{ + return t4_wr_mbox_meat(adap, mbox, cmd, size, rpl, false); +} + +void t4_intr_enable(struct adapter *adapter); +void t4_intr_disable(struct adapter *adapter); +int t4_slow_intr_handler(struct adapter *adapter); + +int t4_wait_dev_ready(struct adapter *adap); +int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port, + struct link_config *lc); +int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port); +int t4_seeprom_wp(struct adapter *adapter, bool enable); +int t4_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size); +int t4_check_fw_version(struct adapter *adapter); +int t4_prep_adapter(struct adapter *adapter); +int t4_port_init(struct adapter *adap, int mbox, int pf, int vf); +void t4_fatal_err(struct adapter *adapter); +int t4_config_rss_range(struct adapter *adapter, int mbox, unsigned int viid, + int start, int n, const u16 *rspq, unsigned int nrspq); +int t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode, + unsigned int flags); +int t4_mc_read(struct adapter *adap, u32 addr, __be32 *data, u64 *parity); +int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, + u64 *parity); + +void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p); +void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log); +void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4, + struct tp_tcp_stats *v6); +void t4_load_mtus(struct adapter *adap, const unsigned short *mtus, + const unsigned short *alpha, const unsigned short *beta); + +void t4_wol_magic_enable(struct adapter *adap, unsigned int port, + const u8 *addr); +int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map, + u64 mask0, u64 mask1, unsigned int crc, bool enable); + +int t4_fw_hello(struct adapter *adap, unsigned int mbox, unsigned int evt_mbox, + enum dev_master master, enum dev_state *state); +int t4_fw_bye(struct adapter *adap, unsigned int mbox); +int t4_early_init(struct adapter *adap, unsigned int mbox); +int t4_fw_reset(struct adapter *adap, unsigned int mbox, int reset); +int t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf, + unsigned int vf, unsigned int nparams, const u32 *params, + u32 *val); +int t4_set_params(struct adapter *adap, unsigned int mbox, unsigned int pf, + unsigned int vf, unsigned int nparams, const u32 *params, + const u32 *val); +int t4_cfg_pfvf(struct adapter *adap, unsigned int mbox, unsigned int pf, + unsigned int vf, unsigned int txq, unsigned int txq_eth_ctrl, + unsigned int rxqi, unsigned int rxq, unsigned int tc, + unsigned int vi, unsigned int cmask, unsigned int pmask, + unsigned int nexact, unsigned int rcaps, unsigned int wxcaps); +int t4_alloc_vi(struct adapter *adap, unsigned int mbox, unsigned int port, + unsigned int pf, unsigned int vf, unsigned int nmac, u8 *mac, + unsigned int *rss_size); +int t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid, + int mtu, int promisc, int all_multi, int bcast, int vlanex, + bool sleep_ok); +int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox, + unsigned int viid, bool free, unsigned int naddr, + const u8 **addr, u16 *idx, u64 *hash, bool sleep_ok); +int t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid, + int idx, const u8 *addr, bool persist, bool add_smt); +int t4_set_addr_hash(struct adapter *adap, unsigned int mbox, unsigned int viid, + bool ucast, u64 vec, bool sleep_ok); +int t4_enable_vi(struct adapter *adap, unsigned int mbox, unsigned int viid, + bool rx_en, bool tx_en); +int t4_identify_port(struct adapter *adap, unsigned int mbox, unsigned int viid, + unsigned int nblinks); +int t4_mdio_rd(struct adapter *adap, unsigned int mbox, unsigned int phy_addr, + unsigned int mmd, unsigned int reg, u16 *valp); +int t4_mdio_wr(struct adapter *adap, unsigned int mbox, unsigned int phy_addr, + unsigned int mmd, unsigned int reg, u16 val); +int t4_iq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, + unsigned int vf, unsigned int iqtype, unsigned int iqid, + unsigned int fl0id, unsigned int fl1id); +int t4_eth_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, + unsigned int vf, unsigned int eqid); +int t4_ctrl_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, + unsigned int vf, unsigned int eqid); +int t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, + unsigned int vf, unsigned int eqid); +int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl); +#endif /* __CXGB4_H__ */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c new file mode 100644 index 000000000000..c9957b7f17b5 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -0,0 +1,3806 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cxgb4.h" +#include "t4_regs.h" +#include "t4_msg.h" +#include "t4fw_api.h" +#include "l2t.h" + +#define DRV_VERSION "1.3.0-ko" +#define DRV_DESC "Chelsio T4 Network Driver" + +/* + * Max interrupt hold-off timer value in us. Queues fall back to this value + * under extreme memory pressure so it's largish to give the system time to + * recover. + */ +#define MAX_SGE_TIMERVAL 200U + +#ifdef CONFIG_PCI_IOV +/* + * Virtual Function provisioning constants. We need two extra Ingress Queues + * with Interrupt capability to serve as the VF's Firmware Event Queue and + * Forwarded Interrupt Queue (when using MSI mode) -- neither will have Free + * Lists associated with them). For each Ethernet/Control Egress Queue and + * for each Free List, we need an Egress Context. + */ +enum { + VFRES_NPORTS = 1, /* # of "ports" per VF */ + VFRES_NQSETS = 2, /* # of "Queue Sets" per VF */ + + VFRES_NVI = VFRES_NPORTS, /* # of Virtual Interfaces */ + VFRES_NETHCTRL = VFRES_NQSETS, /* # of EQs used for ETH or CTRL Qs */ + VFRES_NIQFLINT = VFRES_NQSETS+2,/* # of ingress Qs/w Free List(s)/intr */ + VFRES_NIQ = 0, /* # of non-fl/int ingress queues */ + VFRES_NEQ = VFRES_NQSETS*2, /* # of egress queues */ + VFRES_TC = 0, /* PCI-E traffic class */ + VFRES_NEXACTF = 16, /* # of exact MPS filters */ + + VFRES_R_CAPS = FW_CMD_CAP_DMAQ|FW_CMD_CAP_VF|FW_CMD_CAP_PORT, + VFRES_WX_CAPS = FW_CMD_CAP_DMAQ|FW_CMD_CAP_VF, +}; + +/* + * Provide a Port Access Rights Mask for the specified PF/VF. This is very + * static and likely not to be useful in the long run. We really need to + * implement some form of persistent configuration which the firmware + * controls. + */ +static unsigned int pfvfres_pmask(struct adapter *adapter, + unsigned int pf, unsigned int vf) +{ + unsigned int portn, portvec; + + /* + * Give PF's access to all of the ports. + */ + if (vf == 0) + return FW_PFVF_CMD_PMASK_MASK; + + /* + * For VFs, we'll assign them access to the ports based purely on the + * PF. We assign active ports in order, wrapping around if there are + * fewer active ports than PFs: e.g. active port[pf % nports]. + * Unfortunately the adapter's port_info structs haven't been + * initialized yet so we have to compute this. + */ + if (adapter->params.nports == 0) + return 0; + + portn = pf % adapter->params.nports; + portvec = adapter->params.portvec; + for (;;) { + /* + * Isolate the lowest set bit in the port vector. If we're at + * the port number that we want, return that as the pmask. + * otherwise mask that bit out of the port vector and + * decrement our port number ... + */ + unsigned int pmask = portvec ^ (portvec & (portvec-1)); + if (portn == 0) + return pmask; + portn--; + portvec &= ~pmask; + } + /*NOTREACHED*/ +} +#endif + +enum { + MEMWIN0_APERTURE = 65536, + MEMWIN0_BASE = 0x30000, + MEMWIN1_APERTURE = 32768, + MEMWIN1_BASE = 0x28000, + MEMWIN2_APERTURE = 2048, + MEMWIN2_BASE = 0x1b800, +}; + +enum { + MAX_TXQ_ENTRIES = 16384, + MAX_CTRL_TXQ_ENTRIES = 1024, + MAX_RSPQ_ENTRIES = 16384, + MAX_RX_BUFFERS = 16384, + MIN_TXQ_ENTRIES = 32, + MIN_CTRL_TXQ_ENTRIES = 32, + MIN_RSPQ_ENTRIES = 128, + MIN_FL_ENTRIES = 16 +}; + +#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \ + NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\ + NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) + +#define CH_DEVICE(devid, data) { PCI_VDEVICE(CHELSIO, devid), (data) } + +static DEFINE_PCI_DEVICE_TABLE(cxgb4_pci_tbl) = { + CH_DEVICE(0xa000, 0), /* PE10K */ + CH_DEVICE(0x4001, -1), + CH_DEVICE(0x4002, -1), + CH_DEVICE(0x4003, -1), + CH_DEVICE(0x4004, -1), + CH_DEVICE(0x4005, -1), + CH_DEVICE(0x4006, -1), + CH_DEVICE(0x4007, -1), + CH_DEVICE(0x4008, -1), + CH_DEVICE(0x4009, -1), + CH_DEVICE(0x400a, -1), + CH_DEVICE(0x4401, 4), + CH_DEVICE(0x4402, 4), + CH_DEVICE(0x4403, 4), + CH_DEVICE(0x4404, 4), + CH_DEVICE(0x4405, 4), + CH_DEVICE(0x4406, 4), + CH_DEVICE(0x4407, 4), + CH_DEVICE(0x4408, 4), + CH_DEVICE(0x4409, 4), + CH_DEVICE(0x440a, 4), + { 0, } +}; + +#define FW_FNAME "cxgb4/t4fw.bin" + +MODULE_DESCRIPTION(DRV_DESC); +MODULE_AUTHOR("Chelsio Communications"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_VERSION(DRV_VERSION); +MODULE_DEVICE_TABLE(pci, cxgb4_pci_tbl); +MODULE_FIRMWARE(FW_FNAME); + +static int dflt_msg_enable = DFLT_MSG_ENABLE; + +module_param(dflt_msg_enable, int, 0644); +MODULE_PARM_DESC(dflt_msg_enable, "Chelsio T4 default message enable bitmap"); + +/* + * The driver uses the best interrupt scheme available on a platform in the + * order MSI-X, MSI, legacy INTx interrupts. This parameter determines which + * of these schemes the driver may consider as follows: + * + * msi = 2: choose from among all three options + * msi = 1: only consider MSI and INTx interrupts + * msi = 0: force INTx interrupts + */ +static int msi = 2; + +module_param(msi, int, 0644); +MODULE_PARM_DESC(msi, "whether to use INTx (0), MSI (1) or MSI-X (2)"); + +/* + * Queue interrupt hold-off timer values. Queues default to the first of these + * upon creation. + */ +static unsigned int intr_holdoff[SGE_NTIMERS - 1] = { 5, 10, 20, 50, 100 }; + +module_param_array(intr_holdoff, uint, NULL, 0644); +MODULE_PARM_DESC(intr_holdoff, "values for queue interrupt hold-off timers " + "0..4 in microseconds"); + +static unsigned int intr_cnt[SGE_NCOUNTERS - 1] = { 4, 8, 16 }; + +module_param_array(intr_cnt, uint, NULL, 0644); +MODULE_PARM_DESC(intr_cnt, + "thresholds 1..3 for queue interrupt packet counters"); + +static int vf_acls; + +#ifdef CONFIG_PCI_IOV +module_param(vf_acls, bool, 0644); +MODULE_PARM_DESC(vf_acls, "if set enable virtualization L2 ACL enforcement"); + +static unsigned int num_vf[4]; + +module_param_array(num_vf, uint, NULL, 0644); +MODULE_PARM_DESC(num_vf, "number of VFs for each of PFs 0-3"); +#endif + +static struct dentry *cxgb4_debugfs_root; + +static LIST_HEAD(adapter_list); +static DEFINE_MUTEX(uld_mutex); +static struct cxgb4_uld_info ulds[CXGB4_ULD_MAX]; +static const char *uld_str[] = { "RDMA", "iSCSI" }; + +static void link_report(struct net_device *dev) +{ + if (!netif_carrier_ok(dev)) + netdev_info(dev, "link down\n"); + else { + static const char *fc[] = { "no", "Rx", "Tx", "Tx/Rx" }; + + const char *s = "10Mbps"; + const struct port_info *p = netdev_priv(dev); + + switch (p->link_cfg.speed) { + case SPEED_10000: + s = "10Gbps"; + break; + case SPEED_1000: + s = "1000Mbps"; + break; + case SPEED_100: + s = "100Mbps"; + break; + } + + netdev_info(dev, "link up, %s, full-duplex, %s PAUSE\n", s, + fc[p->link_cfg.fc]); + } +} + +void t4_os_link_changed(struct adapter *adapter, int port_id, int link_stat) +{ + struct net_device *dev = adapter->port[port_id]; + + /* Skip changes from disabled ports. */ + if (netif_running(dev) && link_stat != netif_carrier_ok(dev)) { + if (link_stat) + netif_carrier_on(dev); + else + netif_carrier_off(dev); + + link_report(dev); + } +} + +void t4_os_portmod_changed(const struct adapter *adap, int port_id) +{ + static const char *mod_str[] = { + NULL, "LR", "SR", "ER", "passive DA", "active DA", "LRM" + }; + + const struct net_device *dev = adap->port[port_id]; + const struct port_info *pi = netdev_priv(dev); + + if (pi->mod_type == FW_PORT_MOD_TYPE_NONE) + netdev_info(dev, "port module unplugged\n"); + else if (pi->mod_type < ARRAY_SIZE(mod_str)) + netdev_info(dev, "%s module inserted\n", mod_str[pi->mod_type]); +} + +/* + * Configure the exact and hash address filters to handle a port's multicast + * and secondary unicast MAC addresses. + */ +static int set_addr_filters(const struct net_device *dev, bool sleep) +{ + u64 mhash = 0; + u64 uhash = 0; + bool free = true; + u16 filt_idx[7]; + const u8 *addr[7]; + int ret, naddr = 0; + const struct netdev_hw_addr *ha; + int uc_cnt = netdev_uc_count(dev); + int mc_cnt = netdev_mc_count(dev); + const struct port_info *pi = netdev_priv(dev); + unsigned int mb = pi->adapter->fn; + + /* first do the secondary unicast addresses */ + netdev_for_each_uc_addr(ha, dev) { + addr[naddr++] = ha->addr; + if (--uc_cnt == 0 || naddr >= ARRAY_SIZE(addr)) { + ret = t4_alloc_mac_filt(pi->adapter, mb, pi->viid, free, + naddr, addr, filt_idx, &uhash, sleep); + if (ret < 0) + return ret; + + free = false; + naddr = 0; + } + } + + /* next set up the multicast addresses */ + netdev_for_each_mc_addr(ha, dev) { + addr[naddr++] = ha->addr; + if (--mc_cnt == 0 || naddr >= ARRAY_SIZE(addr)) { + ret = t4_alloc_mac_filt(pi->adapter, mb, pi->viid, free, + naddr, addr, filt_idx, &mhash, sleep); + if (ret < 0) + return ret; + + free = false; + naddr = 0; + } + } + + return t4_set_addr_hash(pi->adapter, mb, pi->viid, uhash != 0, + uhash | mhash, sleep); +} + +/* + * Set Rx properties of a port, such as promiscruity, address filters, and MTU. + * If @mtu is -1 it is left unchanged. + */ +static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok) +{ + int ret; + struct port_info *pi = netdev_priv(dev); + + ret = set_addr_filters(dev, sleep_ok); + if (ret == 0) + ret = t4_set_rxmode(pi->adapter, pi->adapter->fn, pi->viid, mtu, + (dev->flags & IFF_PROMISC) ? 1 : 0, + (dev->flags & IFF_ALLMULTI) ? 1 : 0, 1, -1, + sleep_ok); + return ret; +} + +/** + * link_start - enable a port + * @dev: the port to enable + * + * Performs the MAC and PHY actions needed to enable a port. + */ +static int link_start(struct net_device *dev) +{ + int ret; + struct port_info *pi = netdev_priv(dev); + unsigned int mb = pi->adapter->fn; + + /* + * We do not set address filters and promiscuity here, the stack does + * that step explicitly. + */ + ret = t4_set_rxmode(pi->adapter, mb, pi->viid, dev->mtu, -1, -1, -1, + !!(dev->features & NETIF_F_HW_VLAN_RX), true); + if (ret == 0) { + ret = t4_change_mac(pi->adapter, mb, pi->viid, + pi->xact_addr_filt, dev->dev_addr, true, + true); + if (ret >= 0) { + pi->xact_addr_filt = ret; + ret = 0; + } + } + if (ret == 0) + ret = t4_link_start(pi->adapter, mb, pi->tx_chan, + &pi->link_cfg); + if (ret == 0) + ret = t4_enable_vi(pi->adapter, mb, pi->viid, true, true); + return ret; +} + +/* + * Response queue handler for the FW event queue. + */ +static int fwevtq_handler(struct sge_rspq *q, const __be64 *rsp, + const struct pkt_gl *gl) +{ + u8 opcode = ((const struct rss_header *)rsp)->opcode; + + rsp++; /* skip RSS header */ + if (likely(opcode == CPL_SGE_EGR_UPDATE)) { + const struct cpl_sge_egr_update *p = (void *)rsp; + unsigned int qid = EGR_QID(ntohl(p->opcode_qid)); + struct sge_txq *txq; + + txq = q->adap->sge.egr_map[qid - q->adap->sge.egr_start]; + txq->restarts++; + if ((u8 *)txq < (u8 *)q->adap->sge.ofldtxq) { + struct sge_eth_txq *eq; + + eq = container_of(txq, struct sge_eth_txq, q); + netif_tx_wake_queue(eq->txq); + } else { + struct sge_ofld_txq *oq; + + oq = container_of(txq, struct sge_ofld_txq, q); + tasklet_schedule(&oq->qresume_tsk); + } + } else if (opcode == CPL_FW6_MSG || opcode == CPL_FW4_MSG) { + const struct cpl_fw6_msg *p = (void *)rsp; + + if (p->type == 0) + t4_handle_fw_rpl(q->adap, p->data); + } else if (opcode == CPL_L2T_WRITE_RPL) { + const struct cpl_l2t_write_rpl *p = (void *)rsp; + + do_l2t_write_rpl(q->adap, p); + } else + dev_err(q->adap->pdev_dev, + "unexpected CPL %#x on FW event queue\n", opcode); + return 0; +} + +/** + * uldrx_handler - response queue handler for ULD queues + * @q: the response queue that received the packet + * @rsp: the response queue descriptor holding the offload message + * @gl: the gather list of packet fragments + * + * Deliver an ingress offload packet to a ULD. All processing is done by + * the ULD, we just maintain statistics. + */ +static int uldrx_handler(struct sge_rspq *q, const __be64 *rsp, + const struct pkt_gl *gl) +{ + struct sge_ofld_rxq *rxq = container_of(q, struct sge_ofld_rxq, rspq); + + if (ulds[q->uld].rx_handler(q->adap->uld_handle[q->uld], rsp, gl)) { + rxq->stats.nomem++; + return -1; + } + if (gl == NULL) + rxq->stats.imm++; + else if (gl == CXGB4_MSG_AN) + rxq->stats.an++; + else + rxq->stats.pkts++; + return 0; +} + +static void disable_msi(struct adapter *adapter) +{ + if (adapter->flags & USING_MSIX) { + pci_disable_msix(adapter->pdev); + adapter->flags &= ~USING_MSIX; + } else if (adapter->flags & USING_MSI) { + pci_disable_msi(adapter->pdev); + adapter->flags &= ~USING_MSI; + } +} + +/* + * Interrupt handler for non-data events used with MSI-X. + */ +static irqreturn_t t4_nondata_intr(int irq, void *cookie) +{ + struct adapter *adap = cookie; + + u32 v = t4_read_reg(adap, MYPF_REG(PL_PF_INT_CAUSE)); + if (v & PFSW) { + adap->swintr = 1; + t4_write_reg(adap, MYPF_REG(PL_PF_INT_CAUSE), v); + } + t4_slow_intr_handler(adap); + return IRQ_HANDLED; +} + +/* + * Name the MSI-X interrupts. + */ +static void name_msix_vecs(struct adapter *adap) +{ + int i, j, msi_idx = 2, n = sizeof(adap->msix_info[0].desc); + + /* non-data interrupts */ + snprintf(adap->msix_info[0].desc, n, "%s", adap->port[0]->name); + + /* FW events */ + snprintf(adap->msix_info[1].desc, n, "%s-FWeventq", + adap->port[0]->name); + + /* Ethernet queues */ + for_each_port(adap, j) { + struct net_device *d = adap->port[j]; + const struct port_info *pi = netdev_priv(d); + + for (i = 0; i < pi->nqsets; i++, msi_idx++) + snprintf(adap->msix_info[msi_idx].desc, n, "%s-Rx%d", + d->name, i); + } + + /* offload queues */ + for_each_ofldrxq(&adap->sge, i) + snprintf(adap->msix_info[msi_idx++].desc, n, "%s-ofld%d", + adap->port[0]->name, i); + + for_each_rdmarxq(&adap->sge, i) + snprintf(adap->msix_info[msi_idx++].desc, n, "%s-rdma%d", + adap->port[0]->name, i); +} + +static int request_msix_queue_irqs(struct adapter *adap) +{ + struct sge *s = &adap->sge; + int err, ethqidx, ofldqidx = 0, rdmaqidx = 0, msi = 2; + + err = request_irq(adap->msix_info[1].vec, t4_sge_intr_msix, 0, + adap->msix_info[1].desc, &s->fw_evtq); + if (err) + return err; + + for_each_ethrxq(s, ethqidx) { + err = request_irq(adap->msix_info[msi].vec, t4_sge_intr_msix, 0, + adap->msix_info[msi].desc, + &s->ethrxq[ethqidx].rspq); + if (err) + goto unwind; + msi++; + } + for_each_ofldrxq(s, ofldqidx) { + err = request_irq(adap->msix_info[msi].vec, t4_sge_intr_msix, 0, + adap->msix_info[msi].desc, + &s->ofldrxq[ofldqidx].rspq); + if (err) + goto unwind; + msi++; + } + for_each_rdmarxq(s, rdmaqidx) { + err = request_irq(adap->msix_info[msi].vec, t4_sge_intr_msix, 0, + adap->msix_info[msi].desc, + &s->rdmarxq[rdmaqidx].rspq); + if (err) + goto unwind; + msi++; + } + return 0; + +unwind: + while (--rdmaqidx >= 0) + free_irq(adap->msix_info[--msi].vec, + &s->rdmarxq[rdmaqidx].rspq); + while (--ofldqidx >= 0) + free_irq(adap->msix_info[--msi].vec, + &s->ofldrxq[ofldqidx].rspq); + while (--ethqidx >= 0) + free_irq(adap->msix_info[--msi].vec, &s->ethrxq[ethqidx].rspq); + free_irq(adap->msix_info[1].vec, &s->fw_evtq); + return err; +} + +static void free_msix_queue_irqs(struct adapter *adap) +{ + int i, msi = 2; + struct sge *s = &adap->sge; + + free_irq(adap->msix_info[1].vec, &s->fw_evtq); + for_each_ethrxq(s, i) + free_irq(adap->msix_info[msi++].vec, &s->ethrxq[i].rspq); + for_each_ofldrxq(s, i) + free_irq(adap->msix_info[msi++].vec, &s->ofldrxq[i].rspq); + for_each_rdmarxq(s, i) + free_irq(adap->msix_info[msi++].vec, &s->rdmarxq[i].rspq); +} + +/** + * write_rss - write the RSS table for a given port + * @pi: the port + * @queues: array of queue indices for RSS + * + * Sets up the portion of the HW RSS table for the port's VI to distribute + * packets to the Rx queues in @queues. + */ +static int write_rss(const struct port_info *pi, const u16 *queues) +{ + u16 *rss; + int i, err; + const struct sge_eth_rxq *q = &pi->adapter->sge.ethrxq[pi->first_qset]; + + rss = kmalloc(pi->rss_size * sizeof(u16), GFP_KERNEL); + if (!rss) + return -ENOMEM; + + /* map the queue indices to queue ids */ + for (i = 0; i < pi->rss_size; i++, queues++) + rss[i] = q[*queues].rspq.abs_id; + + err = t4_config_rss_range(pi->adapter, pi->adapter->fn, pi->viid, 0, + pi->rss_size, rss, pi->rss_size); + kfree(rss); + return err; +} + +/** + * setup_rss - configure RSS + * @adap: the adapter + * + * Sets up RSS for each port. + */ +static int setup_rss(struct adapter *adap) +{ + int i, err; + + for_each_port(adap, i) { + const struct port_info *pi = adap2pinfo(adap, i); + + err = write_rss(pi, pi->rss); + if (err) + return err; + } + return 0; +} + +/* + * Return the channel of the ingress queue with the given qid. + */ +static unsigned int rxq_to_chan(const struct sge *p, unsigned int qid) +{ + qid -= p->ingr_start; + return netdev2pinfo(p->ingr_map[qid]->netdev)->tx_chan; +} + +/* + * Wait until all NAPI handlers are descheduled. + */ +static void quiesce_rx(struct adapter *adap) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(adap->sge.ingr_map); i++) { + struct sge_rspq *q = adap->sge.ingr_map[i]; + + if (q && q->handler) + napi_disable(&q->napi); + } +} + +/* + * Enable NAPI scheduling and interrupt generation for all Rx queues. + */ +static void enable_rx(struct adapter *adap) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(adap->sge.ingr_map); i++) { + struct sge_rspq *q = adap->sge.ingr_map[i]; + + if (!q) + continue; + if (q->handler) + napi_enable(&q->napi); + /* 0-increment GTS to start the timer and enable interrupts */ + t4_write_reg(adap, MYPF_REG(SGE_PF_GTS), + SEINTARM(q->intr_params) | + INGRESSQID(q->cntxt_id)); + } +} + +/** + * setup_sge_queues - configure SGE Tx/Rx/response queues + * @adap: the adapter + * + * Determines how many sets of SGE queues to use and initializes them. + * We support multiple queue sets per port if we have MSI-X, otherwise + * just one queue set per port. + */ +static int setup_sge_queues(struct adapter *adap) +{ + int err, msi_idx, i, j; + struct sge *s = &adap->sge; + + bitmap_zero(s->starving_fl, MAX_EGRQ); + bitmap_zero(s->txq_maperr, MAX_EGRQ); + + if (adap->flags & USING_MSIX) + msi_idx = 1; /* vector 0 is for non-queue interrupts */ + else { + err = t4_sge_alloc_rxq(adap, &s->intrq, false, adap->port[0], 0, + NULL, NULL); + if (err) + return err; + msi_idx = -((int)s->intrq.abs_id + 1); + } + + err = t4_sge_alloc_rxq(adap, &s->fw_evtq, true, adap->port[0], + msi_idx, NULL, fwevtq_handler); + if (err) { +freeout: t4_free_sge_resources(adap); + return err; + } + + for_each_port(adap, i) { + struct net_device *dev = adap->port[i]; + struct port_info *pi = netdev_priv(dev); + struct sge_eth_rxq *q = &s->ethrxq[pi->first_qset]; + struct sge_eth_txq *t = &s->ethtxq[pi->first_qset]; + + for (j = 0; j < pi->nqsets; j++, q++) { + if (msi_idx > 0) + msi_idx++; + err = t4_sge_alloc_rxq(adap, &q->rspq, false, dev, + msi_idx, &q->fl, + t4_ethrx_handler); + if (err) + goto freeout; + q->rspq.idx = j; + memset(&q->stats, 0, sizeof(q->stats)); + } + for (j = 0; j < pi->nqsets; j++, t++) { + err = t4_sge_alloc_eth_txq(adap, t, dev, + netdev_get_tx_queue(dev, j), + s->fw_evtq.cntxt_id); + if (err) + goto freeout; + } + } + + j = s->ofldqsets / adap->params.nports; /* ofld queues per channel */ + for_each_ofldrxq(s, i) { + struct sge_ofld_rxq *q = &s->ofldrxq[i]; + struct net_device *dev = adap->port[i / j]; + + if (msi_idx > 0) + msi_idx++; + err = t4_sge_alloc_rxq(adap, &q->rspq, false, dev, msi_idx, + &q->fl, uldrx_handler); + if (err) + goto freeout; + memset(&q->stats, 0, sizeof(q->stats)); + s->ofld_rxq[i] = q->rspq.abs_id; + err = t4_sge_alloc_ofld_txq(adap, &s->ofldtxq[i], dev, + s->fw_evtq.cntxt_id); + if (err) + goto freeout; + } + + for_each_rdmarxq(s, i) { + struct sge_ofld_rxq *q = &s->rdmarxq[i]; + + if (msi_idx > 0) + msi_idx++; + err = t4_sge_alloc_rxq(adap, &q->rspq, false, adap->port[i], + msi_idx, &q->fl, uldrx_handler); + if (err) + goto freeout; + memset(&q->stats, 0, sizeof(q->stats)); + s->rdma_rxq[i] = q->rspq.abs_id; + } + + for_each_port(adap, i) { + /* + * Note that ->rdmarxq[i].rspq.cntxt_id below is 0 if we don't + * have RDMA queues, and that's the right value. + */ + err = t4_sge_alloc_ctrl_txq(adap, &s->ctrlq[i], adap->port[i], + s->fw_evtq.cntxt_id, + s->rdmarxq[i].rspq.cntxt_id); + if (err) + goto freeout; + } + + t4_write_reg(adap, MPS_TRC_RSS_CONTROL, + RSSCONTROL(netdev2pinfo(adap->port[0])->tx_chan) | + QUEUENUMBER(s->ethrxq[0].rspq.abs_id)); + return 0; +} + +/* + * Returns 0 if new FW was successfully loaded, a positive errno if a load was + * started but failed, and a negative errno if flash load couldn't start. + */ +static int upgrade_fw(struct adapter *adap) +{ + int ret; + u32 vers; + const struct fw_hdr *hdr; + const struct firmware *fw; + struct device *dev = adap->pdev_dev; + + ret = request_firmware(&fw, FW_FNAME, dev); + if (ret < 0) { + dev_err(dev, "unable to load firmware image " FW_FNAME + ", error %d\n", ret); + return ret; + } + + hdr = (const struct fw_hdr *)fw->data; + vers = ntohl(hdr->fw_ver); + if (FW_HDR_FW_VER_MAJOR_GET(vers) != FW_VERSION_MAJOR) { + ret = -EINVAL; /* wrong major version, won't do */ + goto out; + } + + /* + * If the flash FW is unusable or we found something newer, load it. + */ + if (FW_HDR_FW_VER_MAJOR_GET(adap->params.fw_vers) != FW_VERSION_MAJOR || + vers > adap->params.fw_vers) { + ret = -t4_load_fw(adap, fw->data, fw->size); + if (!ret) + dev_info(dev, "firmware upgraded to version %pI4 from " + FW_FNAME "\n", &hdr->fw_ver); + } +out: release_firmware(fw); + return ret; +} + +/* + * Allocate a chunk of memory using kmalloc or, if that fails, vmalloc. + * The allocated memory is cleared. + */ +void *t4_alloc_mem(size_t size) +{ + void *p = kzalloc(size, GFP_KERNEL); + + if (!p) + p = vzalloc(size); + return p; +} + +/* + * Free memory allocated through alloc_mem(). + */ +static void t4_free_mem(void *addr) +{ + if (is_vmalloc_addr(addr)) + vfree(addr); + else + kfree(addr); +} + +static inline int is_offload(const struct adapter *adap) +{ + return adap->params.offload; +} + +/* + * Implementation of ethtool operations. + */ + +static u32 get_msglevel(struct net_device *dev) +{ + return netdev2adap(dev)->msg_enable; +} + +static void set_msglevel(struct net_device *dev, u32 val) +{ + netdev2adap(dev)->msg_enable = val; +} + +static char stats_strings[][ETH_GSTRING_LEN] = { + "TxOctetsOK ", + "TxFramesOK ", + "TxBroadcastFrames ", + "TxMulticastFrames ", + "TxUnicastFrames ", + "TxErrorFrames ", + + "TxFrames64 ", + "TxFrames65To127 ", + "TxFrames128To255 ", + "TxFrames256To511 ", + "TxFrames512To1023 ", + "TxFrames1024To1518 ", + "TxFrames1519ToMax ", + + "TxFramesDropped ", + "TxPauseFrames ", + "TxPPP0Frames ", + "TxPPP1Frames ", + "TxPPP2Frames ", + "TxPPP3Frames ", + "TxPPP4Frames ", + "TxPPP5Frames ", + "TxPPP6Frames ", + "TxPPP7Frames ", + + "RxOctetsOK ", + "RxFramesOK ", + "RxBroadcastFrames ", + "RxMulticastFrames ", + "RxUnicastFrames ", + + "RxFramesTooLong ", + "RxJabberErrors ", + "RxFCSErrors ", + "RxLengthErrors ", + "RxSymbolErrors ", + "RxRuntFrames ", + + "RxFrames64 ", + "RxFrames65To127 ", + "RxFrames128To255 ", + "RxFrames256To511 ", + "RxFrames512To1023 ", + "RxFrames1024To1518 ", + "RxFrames1519ToMax ", + + "RxPauseFrames ", + "RxPPP0Frames ", + "RxPPP1Frames ", + "RxPPP2Frames ", + "RxPPP3Frames ", + "RxPPP4Frames ", + "RxPPP5Frames ", + "RxPPP6Frames ", + "RxPPP7Frames ", + + "RxBG0FramesDropped ", + "RxBG1FramesDropped ", + "RxBG2FramesDropped ", + "RxBG3FramesDropped ", + "RxBG0FramesTrunc ", + "RxBG1FramesTrunc ", + "RxBG2FramesTrunc ", + "RxBG3FramesTrunc ", + + "TSO ", + "TxCsumOffload ", + "RxCsumGood ", + "VLANextractions ", + "VLANinsertions ", + "GROpackets ", + "GROmerged ", +}; + +static int get_sset_count(struct net_device *dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(stats_strings); + default: + return -EOPNOTSUPP; + } +} + +#define T4_REGMAP_SIZE (160 * 1024) + +static int get_regs_len(struct net_device *dev) +{ + return T4_REGMAP_SIZE; +} + +static int get_eeprom_len(struct net_device *dev) +{ + return EEPROMSIZE; +} + +static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + struct adapter *adapter = netdev2adap(dev); + + strcpy(info->driver, KBUILD_MODNAME); + strcpy(info->version, DRV_VERSION); + strcpy(info->bus_info, pci_name(adapter->pdev)); + + if (!adapter->params.fw_vers) + strcpy(info->fw_version, "N/A"); + else + snprintf(info->fw_version, sizeof(info->fw_version), + "%u.%u.%u.%u, TP %u.%u.%u.%u", + FW_HDR_FW_VER_MAJOR_GET(adapter->params.fw_vers), + FW_HDR_FW_VER_MINOR_GET(adapter->params.fw_vers), + FW_HDR_FW_VER_MICRO_GET(adapter->params.fw_vers), + FW_HDR_FW_VER_BUILD_GET(adapter->params.fw_vers), + FW_HDR_FW_VER_MAJOR_GET(adapter->params.tp_vers), + FW_HDR_FW_VER_MINOR_GET(adapter->params.tp_vers), + FW_HDR_FW_VER_MICRO_GET(adapter->params.tp_vers), + FW_HDR_FW_VER_BUILD_GET(adapter->params.tp_vers)); +} + +static void get_strings(struct net_device *dev, u32 stringset, u8 *data) +{ + if (stringset == ETH_SS_STATS) + memcpy(data, stats_strings, sizeof(stats_strings)); +} + +/* + * port stats maintained per queue of the port. They should be in the same + * order as in stats_strings above. + */ +struct queue_port_stats { + u64 tso; + u64 tx_csum; + u64 rx_csum; + u64 vlan_ex; + u64 vlan_ins; + u64 gro_pkts; + u64 gro_merged; +}; + +static void collect_sge_port_stats(const struct adapter *adap, + const struct port_info *p, struct queue_port_stats *s) +{ + int i; + const struct sge_eth_txq *tx = &adap->sge.ethtxq[p->first_qset]; + const struct sge_eth_rxq *rx = &adap->sge.ethrxq[p->first_qset]; + + memset(s, 0, sizeof(*s)); + for (i = 0; i < p->nqsets; i++, rx++, tx++) { + s->tso += tx->tso; + s->tx_csum += tx->tx_cso; + s->rx_csum += rx->stats.rx_cso; + s->vlan_ex += rx->stats.vlan_ex; + s->vlan_ins += tx->vlan_ins; + s->gro_pkts += rx->stats.lro_pkts; + s->gro_merged += rx->stats.lro_merged; + } +} + +static void get_stats(struct net_device *dev, struct ethtool_stats *stats, + u64 *data) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + + t4_get_port_stats(adapter, pi->tx_chan, (struct port_stats *)data); + + data += sizeof(struct port_stats) / sizeof(u64); + collect_sge_port_stats(adapter, pi, (struct queue_port_stats *)data); +} + +/* + * Return a version number to identify the type of adapter. The scheme is: + * - bits 0..9: chip version + * - bits 10..15: chip revision + * - bits 16..23: register dump version + */ +static inline unsigned int mk_adap_vers(const struct adapter *ap) +{ + return 4 | (ap->params.rev << 10) | (1 << 16); +} + +static void reg_block_dump(struct adapter *ap, void *buf, unsigned int start, + unsigned int end) +{ + u32 *p = buf + start; + + for ( ; start <= end; start += sizeof(u32)) + *p++ = t4_read_reg(ap, start); +} + +static void get_regs(struct net_device *dev, struct ethtool_regs *regs, + void *buf) +{ + static const unsigned int reg_ranges[] = { + 0x1008, 0x1108, + 0x1180, 0x11b4, + 0x11fc, 0x123c, + 0x1300, 0x173c, + 0x1800, 0x18fc, + 0x3000, 0x30d8, + 0x30e0, 0x5924, + 0x5960, 0x59d4, + 0x5a00, 0x5af8, + 0x6000, 0x6098, + 0x6100, 0x6150, + 0x6200, 0x6208, + 0x6240, 0x6248, + 0x6280, 0x6338, + 0x6370, 0x638c, + 0x6400, 0x643c, + 0x6500, 0x6524, + 0x6a00, 0x6a38, + 0x6a60, 0x6a78, + 0x6b00, 0x6b84, + 0x6bf0, 0x6c84, + 0x6cf0, 0x6d84, + 0x6df0, 0x6e84, + 0x6ef0, 0x6f84, + 0x6ff0, 0x7084, + 0x70f0, 0x7184, + 0x71f0, 0x7284, + 0x72f0, 0x7384, + 0x73f0, 0x7450, + 0x7500, 0x7530, + 0x7600, 0x761c, + 0x7680, 0x76cc, + 0x7700, 0x7798, + 0x77c0, 0x77fc, + 0x7900, 0x79fc, + 0x7b00, 0x7c38, + 0x7d00, 0x7efc, + 0x8dc0, 0x8e1c, + 0x8e30, 0x8e78, + 0x8ea0, 0x8f6c, + 0x8fc0, 0x9074, + 0x90fc, 0x90fc, + 0x9400, 0x9458, + 0x9600, 0x96bc, + 0x9800, 0x9808, + 0x9820, 0x983c, + 0x9850, 0x9864, + 0x9c00, 0x9c6c, + 0x9c80, 0x9cec, + 0x9d00, 0x9d6c, + 0x9d80, 0x9dec, + 0x9e00, 0x9e6c, + 0x9e80, 0x9eec, + 0x9f00, 0x9f6c, + 0x9f80, 0x9fec, + 0xd004, 0xd03c, + 0xdfc0, 0xdfe0, + 0xe000, 0xea7c, + 0xf000, 0x11190, + 0x19040, 0x1906c, + 0x19078, 0x19080, + 0x1908c, 0x19124, + 0x19150, 0x191b0, + 0x191d0, 0x191e8, + 0x19238, 0x1924c, + 0x193f8, 0x19474, + 0x19490, 0x194f8, + 0x19800, 0x19f30, + 0x1a000, 0x1a06c, + 0x1a0b0, 0x1a120, + 0x1a128, 0x1a138, + 0x1a190, 0x1a1c4, + 0x1a1fc, 0x1a1fc, + 0x1e040, 0x1e04c, + 0x1e284, 0x1e28c, + 0x1e2c0, 0x1e2c0, + 0x1e2e0, 0x1e2e0, + 0x1e300, 0x1e384, + 0x1e3c0, 0x1e3c8, + 0x1e440, 0x1e44c, + 0x1e684, 0x1e68c, + 0x1e6c0, 0x1e6c0, + 0x1e6e0, 0x1e6e0, + 0x1e700, 0x1e784, + 0x1e7c0, 0x1e7c8, + 0x1e840, 0x1e84c, + 0x1ea84, 0x1ea8c, + 0x1eac0, 0x1eac0, + 0x1eae0, 0x1eae0, + 0x1eb00, 0x1eb84, + 0x1ebc0, 0x1ebc8, + 0x1ec40, 0x1ec4c, + 0x1ee84, 0x1ee8c, + 0x1eec0, 0x1eec0, + 0x1eee0, 0x1eee0, + 0x1ef00, 0x1ef84, + 0x1efc0, 0x1efc8, + 0x1f040, 0x1f04c, + 0x1f284, 0x1f28c, + 0x1f2c0, 0x1f2c0, + 0x1f2e0, 0x1f2e0, + 0x1f300, 0x1f384, + 0x1f3c0, 0x1f3c8, + 0x1f440, 0x1f44c, + 0x1f684, 0x1f68c, + 0x1f6c0, 0x1f6c0, + 0x1f6e0, 0x1f6e0, + 0x1f700, 0x1f784, + 0x1f7c0, 0x1f7c8, + 0x1f840, 0x1f84c, + 0x1fa84, 0x1fa8c, + 0x1fac0, 0x1fac0, + 0x1fae0, 0x1fae0, + 0x1fb00, 0x1fb84, + 0x1fbc0, 0x1fbc8, + 0x1fc40, 0x1fc4c, + 0x1fe84, 0x1fe8c, + 0x1fec0, 0x1fec0, + 0x1fee0, 0x1fee0, + 0x1ff00, 0x1ff84, + 0x1ffc0, 0x1ffc8, + 0x20000, 0x2002c, + 0x20100, 0x2013c, + 0x20190, 0x201c8, + 0x20200, 0x20318, + 0x20400, 0x20528, + 0x20540, 0x20614, + 0x21000, 0x21040, + 0x2104c, 0x21060, + 0x210c0, 0x210ec, + 0x21200, 0x21268, + 0x21270, 0x21284, + 0x212fc, 0x21388, + 0x21400, 0x21404, + 0x21500, 0x21518, + 0x2152c, 0x2153c, + 0x21550, 0x21554, + 0x21600, 0x21600, + 0x21608, 0x21628, + 0x21630, 0x2163c, + 0x21700, 0x2171c, + 0x21780, 0x2178c, + 0x21800, 0x21c38, + 0x21c80, 0x21d7c, + 0x21e00, 0x21e04, + 0x22000, 0x2202c, + 0x22100, 0x2213c, + 0x22190, 0x221c8, + 0x22200, 0x22318, + 0x22400, 0x22528, + 0x22540, 0x22614, + 0x23000, 0x23040, + 0x2304c, 0x23060, + 0x230c0, 0x230ec, + 0x23200, 0x23268, + 0x23270, 0x23284, + 0x232fc, 0x23388, + 0x23400, 0x23404, + 0x23500, 0x23518, + 0x2352c, 0x2353c, + 0x23550, 0x23554, + 0x23600, 0x23600, + 0x23608, 0x23628, + 0x23630, 0x2363c, + 0x23700, 0x2371c, + 0x23780, 0x2378c, + 0x23800, 0x23c38, + 0x23c80, 0x23d7c, + 0x23e00, 0x23e04, + 0x24000, 0x2402c, + 0x24100, 0x2413c, + 0x24190, 0x241c8, + 0x24200, 0x24318, + 0x24400, 0x24528, + 0x24540, 0x24614, + 0x25000, 0x25040, + 0x2504c, 0x25060, + 0x250c0, 0x250ec, + 0x25200, 0x25268, + 0x25270, 0x25284, + 0x252fc, 0x25388, + 0x25400, 0x25404, + 0x25500, 0x25518, + 0x2552c, 0x2553c, + 0x25550, 0x25554, + 0x25600, 0x25600, + 0x25608, 0x25628, + 0x25630, 0x2563c, + 0x25700, 0x2571c, + 0x25780, 0x2578c, + 0x25800, 0x25c38, + 0x25c80, 0x25d7c, + 0x25e00, 0x25e04, + 0x26000, 0x2602c, + 0x26100, 0x2613c, + 0x26190, 0x261c8, + 0x26200, 0x26318, + 0x26400, 0x26528, + 0x26540, 0x26614, + 0x27000, 0x27040, + 0x2704c, 0x27060, + 0x270c0, 0x270ec, + 0x27200, 0x27268, + 0x27270, 0x27284, + 0x272fc, 0x27388, + 0x27400, 0x27404, + 0x27500, 0x27518, + 0x2752c, 0x2753c, + 0x27550, 0x27554, + 0x27600, 0x27600, + 0x27608, 0x27628, + 0x27630, 0x2763c, + 0x27700, 0x2771c, + 0x27780, 0x2778c, + 0x27800, 0x27c38, + 0x27c80, 0x27d7c, + 0x27e00, 0x27e04 + }; + + int i; + struct adapter *ap = netdev2adap(dev); + + regs->version = mk_adap_vers(ap); + + memset(buf, 0, T4_REGMAP_SIZE); + for (i = 0; i < ARRAY_SIZE(reg_ranges); i += 2) + reg_block_dump(ap, buf, reg_ranges[i], reg_ranges[i + 1]); +} + +static int restart_autoneg(struct net_device *dev) +{ + struct port_info *p = netdev_priv(dev); + + if (!netif_running(dev)) + return -EAGAIN; + if (p->link_cfg.autoneg != AUTONEG_ENABLE) + return -EINVAL; + t4_restart_aneg(p->adapter, p->adapter->fn, p->tx_chan); + return 0; +} + +static int identify_port(struct net_device *dev, + enum ethtool_phys_id_state state) +{ + unsigned int val; + struct adapter *adap = netdev2adap(dev); + + if (state == ETHTOOL_ID_ACTIVE) + val = 0xffff; + else if (state == ETHTOOL_ID_INACTIVE) + val = 0; + else + return -EINVAL; + + return t4_identify_port(adap, adap->fn, netdev2pinfo(dev)->viid, val); +} + +static unsigned int from_fw_linkcaps(unsigned int type, unsigned int caps) +{ + unsigned int v = 0; + + if (type == FW_PORT_TYPE_BT_SGMII || type == FW_PORT_TYPE_BT_XFI || + type == FW_PORT_TYPE_BT_XAUI) { + v |= SUPPORTED_TP; + if (caps & FW_PORT_CAP_SPEED_100M) + v |= SUPPORTED_100baseT_Full; + if (caps & FW_PORT_CAP_SPEED_1G) + v |= SUPPORTED_1000baseT_Full; + if (caps & FW_PORT_CAP_SPEED_10G) + v |= SUPPORTED_10000baseT_Full; + } else if (type == FW_PORT_TYPE_KX4 || type == FW_PORT_TYPE_KX) { + v |= SUPPORTED_Backplane; + if (caps & FW_PORT_CAP_SPEED_1G) + v |= SUPPORTED_1000baseKX_Full; + if (caps & FW_PORT_CAP_SPEED_10G) + v |= SUPPORTED_10000baseKX4_Full; + } else if (type == FW_PORT_TYPE_KR) + v |= SUPPORTED_Backplane | SUPPORTED_10000baseKR_Full; + else if (type == FW_PORT_TYPE_BP_AP) + v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC | + SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full; + else if (type == FW_PORT_TYPE_BP4_AP) + v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC | + SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full | + SUPPORTED_10000baseKX4_Full; + else if (type == FW_PORT_TYPE_FIBER_XFI || + type == FW_PORT_TYPE_FIBER_XAUI || type == FW_PORT_TYPE_SFP) + v |= SUPPORTED_FIBRE; + + if (caps & FW_PORT_CAP_ANEG) + v |= SUPPORTED_Autoneg; + return v; +} + +static unsigned int to_fw_linkcaps(unsigned int caps) +{ + unsigned int v = 0; + + if (caps & ADVERTISED_100baseT_Full) + v |= FW_PORT_CAP_SPEED_100M; + if (caps & ADVERTISED_1000baseT_Full) + v |= FW_PORT_CAP_SPEED_1G; + if (caps & ADVERTISED_10000baseT_Full) + v |= FW_PORT_CAP_SPEED_10G; + return v; +} + +static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + const struct port_info *p = netdev_priv(dev); + + if (p->port_type == FW_PORT_TYPE_BT_SGMII || + p->port_type == FW_PORT_TYPE_BT_XFI || + p->port_type == FW_PORT_TYPE_BT_XAUI) + cmd->port = PORT_TP; + else if (p->port_type == FW_PORT_TYPE_FIBER_XFI || + p->port_type == FW_PORT_TYPE_FIBER_XAUI) + cmd->port = PORT_FIBRE; + else if (p->port_type == FW_PORT_TYPE_SFP) { + if (p->mod_type == FW_PORT_MOD_TYPE_TWINAX_PASSIVE || + p->mod_type == FW_PORT_MOD_TYPE_TWINAX_ACTIVE) + cmd->port = PORT_DA; + else + cmd->port = PORT_FIBRE; + } else + cmd->port = PORT_OTHER; + + if (p->mdio_addr >= 0) { + cmd->phy_address = p->mdio_addr; + cmd->transceiver = XCVR_EXTERNAL; + cmd->mdio_support = p->port_type == FW_PORT_TYPE_BT_SGMII ? + MDIO_SUPPORTS_C22 : MDIO_SUPPORTS_C45; + } else { + cmd->phy_address = 0; /* not really, but no better option */ + cmd->transceiver = XCVR_INTERNAL; + cmd->mdio_support = 0; + } + + cmd->supported = from_fw_linkcaps(p->port_type, p->link_cfg.supported); + cmd->advertising = from_fw_linkcaps(p->port_type, + p->link_cfg.advertising); + ethtool_cmd_speed_set(cmd, + netif_carrier_ok(dev) ? p->link_cfg.speed : 0); + cmd->duplex = DUPLEX_FULL; + cmd->autoneg = p->link_cfg.autoneg; + cmd->maxtxpkt = 0; + cmd->maxrxpkt = 0; + return 0; +} + +static unsigned int speed_to_caps(int speed) +{ + if (speed == SPEED_100) + return FW_PORT_CAP_SPEED_100M; + if (speed == SPEED_1000) + return FW_PORT_CAP_SPEED_1G; + if (speed == SPEED_10000) + return FW_PORT_CAP_SPEED_10G; + return 0; +} + +static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + unsigned int cap; + struct port_info *p = netdev_priv(dev); + struct link_config *lc = &p->link_cfg; + u32 speed = ethtool_cmd_speed(cmd); + + if (cmd->duplex != DUPLEX_FULL) /* only full-duplex supported */ + return -EINVAL; + + if (!(lc->supported & FW_PORT_CAP_ANEG)) { + /* + * PHY offers a single speed. See if that's what's + * being requested. + */ + if (cmd->autoneg == AUTONEG_DISABLE && + (lc->supported & speed_to_caps(speed))) + return 0; + return -EINVAL; + } + + if (cmd->autoneg == AUTONEG_DISABLE) { + cap = speed_to_caps(speed); + + if (!(lc->supported & cap) || (speed == SPEED_1000) || + (speed == SPEED_10000)) + return -EINVAL; + lc->requested_speed = cap; + lc->advertising = 0; + } else { + cap = to_fw_linkcaps(cmd->advertising); + if (!(lc->supported & cap)) + return -EINVAL; + lc->requested_speed = 0; + lc->advertising = cap | FW_PORT_CAP_ANEG; + } + lc->autoneg = cmd->autoneg; + + if (netif_running(dev)) + return t4_link_start(p->adapter, p->adapter->fn, p->tx_chan, + lc); + return 0; +} + +static void get_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *epause) +{ + struct port_info *p = netdev_priv(dev); + + epause->autoneg = (p->link_cfg.requested_fc & PAUSE_AUTONEG) != 0; + epause->rx_pause = (p->link_cfg.fc & PAUSE_RX) != 0; + epause->tx_pause = (p->link_cfg.fc & PAUSE_TX) != 0; +} + +static int set_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *epause) +{ + struct port_info *p = netdev_priv(dev); + struct link_config *lc = &p->link_cfg; + + if (epause->autoneg == AUTONEG_DISABLE) + lc->requested_fc = 0; + else if (lc->supported & FW_PORT_CAP_ANEG) + lc->requested_fc = PAUSE_AUTONEG; + else + return -EINVAL; + + if (epause->rx_pause) + lc->requested_fc |= PAUSE_RX; + if (epause->tx_pause) + lc->requested_fc |= PAUSE_TX; + if (netif_running(dev)) + return t4_link_start(p->adapter, p->adapter->fn, p->tx_chan, + lc); + return 0; +} + +static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) +{ + const struct port_info *pi = netdev_priv(dev); + const struct sge *s = &pi->adapter->sge; + + e->rx_max_pending = MAX_RX_BUFFERS; + e->rx_mini_max_pending = MAX_RSPQ_ENTRIES; + e->rx_jumbo_max_pending = 0; + e->tx_max_pending = MAX_TXQ_ENTRIES; + + e->rx_pending = s->ethrxq[pi->first_qset].fl.size - 8; + e->rx_mini_pending = s->ethrxq[pi->first_qset].rspq.size; + e->rx_jumbo_pending = 0; + e->tx_pending = s->ethtxq[pi->first_qset].q.size; +} + +static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e) +{ + int i; + const struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + struct sge *s = &adapter->sge; + + if (e->rx_pending > MAX_RX_BUFFERS || e->rx_jumbo_pending || + e->tx_pending > MAX_TXQ_ENTRIES || + e->rx_mini_pending > MAX_RSPQ_ENTRIES || + e->rx_mini_pending < MIN_RSPQ_ENTRIES || + e->rx_pending < MIN_FL_ENTRIES || e->tx_pending < MIN_TXQ_ENTRIES) + return -EINVAL; + + if (adapter->flags & FULL_INIT_DONE) + return -EBUSY; + + for (i = 0; i < pi->nqsets; ++i) { + s->ethtxq[pi->first_qset + i].q.size = e->tx_pending; + s->ethrxq[pi->first_qset + i].fl.size = e->rx_pending + 8; + s->ethrxq[pi->first_qset + i].rspq.size = e->rx_mini_pending; + } + return 0; +} + +static int closest_timer(const struct sge *s, int time) +{ + int i, delta, match = 0, min_delta = INT_MAX; + + for (i = 0; i < ARRAY_SIZE(s->timer_val); i++) { + delta = time - s->timer_val[i]; + if (delta < 0) + delta = -delta; + if (delta < min_delta) { + min_delta = delta; + match = i; + } + } + return match; +} + +static int closest_thres(const struct sge *s, int thres) +{ + int i, delta, match = 0, min_delta = INT_MAX; + + for (i = 0; i < ARRAY_SIZE(s->counter_val); i++) { + delta = thres - s->counter_val[i]; + if (delta < 0) + delta = -delta; + if (delta < min_delta) { + min_delta = delta; + match = i; + } + } + return match; +} + +/* + * Return a queue's interrupt hold-off time in us. 0 means no timer. + */ +static unsigned int qtimer_val(const struct adapter *adap, + const struct sge_rspq *q) +{ + unsigned int idx = q->intr_params >> 1; + + return idx < SGE_NTIMERS ? adap->sge.timer_val[idx] : 0; +} + +/** + * set_rxq_intr_params - set a queue's interrupt holdoff parameters + * @adap: the adapter + * @q: the Rx queue + * @us: the hold-off time in us, or 0 to disable timer + * @cnt: the hold-off packet count, or 0 to disable counter + * + * Sets an Rx queue's interrupt hold-off time and packet count. At least + * one of the two needs to be enabled for the queue to generate interrupts. + */ +static int set_rxq_intr_params(struct adapter *adap, struct sge_rspq *q, + unsigned int us, unsigned int cnt) +{ + if ((us | cnt) == 0) + cnt = 1; + + if (cnt) { + int err; + u32 v, new_idx; + + new_idx = closest_thres(&adap->sge, cnt); + if (q->desc && q->pktcnt_idx != new_idx) { + /* the queue has already been created, update it */ + v = FW_PARAMS_MNEM(FW_PARAMS_MNEM_DMAQ) | + FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DMAQ_IQ_INTCNTTHRESH) | + FW_PARAMS_PARAM_YZ(q->cntxt_id); + err = t4_set_params(adap, adap->fn, adap->fn, 0, 1, &v, + &new_idx); + if (err) + return err; + } + q->pktcnt_idx = new_idx; + } + + us = us == 0 ? 6 : closest_timer(&adap->sge, us); + q->intr_params = QINTR_TIMER_IDX(us) | (cnt > 0 ? QINTR_CNT_EN : 0); + return 0; +} + +static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c) +{ + const struct port_info *pi = netdev_priv(dev); + struct adapter *adap = pi->adapter; + + return set_rxq_intr_params(adap, &adap->sge.ethrxq[pi->first_qset].rspq, + c->rx_coalesce_usecs, c->rx_max_coalesced_frames); +} + +static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c) +{ + const struct port_info *pi = netdev_priv(dev); + const struct adapter *adap = pi->adapter; + const struct sge_rspq *rq = &adap->sge.ethrxq[pi->first_qset].rspq; + + c->rx_coalesce_usecs = qtimer_val(adap, rq); + c->rx_max_coalesced_frames = (rq->intr_params & QINTR_CNT_EN) ? + adap->sge.counter_val[rq->pktcnt_idx] : 0; + return 0; +} + +/** + * eeprom_ptov - translate a physical EEPROM address to virtual + * @phys_addr: the physical EEPROM address + * @fn: the PCI function number + * @sz: size of function-specific area + * + * Translate a physical EEPROM address to virtual. The first 1K is + * accessed through virtual addresses starting at 31K, the rest is + * accessed through virtual addresses starting at 0. + * + * The mapping is as follows: + * [0..1K) -> [31K..32K) + * [1K..1K+A) -> [31K-A..31K) + * [1K+A..ES) -> [0..ES-A-1K) + * + * where A = @fn * @sz, and ES = EEPROM size. + */ +static int eeprom_ptov(unsigned int phys_addr, unsigned int fn, unsigned int sz) +{ + fn *= sz; + if (phys_addr < 1024) + return phys_addr + (31 << 10); + if (phys_addr < 1024 + fn) + return 31744 - fn + phys_addr - 1024; + if (phys_addr < EEPROMSIZE) + return phys_addr - 1024 - fn; + return -EINVAL; +} + +/* + * The next two routines implement eeprom read/write from physical addresses. + */ +static int eeprom_rd_phys(struct adapter *adap, unsigned int phys_addr, u32 *v) +{ + int vaddr = eeprom_ptov(phys_addr, adap->fn, EEPROMPFSIZE); + + if (vaddr >= 0) + vaddr = pci_read_vpd(adap->pdev, vaddr, sizeof(u32), v); + return vaddr < 0 ? vaddr : 0; +} + +static int eeprom_wr_phys(struct adapter *adap, unsigned int phys_addr, u32 v) +{ + int vaddr = eeprom_ptov(phys_addr, adap->fn, EEPROMPFSIZE); + + if (vaddr >= 0) + vaddr = pci_write_vpd(adap->pdev, vaddr, sizeof(u32), &v); + return vaddr < 0 ? vaddr : 0; +} + +#define EEPROM_MAGIC 0x38E2F10C + +static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e, + u8 *data) +{ + int i, err = 0; + struct adapter *adapter = netdev2adap(dev); + + u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + e->magic = EEPROM_MAGIC; + for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4) + err = eeprom_rd_phys(adapter, i, (u32 *)&buf[i]); + + if (!err) + memcpy(data, buf + e->offset, e->len); + kfree(buf); + return err; +} + +static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, + u8 *data) +{ + u8 *buf; + int err = 0; + u32 aligned_offset, aligned_len, *p; + struct adapter *adapter = netdev2adap(dev); + + if (eeprom->magic != EEPROM_MAGIC) + return -EINVAL; + + aligned_offset = eeprom->offset & ~3; + aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3; + + if (adapter->fn > 0) { + u32 start = 1024 + adapter->fn * EEPROMPFSIZE; + + if (aligned_offset < start || + aligned_offset + aligned_len > start + EEPROMPFSIZE) + return -EPERM; + } + + if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) { + /* + * RMW possibly needed for first or last words. + */ + buf = kmalloc(aligned_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + err = eeprom_rd_phys(adapter, aligned_offset, (u32 *)buf); + if (!err && aligned_len > 4) + err = eeprom_rd_phys(adapter, + aligned_offset + aligned_len - 4, + (u32 *)&buf[aligned_len - 4]); + if (err) + goto out; + memcpy(buf + (eeprom->offset & 3), data, eeprom->len); + } else + buf = data; + + err = t4_seeprom_wp(adapter, false); + if (err) + goto out; + + for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) { + err = eeprom_wr_phys(adapter, aligned_offset, *p); + aligned_offset += 4; + } + + if (!err) + err = t4_seeprom_wp(adapter, true); +out: + if (buf != data) + kfree(buf); + return err; +} + +static int set_flash(struct net_device *netdev, struct ethtool_flash *ef) +{ + int ret; + const struct firmware *fw; + struct adapter *adap = netdev2adap(netdev); + + ef->data[sizeof(ef->data) - 1] = '\0'; + ret = request_firmware(&fw, ef->data, adap->pdev_dev); + if (ret < 0) + return ret; + + ret = t4_load_fw(adap, fw->data, fw->size); + release_firmware(fw); + if (!ret) + dev_info(adap->pdev_dev, "loaded firmware %s\n", ef->data); + return ret; +} + +#define WOL_SUPPORTED (WAKE_BCAST | WAKE_MAGIC) +#define BCAST_CRC 0xa0ccc1a6 + +static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + wol->supported = WAKE_BCAST | WAKE_MAGIC; + wol->wolopts = netdev2adap(dev)->wol; + memset(&wol->sopass, 0, sizeof(wol->sopass)); +} + +static int set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + int err = 0; + struct port_info *pi = netdev_priv(dev); + + if (wol->wolopts & ~WOL_SUPPORTED) + return -EINVAL; + t4_wol_magic_enable(pi->adapter, pi->tx_chan, + (wol->wolopts & WAKE_MAGIC) ? dev->dev_addr : NULL); + if (wol->wolopts & WAKE_BCAST) { + err = t4_wol_pat_enable(pi->adapter, pi->tx_chan, 0xfe, ~0ULL, + ~0ULL, 0, false); + if (!err) + err = t4_wol_pat_enable(pi->adapter, pi->tx_chan, 1, + ~6ULL, ~0ULL, BCAST_CRC, true); + } else + t4_wol_pat_enable(pi->adapter, pi->tx_chan, 0, 0, 0, 0, false); + return err; +} + +static int cxgb_set_features(struct net_device *dev, u32 features) +{ + const struct port_info *pi = netdev_priv(dev); + u32 changed = dev->features ^ features; + int err; + + if (!(changed & NETIF_F_HW_VLAN_RX)) + return 0; + + err = t4_set_rxmode(pi->adapter, pi->adapter->fn, pi->viid, -1, + -1, -1, -1, + !!(features & NETIF_F_HW_VLAN_RX), true); + if (unlikely(err)) + dev->features = features ^ NETIF_F_HW_VLAN_RX; + return err; +} + +static int get_rss_table(struct net_device *dev, struct ethtool_rxfh_indir *p) +{ + const struct port_info *pi = netdev_priv(dev); + unsigned int n = min_t(unsigned int, p->size, pi->rss_size); + + p->size = pi->rss_size; + while (n--) + p->ring_index[n] = pi->rss[n]; + return 0; +} + +static int set_rss_table(struct net_device *dev, + const struct ethtool_rxfh_indir *p) +{ + unsigned int i; + struct port_info *pi = netdev_priv(dev); + + if (p->size != pi->rss_size) + return -EINVAL; + for (i = 0; i < p->size; i++) + if (p->ring_index[i] >= pi->nqsets) + return -EINVAL; + for (i = 0; i < p->size; i++) + pi->rss[i] = p->ring_index[i]; + if (pi->adapter->flags & FULL_INIT_DONE) + return write_rss(pi, pi->rss); + return 0; +} + +static int get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, + void *rules) +{ + const struct port_info *pi = netdev_priv(dev); + + switch (info->cmd) { + case ETHTOOL_GRXFH: { + unsigned int v = pi->rss_mode; + + info->data = 0; + switch (info->flow_type) { + case TCP_V4_FLOW: + if (v & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN) + info->data = RXH_IP_SRC | RXH_IP_DST | + RXH_L4_B_0_1 | RXH_L4_B_2_3; + else if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN) + info->data = RXH_IP_SRC | RXH_IP_DST; + break; + case UDP_V4_FLOW: + if ((v & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN) && + (v & FW_RSS_VI_CONFIG_CMD_UDPEN)) + info->data = RXH_IP_SRC | RXH_IP_DST | + RXH_L4_B_0_1 | RXH_L4_B_2_3; + else if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN) + info->data = RXH_IP_SRC | RXH_IP_DST; + break; + case SCTP_V4_FLOW: + case AH_ESP_V4_FLOW: + case IPV4_FLOW: + if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN) + info->data = RXH_IP_SRC | RXH_IP_DST; + break; + case TCP_V6_FLOW: + if (v & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN) + info->data = RXH_IP_SRC | RXH_IP_DST | + RXH_L4_B_0_1 | RXH_L4_B_2_3; + else if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN) + info->data = RXH_IP_SRC | RXH_IP_DST; + break; + case UDP_V6_FLOW: + if ((v & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN) && + (v & FW_RSS_VI_CONFIG_CMD_UDPEN)) + info->data = RXH_IP_SRC | RXH_IP_DST | + RXH_L4_B_0_1 | RXH_L4_B_2_3; + else if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN) + info->data = RXH_IP_SRC | RXH_IP_DST; + break; + case SCTP_V6_FLOW: + case AH_ESP_V6_FLOW: + case IPV6_FLOW: + if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN) + info->data = RXH_IP_SRC | RXH_IP_DST; + break; + } + return 0; + } + case ETHTOOL_GRXRINGS: + info->data = pi->nqsets; + return 0; + } + return -EOPNOTSUPP; +} + +static struct ethtool_ops cxgb_ethtool_ops = { + .get_settings = get_settings, + .set_settings = set_settings, + .get_drvinfo = get_drvinfo, + .get_msglevel = get_msglevel, + .set_msglevel = set_msglevel, + .get_ringparam = get_sge_param, + .set_ringparam = set_sge_param, + .get_coalesce = get_coalesce, + .set_coalesce = set_coalesce, + .get_eeprom_len = get_eeprom_len, + .get_eeprom = get_eeprom, + .set_eeprom = set_eeprom, + .get_pauseparam = get_pauseparam, + .set_pauseparam = set_pauseparam, + .get_link = ethtool_op_get_link, + .get_strings = get_strings, + .set_phys_id = identify_port, + .nway_reset = restart_autoneg, + .get_sset_count = get_sset_count, + .get_ethtool_stats = get_stats, + .get_regs_len = get_regs_len, + .get_regs = get_regs, + .get_wol = get_wol, + .set_wol = set_wol, + .get_rxnfc = get_rxnfc, + .get_rxfh_indir = get_rss_table, + .set_rxfh_indir = set_rss_table, + .flash_device = set_flash, +}; + +/* + * debugfs support + */ + +static int mem_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t mem_read(struct file *file, char __user *buf, size_t count, + loff_t *ppos) +{ + loff_t pos = *ppos; + loff_t avail = file->f_path.dentry->d_inode->i_size; + unsigned int mem = (uintptr_t)file->private_data & 3; + struct adapter *adap = file->private_data - mem; + + if (pos < 0) + return -EINVAL; + if (pos >= avail) + return 0; + if (count > avail - pos) + count = avail - pos; + + while (count) { + size_t len; + int ret, ofst; + __be32 data[16]; + + if (mem == MEM_MC) + ret = t4_mc_read(adap, pos, data, NULL); + else + ret = t4_edc_read(adap, mem, pos, data, NULL); + if (ret) + return ret; + + ofst = pos % sizeof(data); + len = min(count, sizeof(data) - ofst); + if (copy_to_user(buf, (u8 *)data + ofst, len)) + return -EFAULT; + + buf += len; + pos += len; + count -= len; + } + count = pos - *ppos; + *ppos = pos; + return count; +} + +static const struct file_operations mem_debugfs_fops = { + .owner = THIS_MODULE, + .open = mem_open, + .read = mem_read, + .llseek = default_llseek, +}; + +static void __devinit add_debugfs_mem(struct adapter *adap, const char *name, + unsigned int idx, unsigned int size_mb) +{ + struct dentry *de; + + de = debugfs_create_file(name, S_IRUSR, adap->debugfs_root, + (void *)adap + idx, &mem_debugfs_fops); + if (de && de->d_inode) + de->d_inode->i_size = size_mb << 20; +} + +static int __devinit setup_debugfs(struct adapter *adap) +{ + int i; + + if (IS_ERR_OR_NULL(adap->debugfs_root)) + return -1; + + i = t4_read_reg(adap, MA_TARGET_MEM_ENABLE); + if (i & EDRAM0_ENABLE) + add_debugfs_mem(adap, "edc0", MEM_EDC0, 5); + if (i & EDRAM1_ENABLE) + add_debugfs_mem(adap, "edc1", MEM_EDC1, 5); + if (i & EXT_MEM_ENABLE) + add_debugfs_mem(adap, "mc", MEM_MC, + EXT_MEM_SIZE_GET(t4_read_reg(adap, MA_EXT_MEMORY_BAR))); + if (adap->l2t) + debugfs_create_file("l2t", S_IRUSR, adap->debugfs_root, adap, + &t4_l2t_fops); + return 0; +} + +/* + * upper-layer driver support + */ + +/* + * Allocate an active-open TID and set it to the supplied value. + */ +int cxgb4_alloc_atid(struct tid_info *t, void *data) +{ + int atid = -1; + + spin_lock_bh(&t->atid_lock); + if (t->afree) { + union aopen_entry *p = t->afree; + + atid = p - t->atid_tab; + t->afree = p->next; + p->data = data; + t->atids_in_use++; + } + spin_unlock_bh(&t->atid_lock); + return atid; +} +EXPORT_SYMBOL(cxgb4_alloc_atid); + +/* + * Release an active-open TID. + */ +void cxgb4_free_atid(struct tid_info *t, unsigned int atid) +{ + union aopen_entry *p = &t->atid_tab[atid]; + + spin_lock_bh(&t->atid_lock); + p->next = t->afree; + t->afree = p; + t->atids_in_use--; + spin_unlock_bh(&t->atid_lock); +} +EXPORT_SYMBOL(cxgb4_free_atid); + +/* + * Allocate a server TID and set it to the supplied value. + */ +int cxgb4_alloc_stid(struct tid_info *t, int family, void *data) +{ + int stid; + + spin_lock_bh(&t->stid_lock); + if (family == PF_INET) { + stid = find_first_zero_bit(t->stid_bmap, t->nstids); + if (stid < t->nstids) + __set_bit(stid, t->stid_bmap); + else + stid = -1; + } else { + stid = bitmap_find_free_region(t->stid_bmap, t->nstids, 2); + if (stid < 0) + stid = -1; + } + if (stid >= 0) { + t->stid_tab[stid].data = data; + stid += t->stid_base; + t->stids_in_use++; + } + spin_unlock_bh(&t->stid_lock); + return stid; +} +EXPORT_SYMBOL(cxgb4_alloc_stid); + +/* + * Release a server TID. + */ +void cxgb4_free_stid(struct tid_info *t, unsigned int stid, int family) +{ + stid -= t->stid_base; + spin_lock_bh(&t->stid_lock); + if (family == PF_INET) + __clear_bit(stid, t->stid_bmap); + else + bitmap_release_region(t->stid_bmap, stid, 2); + t->stid_tab[stid].data = NULL; + t->stids_in_use--; + spin_unlock_bh(&t->stid_lock); +} +EXPORT_SYMBOL(cxgb4_free_stid); + +/* + * Populate a TID_RELEASE WR. Caller must properly size the skb. + */ +static void mk_tid_release(struct sk_buff *skb, unsigned int chan, + unsigned int tid) +{ + struct cpl_tid_release *req; + + set_wr_txq(skb, CPL_PRIORITY_SETUP, chan); + req = (struct cpl_tid_release *)__skb_put(skb, sizeof(*req)); + INIT_TP_WR(req, tid); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, tid)); +} + +/* + * Queue a TID release request and if necessary schedule a work queue to + * process it. + */ +static void cxgb4_queue_tid_release(struct tid_info *t, unsigned int chan, + unsigned int tid) +{ + void **p = &t->tid_tab[tid]; + struct adapter *adap = container_of(t, struct adapter, tids); + + spin_lock_bh(&adap->tid_release_lock); + *p = adap->tid_release_head; + /* Low 2 bits encode the Tx channel number */ + adap->tid_release_head = (void **)((uintptr_t)p | chan); + if (!adap->tid_release_task_busy) { + adap->tid_release_task_busy = true; + schedule_work(&adap->tid_release_task); + } + spin_unlock_bh(&adap->tid_release_lock); +} + +/* + * Process the list of pending TID release requests. + */ +static void process_tid_release_list(struct work_struct *work) +{ + struct sk_buff *skb; + struct adapter *adap; + + adap = container_of(work, struct adapter, tid_release_task); + + spin_lock_bh(&adap->tid_release_lock); + while (adap->tid_release_head) { + void **p = adap->tid_release_head; + unsigned int chan = (uintptr_t)p & 3; + p = (void *)p - chan; + + adap->tid_release_head = *p; + *p = NULL; + spin_unlock_bh(&adap->tid_release_lock); + + while (!(skb = alloc_skb(sizeof(struct cpl_tid_release), + GFP_KERNEL))) + schedule_timeout_uninterruptible(1); + + mk_tid_release(skb, chan, p - adap->tids.tid_tab); + t4_ofld_send(adap, skb); + spin_lock_bh(&adap->tid_release_lock); + } + adap->tid_release_task_busy = false; + spin_unlock_bh(&adap->tid_release_lock); +} + +/* + * Release a TID and inform HW. If we are unable to allocate the release + * message we defer to a work queue. + */ +void cxgb4_remove_tid(struct tid_info *t, unsigned int chan, unsigned int tid) +{ + void *old; + struct sk_buff *skb; + struct adapter *adap = container_of(t, struct adapter, tids); + + old = t->tid_tab[tid]; + skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_ATOMIC); + if (likely(skb)) { + t->tid_tab[tid] = NULL; + mk_tid_release(skb, chan, tid); + t4_ofld_send(adap, skb); + } else + cxgb4_queue_tid_release(t, chan, tid); + if (old) + atomic_dec(&t->tids_in_use); +} +EXPORT_SYMBOL(cxgb4_remove_tid); + +/* + * Allocate and initialize the TID tables. Returns 0 on success. + */ +static int tid_init(struct tid_info *t) +{ + size_t size; + unsigned int natids = t->natids; + + size = t->ntids * sizeof(*t->tid_tab) + natids * sizeof(*t->atid_tab) + + t->nstids * sizeof(*t->stid_tab) + + BITS_TO_LONGS(t->nstids) * sizeof(long); + t->tid_tab = t4_alloc_mem(size); + if (!t->tid_tab) + return -ENOMEM; + + t->atid_tab = (union aopen_entry *)&t->tid_tab[t->ntids]; + t->stid_tab = (struct serv_entry *)&t->atid_tab[natids]; + t->stid_bmap = (unsigned long *)&t->stid_tab[t->nstids]; + spin_lock_init(&t->stid_lock); + spin_lock_init(&t->atid_lock); + + t->stids_in_use = 0; + t->afree = NULL; + t->atids_in_use = 0; + atomic_set(&t->tids_in_use, 0); + + /* Setup the free list for atid_tab and clear the stid bitmap. */ + if (natids) { + while (--natids) + t->atid_tab[natids - 1].next = &t->atid_tab[natids]; + t->afree = t->atid_tab; + } + bitmap_zero(t->stid_bmap, t->nstids); + return 0; +} + +/** + * cxgb4_create_server - create an IP server + * @dev: the device + * @stid: the server TID + * @sip: local IP address to bind server to + * @sport: the server's TCP port + * @queue: queue to direct messages from this server to + * + * Create an IP server for the given port and address. + * Returns <0 on error and one of the %NET_XMIT_* values on success. + */ +int cxgb4_create_server(const struct net_device *dev, unsigned int stid, + __be32 sip, __be16 sport, unsigned int queue) +{ + unsigned int chan; + struct sk_buff *skb; + struct adapter *adap; + struct cpl_pass_open_req *req; + + skb = alloc_skb(sizeof(*req), GFP_KERNEL); + if (!skb) + return -ENOMEM; + + adap = netdev2adap(dev); + req = (struct cpl_pass_open_req *)__skb_put(skb, sizeof(*req)); + INIT_TP_WR(req, 0); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_PASS_OPEN_REQ, stid)); + req->local_port = sport; + req->peer_port = htons(0); + req->local_ip = sip; + req->peer_ip = htonl(0); + chan = rxq_to_chan(&adap->sge, queue); + req->opt0 = cpu_to_be64(TX_CHAN(chan)); + req->opt1 = cpu_to_be64(CONN_POLICY_ASK | + SYN_RSS_ENABLE | SYN_RSS_QUEUE(queue)); + return t4_mgmt_tx(adap, skb); +} +EXPORT_SYMBOL(cxgb4_create_server); + +/** + * cxgb4_best_mtu - find the entry in the MTU table closest to an MTU + * @mtus: the HW MTU table + * @mtu: the target MTU + * @idx: index of selected entry in the MTU table + * + * Returns the index and the value in the HW MTU table that is closest to + * but does not exceed @mtu, unless @mtu is smaller than any value in the + * table, in which case that smallest available value is selected. + */ +unsigned int cxgb4_best_mtu(const unsigned short *mtus, unsigned short mtu, + unsigned int *idx) +{ + unsigned int i = 0; + + while (i < NMTUS - 1 && mtus[i + 1] <= mtu) + ++i; + if (idx) + *idx = i; + return mtus[i]; +} +EXPORT_SYMBOL(cxgb4_best_mtu); + +/** + * cxgb4_port_chan - get the HW channel of a port + * @dev: the net device for the port + * + * Return the HW Tx channel of the given port. + */ +unsigned int cxgb4_port_chan(const struct net_device *dev) +{ + return netdev2pinfo(dev)->tx_chan; +} +EXPORT_SYMBOL(cxgb4_port_chan); + +/** + * cxgb4_port_viid - get the VI id of a port + * @dev: the net device for the port + * + * Return the VI id of the given port. + */ +unsigned int cxgb4_port_viid(const struct net_device *dev) +{ + return netdev2pinfo(dev)->viid; +} +EXPORT_SYMBOL(cxgb4_port_viid); + +/** + * cxgb4_port_idx - get the index of a port + * @dev: the net device for the port + * + * Return the index of the given port. + */ +unsigned int cxgb4_port_idx(const struct net_device *dev) +{ + return netdev2pinfo(dev)->port_id; +} +EXPORT_SYMBOL(cxgb4_port_idx); + +void cxgb4_get_tcp_stats(struct pci_dev *pdev, struct tp_tcp_stats *v4, + struct tp_tcp_stats *v6) +{ + struct adapter *adap = pci_get_drvdata(pdev); + + spin_lock(&adap->stats_lock); + t4_tp_get_tcp_stats(adap, v4, v6); + spin_unlock(&adap->stats_lock); +} +EXPORT_SYMBOL(cxgb4_get_tcp_stats); + +void cxgb4_iscsi_init(struct net_device *dev, unsigned int tag_mask, + const unsigned int *pgsz_order) +{ + struct adapter *adap = netdev2adap(dev); + + t4_write_reg(adap, ULP_RX_ISCSI_TAGMASK, tag_mask); + t4_write_reg(adap, ULP_RX_ISCSI_PSZ, HPZ0(pgsz_order[0]) | + HPZ1(pgsz_order[1]) | HPZ2(pgsz_order[2]) | + HPZ3(pgsz_order[3])); +} +EXPORT_SYMBOL(cxgb4_iscsi_init); + +static struct pci_driver cxgb4_driver; + +static void check_neigh_update(struct neighbour *neigh) +{ + const struct device *parent; + const struct net_device *netdev = neigh->dev; + + if (netdev->priv_flags & IFF_802_1Q_VLAN) + netdev = vlan_dev_real_dev(netdev); + parent = netdev->dev.parent; + if (parent && parent->driver == &cxgb4_driver.driver) + t4_l2t_update(dev_get_drvdata(parent), neigh); +} + +static int netevent_cb(struct notifier_block *nb, unsigned long event, + void *data) +{ + switch (event) { + case NETEVENT_NEIGH_UPDATE: + check_neigh_update(data); + break; + case NETEVENT_REDIRECT: + default: + break; + } + return 0; +} + +static bool netevent_registered; +static struct notifier_block cxgb4_netevent_nb = { + .notifier_call = netevent_cb +}; + +static void uld_attach(struct adapter *adap, unsigned int uld) +{ + void *handle; + struct cxgb4_lld_info lli; + + lli.pdev = adap->pdev; + lli.l2t = adap->l2t; + lli.tids = &adap->tids; + lli.ports = adap->port; + lli.vr = &adap->vres; + lli.mtus = adap->params.mtus; + if (uld == CXGB4_ULD_RDMA) { + lli.rxq_ids = adap->sge.rdma_rxq; + lli.nrxq = adap->sge.rdmaqs; + } else if (uld == CXGB4_ULD_ISCSI) { + lli.rxq_ids = adap->sge.ofld_rxq; + lli.nrxq = adap->sge.ofldqsets; + } + lli.ntxq = adap->sge.ofldqsets; + lli.nchan = adap->params.nports; + lli.nports = adap->params.nports; + lli.wr_cred = adap->params.ofldq_wr_cred; + lli.adapter_type = adap->params.rev; + lli.iscsi_iolen = MAXRXDATA_GET(t4_read_reg(adap, TP_PARA_REG2)); + lli.udb_density = 1 << QUEUESPERPAGEPF0_GET( + t4_read_reg(adap, SGE_EGRESS_QUEUES_PER_PAGE_PF) >> + (adap->fn * 4)); + lli.ucq_density = 1 << QUEUESPERPAGEPF0_GET( + t4_read_reg(adap, SGE_INGRESS_QUEUES_PER_PAGE_PF) >> + (adap->fn * 4)); + lli.gts_reg = adap->regs + MYPF_REG(SGE_PF_GTS); + lli.db_reg = adap->regs + MYPF_REG(SGE_PF_KDOORBELL); + lli.fw_vers = adap->params.fw_vers; + + handle = ulds[uld].add(&lli); + if (IS_ERR(handle)) { + dev_warn(adap->pdev_dev, + "could not attach to the %s driver, error %ld\n", + uld_str[uld], PTR_ERR(handle)); + return; + } + + adap->uld_handle[uld] = handle; + + if (!netevent_registered) { + register_netevent_notifier(&cxgb4_netevent_nb); + netevent_registered = true; + } + + if (adap->flags & FULL_INIT_DONE) + ulds[uld].state_change(handle, CXGB4_STATE_UP); +} + +static void attach_ulds(struct adapter *adap) +{ + unsigned int i; + + mutex_lock(&uld_mutex); + list_add_tail(&adap->list_node, &adapter_list); + for (i = 0; i < CXGB4_ULD_MAX; i++) + if (ulds[i].add) + uld_attach(adap, i); + mutex_unlock(&uld_mutex); +} + +static void detach_ulds(struct adapter *adap) +{ + unsigned int i; + + mutex_lock(&uld_mutex); + list_del(&adap->list_node); + for (i = 0; i < CXGB4_ULD_MAX; i++) + if (adap->uld_handle[i]) { + ulds[i].state_change(adap->uld_handle[i], + CXGB4_STATE_DETACH); + adap->uld_handle[i] = NULL; + } + if (netevent_registered && list_empty(&adapter_list)) { + unregister_netevent_notifier(&cxgb4_netevent_nb); + netevent_registered = false; + } + mutex_unlock(&uld_mutex); +} + +static void notify_ulds(struct adapter *adap, enum cxgb4_state new_state) +{ + unsigned int i; + + mutex_lock(&uld_mutex); + for (i = 0; i < CXGB4_ULD_MAX; i++) + if (adap->uld_handle[i]) + ulds[i].state_change(adap->uld_handle[i], new_state); + mutex_unlock(&uld_mutex); +} + +/** + * cxgb4_register_uld - register an upper-layer driver + * @type: the ULD type + * @p: the ULD methods + * + * Registers an upper-layer driver with this driver and notifies the ULD + * about any presently available devices that support its type. Returns + * %-EBUSY if a ULD of the same type is already registered. + */ +int cxgb4_register_uld(enum cxgb4_uld type, const struct cxgb4_uld_info *p) +{ + int ret = 0; + struct adapter *adap; + + if (type >= CXGB4_ULD_MAX) + return -EINVAL; + mutex_lock(&uld_mutex); + if (ulds[type].add) { + ret = -EBUSY; + goto out; + } + ulds[type] = *p; + list_for_each_entry(adap, &adapter_list, list_node) + uld_attach(adap, type); +out: mutex_unlock(&uld_mutex); + return ret; +} +EXPORT_SYMBOL(cxgb4_register_uld); + +/** + * cxgb4_unregister_uld - unregister an upper-layer driver + * @type: the ULD type + * + * Unregisters an existing upper-layer driver. + */ +int cxgb4_unregister_uld(enum cxgb4_uld type) +{ + struct adapter *adap; + + if (type >= CXGB4_ULD_MAX) + return -EINVAL; + mutex_lock(&uld_mutex); + list_for_each_entry(adap, &adapter_list, list_node) + adap->uld_handle[type] = NULL; + ulds[type].add = NULL; + mutex_unlock(&uld_mutex); + return 0; +} +EXPORT_SYMBOL(cxgb4_unregister_uld); + +/** + * cxgb_up - enable the adapter + * @adap: adapter being enabled + * + * Called when the first port is enabled, this function performs the + * actions necessary to make an adapter operational, such as completing + * the initialization of HW modules, and enabling interrupts. + * + * Must be called with the rtnl lock held. + */ +static int cxgb_up(struct adapter *adap) +{ + int err; + + err = setup_sge_queues(adap); + if (err) + goto out; + err = setup_rss(adap); + if (err) + goto freeq; + + if (adap->flags & USING_MSIX) { + name_msix_vecs(adap); + err = request_irq(adap->msix_info[0].vec, t4_nondata_intr, 0, + adap->msix_info[0].desc, adap); + if (err) + goto irq_err; + + err = request_msix_queue_irqs(adap); + if (err) { + free_irq(adap->msix_info[0].vec, adap); + goto irq_err; + } + } else { + err = request_irq(adap->pdev->irq, t4_intr_handler(adap), + (adap->flags & USING_MSI) ? 0 : IRQF_SHARED, + adap->port[0]->name, adap); + if (err) + goto irq_err; + } + enable_rx(adap); + t4_sge_start(adap); + t4_intr_enable(adap); + adap->flags |= FULL_INIT_DONE; + notify_ulds(adap, CXGB4_STATE_UP); + out: + return err; + irq_err: + dev_err(adap->pdev_dev, "request_irq failed, err %d\n", err); + freeq: + t4_free_sge_resources(adap); + goto out; +} + +static void cxgb_down(struct adapter *adapter) +{ + t4_intr_disable(adapter); + cancel_work_sync(&adapter->tid_release_task); + adapter->tid_release_task_busy = false; + adapter->tid_release_head = NULL; + + if (adapter->flags & USING_MSIX) { + free_msix_queue_irqs(adapter); + free_irq(adapter->msix_info[0].vec, adapter); + } else + free_irq(adapter->pdev->irq, adapter); + quiesce_rx(adapter); + t4_sge_stop(adapter); + t4_free_sge_resources(adapter); + adapter->flags &= ~FULL_INIT_DONE; +} + +/* + * net_device operations + */ +static int cxgb_open(struct net_device *dev) +{ + int err; + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + + netif_carrier_off(dev); + + if (!(adapter->flags & FULL_INIT_DONE)) { + err = cxgb_up(adapter); + if (err < 0) + return err; + } + + err = link_start(dev); + if (!err) + netif_tx_start_all_queues(dev); + return err; +} + +static int cxgb_close(struct net_device *dev) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + + netif_tx_stop_all_queues(dev); + netif_carrier_off(dev); + return t4_enable_vi(adapter, adapter->fn, pi->viid, false, false); +} + +static struct rtnl_link_stats64 *cxgb_get_stats(struct net_device *dev, + struct rtnl_link_stats64 *ns) +{ + struct port_stats stats; + struct port_info *p = netdev_priv(dev); + struct adapter *adapter = p->adapter; + + spin_lock(&adapter->stats_lock); + t4_get_port_stats(adapter, p->tx_chan, &stats); + spin_unlock(&adapter->stats_lock); + + ns->tx_bytes = stats.tx_octets; + ns->tx_packets = stats.tx_frames; + ns->rx_bytes = stats.rx_octets; + ns->rx_packets = stats.rx_frames; + ns->multicast = stats.rx_mcast_frames; + + /* detailed rx_errors */ + ns->rx_length_errors = stats.rx_jabber + stats.rx_too_long + + stats.rx_runt; + ns->rx_over_errors = 0; + ns->rx_crc_errors = stats.rx_fcs_err; + ns->rx_frame_errors = stats.rx_symbol_err; + ns->rx_fifo_errors = stats.rx_ovflow0 + stats.rx_ovflow1 + + stats.rx_ovflow2 + stats.rx_ovflow3 + + stats.rx_trunc0 + stats.rx_trunc1 + + stats.rx_trunc2 + stats.rx_trunc3; + ns->rx_missed_errors = 0; + + /* detailed tx_errors */ + ns->tx_aborted_errors = 0; + ns->tx_carrier_errors = 0; + ns->tx_fifo_errors = 0; + ns->tx_heartbeat_errors = 0; + ns->tx_window_errors = 0; + + ns->tx_errors = stats.tx_error_frames; + ns->rx_errors = stats.rx_symbol_err + stats.rx_fcs_err + + ns->rx_length_errors + stats.rx_len_err + ns->rx_fifo_errors; + return ns; +} + +static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd) +{ + unsigned int mbox; + int ret = 0, prtad, devad; + struct port_info *pi = netdev_priv(dev); + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&req->ifr_data; + + switch (cmd) { + case SIOCGMIIPHY: + if (pi->mdio_addr < 0) + return -EOPNOTSUPP; + data->phy_id = pi->mdio_addr; + break; + case SIOCGMIIREG: + case SIOCSMIIREG: + if (mdio_phy_id_is_c45(data->phy_id)) { + prtad = mdio_phy_id_prtad(data->phy_id); + devad = mdio_phy_id_devad(data->phy_id); + } else if (data->phy_id < 32) { + prtad = data->phy_id; + devad = 0; + data->reg_num &= 0x1f; + } else + return -EINVAL; + + mbox = pi->adapter->fn; + if (cmd == SIOCGMIIREG) + ret = t4_mdio_rd(pi->adapter, mbox, prtad, devad, + data->reg_num, &data->val_out); + else + ret = t4_mdio_wr(pi->adapter, mbox, prtad, devad, + data->reg_num, data->val_in); + break; + default: + return -EOPNOTSUPP; + } + return ret; +} + +static void cxgb_set_rxmode(struct net_device *dev) +{ + /* unfortunately we can't return errors to the stack */ + set_rxmode(dev, -1, false); +} + +static int cxgb_change_mtu(struct net_device *dev, int new_mtu) +{ + int ret; + struct port_info *pi = netdev_priv(dev); + + if (new_mtu < 81 || new_mtu > MAX_MTU) /* accommodate SACK */ + return -EINVAL; + ret = t4_set_rxmode(pi->adapter, pi->adapter->fn, pi->viid, new_mtu, -1, + -1, -1, -1, true); + if (!ret) + dev->mtu = new_mtu; + return ret; +} + +static int cxgb_set_mac_addr(struct net_device *dev, void *p) +{ + int ret; + struct sockaddr *addr = p; + struct port_info *pi = netdev_priv(dev); + + if (!is_valid_ether_addr(addr->sa_data)) + return -EINVAL; + + ret = t4_change_mac(pi->adapter, pi->adapter->fn, pi->viid, + pi->xact_addr_filt, addr->sa_data, true, true); + if (ret < 0) + return ret; + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + pi->xact_addr_filt = ret; + return 0; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void cxgb_netpoll(struct net_device *dev) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adap = pi->adapter; + + if (adap->flags & USING_MSIX) { + int i; + struct sge_eth_rxq *rx = &adap->sge.ethrxq[pi->first_qset]; + + for (i = pi->nqsets; i; i--, rx++) + t4_sge_intr_msix(0, &rx->rspq); + } else + t4_intr_handler(adap)(0, adap); +} +#endif + +static const struct net_device_ops cxgb4_netdev_ops = { + .ndo_open = cxgb_open, + .ndo_stop = cxgb_close, + .ndo_start_xmit = t4_eth_xmit, + .ndo_get_stats64 = cxgb_get_stats, + .ndo_set_rx_mode = cxgb_set_rxmode, + .ndo_set_mac_address = cxgb_set_mac_addr, + .ndo_set_features = cxgb_set_features, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = cxgb_ioctl, + .ndo_change_mtu = cxgb_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = cxgb_netpoll, +#endif +}; + +void t4_fatal_err(struct adapter *adap) +{ + t4_set_reg_field(adap, SGE_CONTROL, GLOBALENABLE, 0); + t4_intr_disable(adap); + dev_alert(adap->pdev_dev, "encountered fatal error, adapter stopped\n"); +} + +static void setup_memwin(struct adapter *adap) +{ + u32 bar0; + + bar0 = pci_resource_start(adap->pdev, 0); /* truncation intentional */ + t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 0), + (bar0 + MEMWIN0_BASE) | BIR(0) | + WINDOW(ilog2(MEMWIN0_APERTURE) - 10)); + t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 1), + (bar0 + MEMWIN1_BASE) | BIR(0) | + WINDOW(ilog2(MEMWIN1_APERTURE) - 10)); + t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 2), + (bar0 + MEMWIN2_BASE) | BIR(0) | + WINDOW(ilog2(MEMWIN2_APERTURE) - 10)); + if (adap->vres.ocq.size) { + unsigned int start, sz_kb; + + start = pci_resource_start(adap->pdev, 2) + + OCQ_WIN_OFFSET(adap->pdev, &adap->vres); + sz_kb = roundup_pow_of_two(adap->vres.ocq.size) >> 10; + t4_write_reg(adap, + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 3), + start | BIR(1) | WINDOW(ilog2(sz_kb))); + t4_write_reg(adap, + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, 3), + adap->vres.ocq.start); + t4_read_reg(adap, + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, 3)); + } +} + +static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c) +{ + u32 v; + int ret; + + /* get device capabilities */ + memset(c, 0, sizeof(*c)); + c->op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) | + FW_CMD_REQUEST | FW_CMD_READ); + c->retval_len16 = htonl(FW_LEN16(*c)); + ret = t4_wr_mbox(adap, adap->fn, c, sizeof(*c), c); + if (ret < 0) + return ret; + + /* select capabilities we'll be using */ + if (c->niccaps & htons(FW_CAPS_CONFIG_NIC_VM)) { + if (!vf_acls) + c->niccaps ^= htons(FW_CAPS_CONFIG_NIC_VM); + else + c->niccaps = htons(FW_CAPS_CONFIG_NIC_VM); + } else if (vf_acls) { + dev_err(adap->pdev_dev, "virtualization ACLs not supported"); + return ret; + } + c->op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) | + FW_CMD_REQUEST | FW_CMD_WRITE); + ret = t4_wr_mbox(adap, adap->fn, c, sizeof(*c), NULL); + if (ret < 0) + return ret; + + ret = t4_config_glbl_rss(adap, adap->fn, + FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL, + FW_RSS_GLB_CONFIG_CMD_TNLMAPEN | + FW_RSS_GLB_CONFIG_CMD_TNLALLLKP); + if (ret < 0) + return ret; + + ret = t4_cfg_pfvf(adap, adap->fn, adap->fn, 0, MAX_EGRQ, 64, MAX_INGQ, + 0, 0, 4, 0xf, 0xf, 16, FW_CMD_CAP_PF, FW_CMD_CAP_PF); + if (ret < 0) + return ret; + + t4_sge_init(adap); + + /* tweak some settings */ + t4_write_reg(adap, TP_SHIFT_CNT, 0x64f8849); + t4_write_reg(adap, ULP_RX_TDDP_PSZ, HPZ0(PAGE_SHIFT - 12)); + t4_write_reg(adap, TP_PIO_ADDR, TP_INGRESS_CONFIG); + v = t4_read_reg(adap, TP_PIO_DATA); + t4_write_reg(adap, TP_PIO_DATA, v & ~CSUM_HAS_PSEUDO_HDR); + + /* get basic stuff going */ + return t4_early_init(adap, adap->fn); +} + +/* + * Max # of ATIDs. The absolute HW max is 16K but we keep it lower. + */ +#define MAX_ATIDS 8192U + +/* + * Phase 0 of initialization: contact FW, obtain config, perform basic init. + */ +static int adap_init0(struct adapter *adap) +{ + int ret; + u32 v, port_vec; + enum dev_state state; + u32 params[7], val[7]; + struct fw_caps_config_cmd c; + + ret = t4_check_fw_version(adap); + if (ret == -EINVAL || ret > 0) { + if (upgrade_fw(adap) >= 0) /* recache FW version */ + ret = t4_check_fw_version(adap); + } + if (ret < 0) + return ret; + + /* contact FW, request master */ + ret = t4_fw_hello(adap, adap->fn, adap->fn, MASTER_MUST, &state); + if (ret < 0) { + dev_err(adap->pdev_dev, "could not connect to FW, error %d\n", + ret); + return ret; + } + + /* reset device */ + ret = t4_fw_reset(adap, adap->fn, PIORSTMODE | PIORST); + if (ret < 0) + goto bye; + + for (v = 0; v < SGE_NTIMERS - 1; v++) + adap->sge.timer_val[v] = min(intr_holdoff[v], MAX_SGE_TIMERVAL); + adap->sge.timer_val[SGE_NTIMERS - 1] = MAX_SGE_TIMERVAL; + adap->sge.counter_val[0] = 1; + for (v = 1; v < SGE_NCOUNTERS; v++) + adap->sge.counter_val[v] = min(intr_cnt[v - 1], + THRESHOLD_3_MASK); +#define FW_PARAM_DEV(param) \ + (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \ + FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param)) + + params[0] = FW_PARAM_DEV(CCLK); + ret = t4_query_params(adap, adap->fn, adap->fn, 0, 1, params, val); + if (ret < 0) + goto bye; + adap->params.vpd.cclk = val[0]; + + ret = adap_init1(adap, &c); + if (ret < 0) + goto bye; + +#define FW_PARAM_PFVF(param) \ + (FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \ + FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param) | \ + FW_PARAMS_PARAM_Y(adap->fn)) + + params[0] = FW_PARAM_DEV(PORTVEC); + params[1] = FW_PARAM_PFVF(L2T_START); + params[2] = FW_PARAM_PFVF(L2T_END); + params[3] = FW_PARAM_PFVF(FILTER_START); + params[4] = FW_PARAM_PFVF(FILTER_END); + params[5] = FW_PARAM_PFVF(IQFLINT_START); + params[6] = FW_PARAM_PFVF(EQ_START); + ret = t4_query_params(adap, adap->fn, adap->fn, 0, 7, params, val); + if (ret < 0) + goto bye; + port_vec = val[0]; + adap->tids.ftid_base = val[3]; + adap->tids.nftids = val[4] - val[3] + 1; + adap->sge.ingr_start = val[5]; + adap->sge.egr_start = val[6]; + + if (c.ofldcaps) { + /* query offload-related parameters */ + params[0] = FW_PARAM_DEV(NTID); + params[1] = FW_PARAM_PFVF(SERVER_START); + params[2] = FW_PARAM_PFVF(SERVER_END); + params[3] = FW_PARAM_PFVF(TDDP_START); + params[4] = FW_PARAM_PFVF(TDDP_END); + params[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ); + ret = t4_query_params(adap, adap->fn, adap->fn, 0, 6, params, + val); + if (ret < 0) + goto bye; + adap->tids.ntids = val[0]; + adap->tids.natids = min(adap->tids.ntids / 2, MAX_ATIDS); + adap->tids.stid_base = val[1]; + adap->tids.nstids = val[2] - val[1] + 1; + adap->vres.ddp.start = val[3]; + adap->vres.ddp.size = val[4] - val[3] + 1; + adap->params.ofldq_wr_cred = val[5]; + adap->params.offload = 1; + } + if (c.rdmacaps) { + params[0] = FW_PARAM_PFVF(STAG_START); + params[1] = FW_PARAM_PFVF(STAG_END); + params[2] = FW_PARAM_PFVF(RQ_START); + params[3] = FW_PARAM_PFVF(RQ_END); + params[4] = FW_PARAM_PFVF(PBL_START); + params[5] = FW_PARAM_PFVF(PBL_END); + ret = t4_query_params(adap, adap->fn, adap->fn, 0, 6, params, + val); + if (ret < 0) + goto bye; + adap->vres.stag.start = val[0]; + adap->vres.stag.size = val[1] - val[0] + 1; + adap->vres.rq.start = val[2]; + adap->vres.rq.size = val[3] - val[2] + 1; + adap->vres.pbl.start = val[4]; + adap->vres.pbl.size = val[5] - val[4] + 1; + + params[0] = FW_PARAM_PFVF(SQRQ_START); + params[1] = FW_PARAM_PFVF(SQRQ_END); + params[2] = FW_PARAM_PFVF(CQ_START); + params[3] = FW_PARAM_PFVF(CQ_END); + params[4] = FW_PARAM_PFVF(OCQ_START); + params[5] = FW_PARAM_PFVF(OCQ_END); + ret = t4_query_params(adap, adap->fn, adap->fn, 0, 6, params, + val); + if (ret < 0) + goto bye; + adap->vres.qp.start = val[0]; + adap->vres.qp.size = val[1] - val[0] + 1; + adap->vres.cq.start = val[2]; + adap->vres.cq.size = val[3] - val[2] + 1; + adap->vres.ocq.start = val[4]; + adap->vres.ocq.size = val[5] - val[4] + 1; + } + if (c.iscsicaps) { + params[0] = FW_PARAM_PFVF(ISCSI_START); + params[1] = FW_PARAM_PFVF(ISCSI_END); + ret = t4_query_params(adap, adap->fn, adap->fn, 0, 2, params, + val); + if (ret < 0) + goto bye; + adap->vres.iscsi.start = val[0]; + adap->vres.iscsi.size = val[1] - val[0] + 1; + } +#undef FW_PARAM_PFVF +#undef FW_PARAM_DEV + + adap->params.nports = hweight32(port_vec); + adap->params.portvec = port_vec; + adap->flags |= FW_OK; + + /* These are finalized by FW initialization, load their values now */ + v = t4_read_reg(adap, TP_TIMER_RESOLUTION); + adap->params.tp.tre = TIMERRESOLUTION_GET(v); + t4_read_mtu_tbl(adap, adap->params.mtus, NULL); + t4_load_mtus(adap, adap->params.mtus, adap->params.a_wnd, + adap->params.b_wnd); + +#ifdef CONFIG_PCI_IOV + /* + * Provision resource limits for Virtual Functions. We currently + * grant them all the same static resource limits except for the Port + * Access Rights Mask which we're assigning based on the PF. All of + * the static provisioning stuff for both the PF and VF really needs + * to be managed in a persistent manner for each device which the + * firmware controls. + */ + { + int pf, vf; + + for (pf = 0; pf < ARRAY_SIZE(num_vf); pf++) { + if (num_vf[pf] <= 0) + continue; + + /* VF numbering starts at 1! */ + for (vf = 1; vf <= num_vf[pf]; vf++) { + ret = t4_cfg_pfvf(adap, adap->fn, pf, vf, + VFRES_NEQ, VFRES_NETHCTRL, + VFRES_NIQFLINT, VFRES_NIQ, + VFRES_TC, VFRES_NVI, + FW_PFVF_CMD_CMASK_MASK, + pfvfres_pmask(adap, pf, vf), + VFRES_NEXACTF, + VFRES_R_CAPS, VFRES_WX_CAPS); + if (ret < 0) + dev_warn(adap->pdev_dev, "failed to " + "provision pf/vf=%d/%d; " + "err=%d\n", pf, vf, ret); + } + } + } +#endif + + setup_memwin(adap); + return 0; + + /* + * If a command timed out or failed with EIO FW does not operate within + * its spec or something catastrophic happened to HW/FW, stop issuing + * commands. + */ +bye: if (ret != -ETIMEDOUT && ret != -EIO) + t4_fw_bye(adap, adap->fn); + return ret; +} + +/* EEH callbacks */ + +static pci_ers_result_t eeh_err_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + int i; + struct adapter *adap = pci_get_drvdata(pdev); + + if (!adap) + goto out; + + rtnl_lock(); + adap->flags &= ~FW_OK; + notify_ulds(adap, CXGB4_STATE_START_RECOVERY); + for_each_port(adap, i) { + struct net_device *dev = adap->port[i]; + + netif_device_detach(dev); + netif_carrier_off(dev); + } + if (adap->flags & FULL_INIT_DONE) + cxgb_down(adap); + rtnl_unlock(); + pci_disable_device(pdev); +out: return state == pci_channel_io_perm_failure ? + PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET; +} + +static pci_ers_result_t eeh_slot_reset(struct pci_dev *pdev) +{ + int i, ret; + struct fw_caps_config_cmd c; + struct adapter *adap = pci_get_drvdata(pdev); + + if (!adap) { + pci_restore_state(pdev); + pci_save_state(pdev); + return PCI_ERS_RESULT_RECOVERED; + } + + if (pci_enable_device(pdev)) { + dev_err(&pdev->dev, "cannot reenable PCI device after reset\n"); + return PCI_ERS_RESULT_DISCONNECT; + } + + pci_set_master(pdev); + pci_restore_state(pdev); + pci_save_state(pdev); + pci_cleanup_aer_uncorrect_error_status(pdev); + + if (t4_wait_dev_ready(adap) < 0) + return PCI_ERS_RESULT_DISCONNECT; + if (t4_fw_hello(adap, adap->fn, adap->fn, MASTER_MUST, NULL)) + return PCI_ERS_RESULT_DISCONNECT; + adap->flags |= FW_OK; + if (adap_init1(adap, &c)) + return PCI_ERS_RESULT_DISCONNECT; + + for_each_port(adap, i) { + struct port_info *p = adap2pinfo(adap, i); + + ret = t4_alloc_vi(adap, adap->fn, p->tx_chan, adap->fn, 0, 1, + NULL, NULL); + if (ret < 0) + return PCI_ERS_RESULT_DISCONNECT; + p->viid = ret; + p->xact_addr_filt = -1; + } + + t4_load_mtus(adap, adap->params.mtus, adap->params.a_wnd, + adap->params.b_wnd); + setup_memwin(adap); + if (cxgb_up(adap)) + return PCI_ERS_RESULT_DISCONNECT; + return PCI_ERS_RESULT_RECOVERED; +} + +static void eeh_resume(struct pci_dev *pdev) +{ + int i; + struct adapter *adap = pci_get_drvdata(pdev); + + if (!adap) + return; + + rtnl_lock(); + for_each_port(adap, i) { + struct net_device *dev = adap->port[i]; + + if (netif_running(dev)) { + link_start(dev); + cxgb_set_rxmode(dev); + } + netif_device_attach(dev); + } + rtnl_unlock(); +} + +static struct pci_error_handlers cxgb4_eeh = { + .error_detected = eeh_err_detected, + .slot_reset = eeh_slot_reset, + .resume = eeh_resume, +}; + +static inline bool is_10g_port(const struct link_config *lc) +{ + return (lc->supported & FW_PORT_CAP_SPEED_10G) != 0; +} + +static inline void init_rspq(struct sge_rspq *q, u8 timer_idx, u8 pkt_cnt_idx, + unsigned int size, unsigned int iqe_size) +{ + q->intr_params = QINTR_TIMER_IDX(timer_idx) | + (pkt_cnt_idx < SGE_NCOUNTERS ? QINTR_CNT_EN : 0); + q->pktcnt_idx = pkt_cnt_idx < SGE_NCOUNTERS ? pkt_cnt_idx : 0; + q->iqe_len = iqe_size; + q->size = size; +} + +/* + * Perform default configuration of DMA queues depending on the number and type + * of ports we found and the number of available CPUs. Most settings can be + * modified by the admin prior to actual use. + */ +static void __devinit cfg_queues(struct adapter *adap) +{ + struct sge *s = &adap->sge; + int i, q10g = 0, n10g = 0, qidx = 0; + + for_each_port(adap, i) + n10g += is_10g_port(&adap2pinfo(adap, i)->link_cfg); + + /* + * We default to 1 queue per non-10G port and up to # of cores queues + * per 10G port. + */ + if (n10g) + q10g = (MAX_ETH_QSETS - (adap->params.nports - n10g)) / n10g; + if (q10g > num_online_cpus()) + q10g = num_online_cpus(); + + for_each_port(adap, i) { + struct port_info *pi = adap2pinfo(adap, i); + + pi->first_qset = qidx; + pi->nqsets = is_10g_port(&pi->link_cfg) ? q10g : 1; + qidx += pi->nqsets; + } + + s->ethqsets = qidx; + s->max_ethqsets = qidx; /* MSI-X may lower it later */ + + if (is_offload(adap)) { + /* + * For offload we use 1 queue/channel if all ports are up to 1G, + * otherwise we divide all available queues amongst the channels + * capped by the number of available cores. + */ + if (n10g) { + i = min_t(int, ARRAY_SIZE(s->ofldrxq), + num_online_cpus()); + s->ofldqsets = roundup(i, adap->params.nports); + } else + s->ofldqsets = adap->params.nports; + /* For RDMA one Rx queue per channel suffices */ + s->rdmaqs = adap->params.nports; + } + + for (i = 0; i < ARRAY_SIZE(s->ethrxq); i++) { + struct sge_eth_rxq *r = &s->ethrxq[i]; + + init_rspq(&r->rspq, 0, 0, 1024, 64); + r->fl.size = 72; + } + + for (i = 0; i < ARRAY_SIZE(s->ethtxq); i++) + s->ethtxq[i].q.size = 1024; + + for (i = 0; i < ARRAY_SIZE(s->ctrlq); i++) + s->ctrlq[i].q.size = 512; + + for (i = 0; i < ARRAY_SIZE(s->ofldtxq); i++) + s->ofldtxq[i].q.size = 1024; + + for (i = 0; i < ARRAY_SIZE(s->ofldrxq); i++) { + struct sge_ofld_rxq *r = &s->ofldrxq[i]; + + init_rspq(&r->rspq, 0, 0, 1024, 64); + r->rspq.uld = CXGB4_ULD_ISCSI; + r->fl.size = 72; + } + + for (i = 0; i < ARRAY_SIZE(s->rdmarxq); i++) { + struct sge_ofld_rxq *r = &s->rdmarxq[i]; + + init_rspq(&r->rspq, 0, 0, 511, 64); + r->rspq.uld = CXGB4_ULD_RDMA; + r->fl.size = 72; + } + + init_rspq(&s->fw_evtq, 6, 0, 512, 64); + init_rspq(&s->intrq, 6, 0, 2 * MAX_INGQ, 64); +} + +/* + * Reduce the number of Ethernet queues across all ports to at most n. + * n provides at least one queue per port. + */ +static void __devinit reduce_ethqs(struct adapter *adap, int n) +{ + int i; + struct port_info *pi; + + while (n < adap->sge.ethqsets) + for_each_port(adap, i) { + pi = adap2pinfo(adap, i); + if (pi->nqsets > 1) { + pi->nqsets--; + adap->sge.ethqsets--; + if (adap->sge.ethqsets <= n) + break; + } + } + + n = 0; + for_each_port(adap, i) { + pi = adap2pinfo(adap, i); + pi->first_qset = n; + n += pi->nqsets; + } +} + +/* 2 MSI-X vectors needed for the FW queue and non-data interrupts */ +#define EXTRA_VECS 2 + +static int __devinit enable_msix(struct adapter *adap) +{ + int ofld_need = 0; + int i, err, want, need; + struct sge *s = &adap->sge; + unsigned int nchan = adap->params.nports; + struct msix_entry entries[MAX_INGQ + 1]; + + for (i = 0; i < ARRAY_SIZE(entries); ++i) + entries[i].entry = i; + + want = s->max_ethqsets + EXTRA_VECS; + if (is_offload(adap)) { + want += s->rdmaqs + s->ofldqsets; + /* need nchan for each possible ULD */ + ofld_need = 2 * nchan; + } + need = adap->params.nports + EXTRA_VECS + ofld_need; + + while ((err = pci_enable_msix(adap->pdev, entries, want)) >= need) + want = err; + + if (!err) { + /* + * Distribute available vectors to the various queue groups. + * Every group gets its minimum requirement and NIC gets top + * priority for leftovers. + */ + i = want - EXTRA_VECS - ofld_need; + if (i < s->max_ethqsets) { + s->max_ethqsets = i; + if (i < s->ethqsets) + reduce_ethqs(adap, i); + } + if (is_offload(adap)) { + i = want - EXTRA_VECS - s->max_ethqsets; + i -= ofld_need - nchan; + s->ofldqsets = (i / nchan) * nchan; /* round down */ + } + for (i = 0; i < want; ++i) + adap->msix_info[i].vec = entries[i].vector; + } else if (err > 0) + dev_info(adap->pdev_dev, + "only %d MSI-X vectors left, not using MSI-X\n", err); + return err; +} + +#undef EXTRA_VECS + +static int __devinit init_rss(struct adapter *adap) +{ + unsigned int i, j; + + for_each_port(adap, i) { + struct port_info *pi = adap2pinfo(adap, i); + + pi->rss = kcalloc(pi->rss_size, sizeof(u16), GFP_KERNEL); + if (!pi->rss) + return -ENOMEM; + for (j = 0; j < pi->rss_size; j++) + pi->rss[j] = j % pi->nqsets; + } + return 0; +} + +static void __devinit print_port_info(const struct net_device *dev) +{ + static const char *base[] = { + "R XFI", "R XAUI", "T SGMII", "T XFI", "T XAUI", "KX4", "CX4", + "KX", "KR", "R SFP+", "KR/KX", "KR/KX/KX4" + }; + + char buf[80]; + char *bufp = buf; + const char *spd = ""; + const struct port_info *pi = netdev_priv(dev); + const struct adapter *adap = pi->adapter; + + if (adap->params.pci.speed == PCI_EXP_LNKSTA_CLS_2_5GB) + spd = " 2.5 GT/s"; + else if (adap->params.pci.speed == PCI_EXP_LNKSTA_CLS_5_0GB) + spd = " 5 GT/s"; + + if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_100M) + bufp += sprintf(bufp, "100/"); + if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_1G) + bufp += sprintf(bufp, "1000/"); + if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_10G) + bufp += sprintf(bufp, "10G/"); + if (bufp != buf) + --bufp; + sprintf(bufp, "BASE-%s", base[pi->port_type]); + + netdev_info(dev, "Chelsio %s rev %d %s %sNIC PCIe x%d%s%s\n", + adap->params.vpd.id, adap->params.rev, buf, + is_offload(adap) ? "R" : "", adap->params.pci.width, spd, + (adap->flags & USING_MSIX) ? " MSI-X" : + (adap->flags & USING_MSI) ? " MSI" : ""); + netdev_info(dev, "S/N: %s, E/C: %s\n", + adap->params.vpd.sn, adap->params.vpd.ec); +} + +static void __devinit enable_pcie_relaxed_ordering(struct pci_dev *dev) +{ + u16 v; + int pos; + + pos = pci_pcie_cap(dev); + if (pos > 0) { + pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &v); + v |= PCI_EXP_DEVCTL_RELAX_EN; + pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, v); + } +} + +/* + * Free the following resources: + * - memory used for tables + * - MSI/MSI-X + * - net devices + * - resources FW is holding for us + */ +static void free_some_resources(struct adapter *adapter) +{ + unsigned int i; + + t4_free_mem(adapter->l2t); + t4_free_mem(adapter->tids.tid_tab); + disable_msi(adapter); + + for_each_port(adapter, i) + if (adapter->port[i]) { + kfree(adap2pinfo(adapter, i)->rss); + free_netdev(adapter->port[i]); + } + if (adapter->flags & FW_OK) + t4_fw_bye(adapter, adapter->fn); +} + +#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN) +#define VLAN_FEAT (NETIF_F_SG | NETIF_F_IP_CSUM | TSO_FLAGS | \ + NETIF_F_IPV6_CSUM | NETIF_F_HIGHDMA) + +static int __devinit init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int func, i, err; + struct port_info *pi; + unsigned int highdma = 0; + struct adapter *adapter = NULL; + + printk_once(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION); + + err = pci_request_regions(pdev, KBUILD_MODNAME); + if (err) { + /* Just info, some other driver may have claimed the device. */ + dev_info(&pdev->dev, "cannot obtain PCI resources\n"); + return err; + } + + /* We control everything through one PF */ + func = PCI_FUNC(pdev->devfn); + if (func != ent->driver_data) { + pci_save_state(pdev); /* to restore SR-IOV later */ + goto sriov; + } + + err = pci_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, "cannot enable PCI device\n"); + goto out_release_regions; + } + + if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { + highdma = NETIF_F_HIGHDMA; + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + if (err) { + dev_err(&pdev->dev, "unable to obtain 64-bit DMA for " + "coherent allocations\n"); + goto out_disable_device; + } + } else { + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (err) { + dev_err(&pdev->dev, "no usable DMA configuration\n"); + goto out_disable_device; + } + } + + pci_enable_pcie_error_reporting(pdev); + enable_pcie_relaxed_ordering(pdev); + pci_set_master(pdev); + pci_save_state(pdev); + + adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); + if (!adapter) { + err = -ENOMEM; + goto out_disable_device; + } + + adapter->regs = pci_ioremap_bar(pdev, 0); + if (!adapter->regs) { + dev_err(&pdev->dev, "cannot map device registers\n"); + err = -ENOMEM; + goto out_free_adapter; + } + + adapter->pdev = pdev; + adapter->pdev_dev = &pdev->dev; + adapter->fn = func; + adapter->msg_enable = dflt_msg_enable; + memset(adapter->chan_map, 0xff, sizeof(adapter->chan_map)); + + spin_lock_init(&adapter->stats_lock); + spin_lock_init(&adapter->tid_release_lock); + + INIT_WORK(&adapter->tid_release_task, process_tid_release_list); + + err = t4_prep_adapter(adapter); + if (err) + goto out_unmap_bar; + err = adap_init0(adapter); + if (err) + goto out_unmap_bar; + + for_each_port(adapter, i) { + struct net_device *netdev; + + netdev = alloc_etherdev_mq(sizeof(struct port_info), + MAX_ETH_QSETS); + if (!netdev) { + err = -ENOMEM; + goto out_free_dev; + } + + SET_NETDEV_DEV(netdev, &pdev->dev); + + adapter->port[i] = netdev; + pi = netdev_priv(netdev); + pi->adapter = adapter; + pi->xact_addr_filt = -1; + pi->port_id = i; + netdev->irq = pdev->irq; + + netdev->hw_features = NETIF_F_SG | TSO_FLAGS | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_RXCSUM | NETIF_F_RXHASH | + NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + netdev->features |= netdev->hw_features | highdma; + netdev->vlan_features = netdev->features & VLAN_FEAT; + + netdev->netdev_ops = &cxgb4_netdev_ops; + SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops); + } + + pci_set_drvdata(pdev, adapter); + + if (adapter->flags & FW_OK) { + err = t4_port_init(adapter, func, func, 0); + if (err) + goto out_free_dev; + } + + /* + * Configure queues and allocate tables now, they can be needed as + * soon as the first register_netdev completes. + */ + cfg_queues(adapter); + + adapter->l2t = t4_init_l2t(); + if (!adapter->l2t) { + /* We tolerate a lack of L2T, giving up some functionality */ + dev_warn(&pdev->dev, "could not allocate L2T, continuing\n"); + adapter->params.offload = 0; + } + + if (is_offload(adapter) && tid_init(&adapter->tids) < 0) { + dev_warn(&pdev->dev, "could not allocate TID table, " + "continuing\n"); + adapter->params.offload = 0; + } + + /* See what interrupts we'll be using */ + if (msi > 1 && enable_msix(adapter) == 0) + adapter->flags |= USING_MSIX; + else if (msi > 0 && pci_enable_msi(pdev) == 0) + adapter->flags |= USING_MSI; + + err = init_rss(adapter); + if (err) + goto out_free_dev; + + /* + * The card is now ready to go. If any errors occur during device + * registration we do not fail the whole card but rather proceed only + * with the ports we manage to register successfully. However we must + * register at least one net device. + */ + for_each_port(adapter, i) { + pi = adap2pinfo(adapter, i); + netif_set_real_num_tx_queues(adapter->port[i], pi->nqsets); + netif_set_real_num_rx_queues(adapter->port[i], pi->nqsets); + + err = register_netdev(adapter->port[i]); + if (err) + break; + adapter->chan_map[pi->tx_chan] = i; + print_port_info(adapter->port[i]); + } + if (i == 0) { + dev_err(&pdev->dev, "could not register any net devices\n"); + goto out_free_dev; + } + if (err) { + dev_warn(&pdev->dev, "only %d net devices registered\n", i); + err = 0; + } + + if (cxgb4_debugfs_root) { + adapter->debugfs_root = debugfs_create_dir(pci_name(pdev), + cxgb4_debugfs_root); + setup_debugfs(adapter); + } + + if (is_offload(adapter)) + attach_ulds(adapter); + +sriov: +#ifdef CONFIG_PCI_IOV + if (func < ARRAY_SIZE(num_vf) && num_vf[func] > 0) + if (pci_enable_sriov(pdev, num_vf[func]) == 0) + dev_info(&pdev->dev, + "instantiated %u virtual functions\n", + num_vf[func]); +#endif + return 0; + + out_free_dev: + free_some_resources(adapter); + out_unmap_bar: + iounmap(adapter->regs); + out_free_adapter: + kfree(adapter); + out_disable_device: + pci_disable_pcie_error_reporting(pdev); + pci_disable_device(pdev); + out_release_regions: + pci_release_regions(pdev); + pci_set_drvdata(pdev, NULL); + return err; +} + +static void __devexit remove_one(struct pci_dev *pdev) +{ + struct adapter *adapter = pci_get_drvdata(pdev); + + pci_disable_sriov(pdev); + + if (adapter) { + int i; + + if (is_offload(adapter)) + detach_ulds(adapter); + + for_each_port(adapter, i) + if (adapter->port[i]->reg_state == NETREG_REGISTERED) + unregister_netdev(adapter->port[i]); + + if (adapter->debugfs_root) + debugfs_remove_recursive(adapter->debugfs_root); + + if (adapter->flags & FULL_INIT_DONE) + cxgb_down(adapter); + + free_some_resources(adapter); + iounmap(adapter->regs); + kfree(adapter); + pci_disable_pcie_error_reporting(pdev); + pci_disable_device(pdev); + pci_release_regions(pdev); + pci_set_drvdata(pdev, NULL); + } else + pci_release_regions(pdev); +} + +static struct pci_driver cxgb4_driver = { + .name = KBUILD_MODNAME, + .id_table = cxgb4_pci_tbl, + .probe = init_one, + .remove = __devexit_p(remove_one), + .err_handler = &cxgb4_eeh, +}; + +static int __init cxgb4_init_module(void) +{ + int ret; + + /* Debugfs support is optional, just warn if this fails */ + cxgb4_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); + if (!cxgb4_debugfs_root) + pr_warning("could not create debugfs entry, continuing\n"); + + ret = pci_register_driver(&cxgb4_driver); + if (ret < 0) + debugfs_remove(cxgb4_debugfs_root); + return ret; +} + +static void __exit cxgb4_cleanup_module(void) +{ + pci_unregister_driver(&cxgb4_driver); + debugfs_remove(cxgb4_debugfs_root); /* NULL ok */ +} + +module_init(cxgb4_init_module); +module_exit(cxgb4_cleanup_module); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h new file mode 100644 index 000000000000..b1d39b8d141a --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h @@ -0,0 +1,239 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __CXGB4_OFLD_H +#define __CXGB4_OFLD_H + +#include +#include +#include +#include + +/* CPL message priority levels */ +enum { + CPL_PRIORITY_DATA = 0, /* data messages */ + CPL_PRIORITY_SETUP = 1, /* connection setup messages */ + CPL_PRIORITY_TEARDOWN = 0, /* connection teardown messages */ + CPL_PRIORITY_LISTEN = 1, /* listen start/stop messages */ + CPL_PRIORITY_ACK = 1, /* RX ACK messages */ + CPL_PRIORITY_CONTROL = 1 /* control messages */ +}; + +#define INIT_TP_WR(w, tid) do { \ + (w)->wr.wr_hi = htonl(FW_WR_OP(FW_TP_WR) | \ + FW_WR_IMMDLEN(sizeof(*w) - sizeof(w->wr))); \ + (w)->wr.wr_mid = htonl(FW_WR_LEN16(DIV_ROUND_UP(sizeof(*w), 16)) | \ + FW_WR_FLOWID(tid)); \ + (w)->wr.wr_lo = cpu_to_be64(0); \ +} while (0) + +#define INIT_TP_WR_CPL(w, cpl, tid) do { \ + INIT_TP_WR(w, tid); \ + OPCODE_TID(w) = htonl(MK_OPCODE_TID(cpl, tid)); \ +} while (0) + +#define INIT_ULPTX_WR(w, wrlen, atomic, tid) do { \ + (w)->wr.wr_hi = htonl(FW_WR_OP(FW_ULPTX_WR) | FW_WR_ATOMIC(atomic)); \ + (w)->wr.wr_mid = htonl(FW_WR_LEN16(DIV_ROUND_UP(wrlen, 16)) | \ + FW_WR_FLOWID(tid)); \ + (w)->wr.wr_lo = cpu_to_be64(0); \ +} while (0) + +/* Special asynchronous notification message */ +#define CXGB4_MSG_AN ((void *)1) + +struct serv_entry { + void *data; +}; + +union aopen_entry { + void *data; + union aopen_entry *next; +}; + +/* + * Holds the size, base address, free list start, etc of the TID, server TID, + * and active-open TID tables. The tables themselves are allocated dynamically. + */ +struct tid_info { + void **tid_tab; + unsigned int ntids; + + struct serv_entry *stid_tab; + unsigned long *stid_bmap; + unsigned int nstids; + unsigned int stid_base; + + union aopen_entry *atid_tab; + unsigned int natids; + + unsigned int nftids; + unsigned int ftid_base; + + spinlock_t atid_lock ____cacheline_aligned_in_smp; + union aopen_entry *afree; + unsigned int atids_in_use; + + spinlock_t stid_lock; + unsigned int stids_in_use; + + atomic_t tids_in_use; +}; + +static inline void *lookup_tid(const struct tid_info *t, unsigned int tid) +{ + return tid < t->ntids ? t->tid_tab[tid] : NULL; +} + +static inline void *lookup_atid(const struct tid_info *t, unsigned int atid) +{ + return atid < t->natids ? t->atid_tab[atid].data : NULL; +} + +static inline void *lookup_stid(const struct tid_info *t, unsigned int stid) +{ + stid -= t->stid_base; + return stid < t->nstids ? t->stid_tab[stid].data : NULL; +} + +static inline void cxgb4_insert_tid(struct tid_info *t, void *data, + unsigned int tid) +{ + t->tid_tab[tid] = data; + atomic_inc(&t->tids_in_use); +} + +int cxgb4_alloc_atid(struct tid_info *t, void *data); +int cxgb4_alloc_stid(struct tid_info *t, int family, void *data); +void cxgb4_free_atid(struct tid_info *t, unsigned int atid); +void cxgb4_free_stid(struct tid_info *t, unsigned int stid, int family); +void cxgb4_remove_tid(struct tid_info *t, unsigned int qid, unsigned int tid); + +struct in6_addr; + +int cxgb4_create_server(const struct net_device *dev, unsigned int stid, + __be32 sip, __be16 sport, unsigned int queue); + +static inline void set_wr_txq(struct sk_buff *skb, int prio, int queue) +{ + skb_set_queue_mapping(skb, (queue << 1) | prio); +} + +enum cxgb4_uld { + CXGB4_ULD_RDMA, + CXGB4_ULD_ISCSI, + CXGB4_ULD_MAX +}; + +enum cxgb4_state { + CXGB4_STATE_UP, + CXGB4_STATE_START_RECOVERY, + CXGB4_STATE_DOWN, + CXGB4_STATE_DETACH +}; + +struct pci_dev; +struct l2t_data; +struct net_device; +struct pkt_gl; +struct tp_tcp_stats; + +struct cxgb4_range { + unsigned int start; + unsigned int size; +}; + +struct cxgb4_virt_res { /* virtualized HW resources */ + struct cxgb4_range ddp; + struct cxgb4_range iscsi; + struct cxgb4_range stag; + struct cxgb4_range rq; + struct cxgb4_range pbl; + struct cxgb4_range qp; + struct cxgb4_range cq; + struct cxgb4_range ocq; +}; + +#define OCQ_WIN_OFFSET(pdev, vres) \ + (pci_resource_len((pdev), 2) - roundup_pow_of_two((vres)->ocq.size)) + +/* + * Block of information the LLD provides to ULDs attaching to a device. + */ +struct cxgb4_lld_info { + struct pci_dev *pdev; /* associated PCI device */ + struct l2t_data *l2t; /* L2 table */ + struct tid_info *tids; /* TID table */ + struct net_device **ports; /* device ports */ + const struct cxgb4_virt_res *vr; /* assorted HW resources */ + const unsigned short *mtus; /* MTU table */ + const unsigned short *rxq_ids; /* the ULD's Rx queue ids */ + unsigned short nrxq; /* # of Rx queues */ + unsigned short ntxq; /* # of Tx queues */ + unsigned char nchan:4; /* # of channels */ + unsigned char nports:4; /* # of ports */ + unsigned char wr_cred; /* WR 16-byte credits */ + unsigned char adapter_type; /* type of adapter */ + unsigned char fw_api_ver; /* FW API version */ + unsigned int fw_vers; /* FW version */ + unsigned int iscsi_iolen; /* iSCSI max I/O length */ + unsigned short udb_density; /* # of user DB/page */ + unsigned short ucq_density; /* # of user CQs/page */ + void __iomem *gts_reg; /* address of GTS register */ + void __iomem *db_reg; /* address of kernel doorbell */ +}; + +struct cxgb4_uld_info { + const char *name; + void *(*add)(const struct cxgb4_lld_info *p); + int (*rx_handler)(void *handle, const __be64 *rsp, + const struct pkt_gl *gl); + int (*state_change)(void *handle, enum cxgb4_state new_state); +}; + +int cxgb4_register_uld(enum cxgb4_uld type, const struct cxgb4_uld_info *p); +int cxgb4_unregister_uld(enum cxgb4_uld type); +int cxgb4_ofld_send(struct net_device *dev, struct sk_buff *skb); +unsigned int cxgb4_port_chan(const struct net_device *dev); +unsigned int cxgb4_port_viid(const struct net_device *dev); +unsigned int cxgb4_port_idx(const struct net_device *dev); +unsigned int cxgb4_best_mtu(const unsigned short *mtus, unsigned short mtu, + unsigned int *idx); +void cxgb4_get_tcp_stats(struct pci_dev *pdev, struct tp_tcp_stats *v4, + struct tp_tcp_stats *v6); +void cxgb4_iscsi_init(struct net_device *dev, unsigned int tag_mask, + const unsigned int *pgsz_order); +struct sk_buff *cxgb4_pktgl_to_skb(const struct pkt_gl *gl, + unsigned int skb_len, unsigned int pull_len); +#endif /* !__CXGB4_OFLD_H */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.c b/drivers/net/ethernet/chelsio/cxgb4/l2t.c new file mode 100644 index 000000000000..a2d323c473f8 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.c @@ -0,0 +1,597 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include "cxgb4.h" +#include "l2t.h" +#include "t4_msg.h" +#include "t4fw_api.h" + +#define VLAN_NONE 0xfff + +/* identifies sync vs async L2T_WRITE_REQs */ +#define F_SYNC_WR (1 << 12) + +enum { + L2T_STATE_VALID, /* entry is up to date */ + L2T_STATE_STALE, /* entry may be used but needs revalidation */ + L2T_STATE_RESOLVING, /* entry needs address resolution */ + L2T_STATE_SYNC_WRITE, /* synchronous write of entry underway */ + + /* when state is one of the below the entry is not hashed */ + L2T_STATE_SWITCHING, /* entry is being used by a switching filter */ + L2T_STATE_UNUSED /* entry not in use */ +}; + +struct l2t_data { + rwlock_t lock; + atomic_t nfree; /* number of free entries */ + struct l2t_entry *rover; /* starting point for next allocation */ + struct l2t_entry l2tab[L2T_SIZE]; +}; + +static inline unsigned int vlan_prio(const struct l2t_entry *e) +{ + return e->vlan >> 13; +} + +static inline void l2t_hold(struct l2t_data *d, struct l2t_entry *e) +{ + if (atomic_add_return(1, &e->refcnt) == 1) /* 0 -> 1 transition */ + atomic_dec(&d->nfree); +} + +/* + * To avoid having to check address families we do not allow v4 and v6 + * neighbors to be on the same hash chain. We keep v4 entries in the first + * half of available hash buckets and v6 in the second. + */ +enum { + L2T_SZ_HALF = L2T_SIZE / 2, + L2T_HASH_MASK = L2T_SZ_HALF - 1 +}; + +static inline unsigned int arp_hash(const u32 *key, int ifindex) +{ + return jhash_2words(*key, ifindex, 0) & L2T_HASH_MASK; +} + +static inline unsigned int ipv6_hash(const u32 *key, int ifindex) +{ + u32 xor = key[0] ^ key[1] ^ key[2] ^ key[3]; + + return L2T_SZ_HALF + (jhash_2words(xor, ifindex, 0) & L2T_HASH_MASK); +} + +static unsigned int addr_hash(const u32 *addr, int addr_len, int ifindex) +{ + return addr_len == 4 ? arp_hash(addr, ifindex) : + ipv6_hash(addr, ifindex); +} + +/* + * Checks if an L2T entry is for the given IP/IPv6 address. It does not check + * whether the L2T entry and the address are of the same address family. + * Callers ensure an address is only checked against L2T entries of the same + * family, something made trivial by the separation of IP and IPv6 hash chains + * mentioned above. Returns 0 if there's a match, + */ +static int addreq(const struct l2t_entry *e, const u32 *addr) +{ + if (e->v6) + return (e->addr[0] ^ addr[0]) | (e->addr[1] ^ addr[1]) | + (e->addr[2] ^ addr[2]) | (e->addr[3] ^ addr[3]); + return e->addr[0] ^ addr[0]; +} + +static void neigh_replace(struct l2t_entry *e, struct neighbour *n) +{ + neigh_hold(n); + if (e->neigh) + neigh_release(e->neigh); + e->neigh = n; +} + +/* + * Write an L2T entry. Must be called with the entry locked. + * The write may be synchronous or asynchronous. + */ +static int write_l2e(struct adapter *adap, struct l2t_entry *e, int sync) +{ + struct sk_buff *skb; + struct cpl_l2t_write_req *req; + + skb = alloc_skb(sizeof(*req), GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req)); + INIT_TP_WR(req, 0); + + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, + e->idx | (sync ? F_SYNC_WR : 0) | + TID_QID(adap->sge.fw_evtq.abs_id))); + req->params = htons(L2T_W_PORT(e->lport) | L2T_W_NOREPLY(!sync)); + req->l2t_idx = htons(e->idx); + req->vlan = htons(e->vlan); + if (e->neigh) + memcpy(e->dmac, e->neigh->ha, sizeof(e->dmac)); + memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac)); + + set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0); + t4_ofld_send(adap, skb); + + if (sync && e->state != L2T_STATE_SWITCHING) + e->state = L2T_STATE_SYNC_WRITE; + return 0; +} + +/* + * Send packets waiting in an L2T entry's ARP queue. Must be called with the + * entry locked. + */ +static void send_pending(struct adapter *adap, struct l2t_entry *e) +{ + while (e->arpq_head) { + struct sk_buff *skb = e->arpq_head; + + e->arpq_head = skb->next; + skb->next = NULL; + t4_ofld_send(adap, skb); + } + e->arpq_tail = NULL; +} + +/* + * Process a CPL_L2T_WRITE_RPL. Wake up the ARP queue if it completes a + * synchronous L2T_WRITE. Note that the TID in the reply is really the L2T + * index it refers to. + */ +void do_l2t_write_rpl(struct adapter *adap, const struct cpl_l2t_write_rpl *rpl) +{ + unsigned int tid = GET_TID(rpl); + unsigned int idx = tid & (L2T_SIZE - 1); + + if (unlikely(rpl->status != CPL_ERR_NONE)) { + dev_err(adap->pdev_dev, + "Unexpected L2T_WRITE_RPL status %u for entry %u\n", + rpl->status, idx); + return; + } + + if (tid & F_SYNC_WR) { + struct l2t_entry *e = &adap->l2t->l2tab[idx]; + + spin_lock(&e->lock); + if (e->state != L2T_STATE_SWITCHING) { + send_pending(adap, e); + e->state = (e->neigh->nud_state & NUD_STALE) ? + L2T_STATE_STALE : L2T_STATE_VALID; + } + spin_unlock(&e->lock); + } +} + +/* + * Add a packet to an L2T entry's queue of packets awaiting resolution. + * Must be called with the entry's lock held. + */ +static inline void arpq_enqueue(struct l2t_entry *e, struct sk_buff *skb) +{ + skb->next = NULL; + if (e->arpq_head) + e->arpq_tail->next = skb; + else + e->arpq_head = skb; + e->arpq_tail = skb; +} + +int cxgb4_l2t_send(struct net_device *dev, struct sk_buff *skb, + struct l2t_entry *e) +{ + struct adapter *adap = netdev2adap(dev); + +again: + switch (e->state) { + case L2T_STATE_STALE: /* entry is stale, kick off revalidation */ + neigh_event_send(e->neigh, NULL); + spin_lock_bh(&e->lock); + if (e->state == L2T_STATE_STALE) + e->state = L2T_STATE_VALID; + spin_unlock_bh(&e->lock); + case L2T_STATE_VALID: /* fast-path, send the packet on */ + return t4_ofld_send(adap, skb); + case L2T_STATE_RESOLVING: + case L2T_STATE_SYNC_WRITE: + spin_lock_bh(&e->lock); + if (e->state != L2T_STATE_SYNC_WRITE && + e->state != L2T_STATE_RESOLVING) { + spin_unlock_bh(&e->lock); + goto again; + } + arpq_enqueue(e, skb); + spin_unlock_bh(&e->lock); + + if (e->state == L2T_STATE_RESOLVING && + !neigh_event_send(e->neigh, NULL)) { + spin_lock_bh(&e->lock); + if (e->state == L2T_STATE_RESOLVING && e->arpq_head) + write_l2e(adap, e, 1); + spin_unlock_bh(&e->lock); + } + } + return 0; +} +EXPORT_SYMBOL(cxgb4_l2t_send); + +/* + * Allocate a free L2T entry. Must be called with l2t_data.lock held. + */ +static struct l2t_entry *alloc_l2e(struct l2t_data *d) +{ + struct l2t_entry *end, *e, **p; + + if (!atomic_read(&d->nfree)) + return NULL; + + /* there's definitely a free entry */ + for (e = d->rover, end = &d->l2tab[L2T_SIZE]; e != end; ++e) + if (atomic_read(&e->refcnt) == 0) + goto found; + + for (e = d->l2tab; atomic_read(&e->refcnt); ++e) + ; +found: + d->rover = e + 1; + atomic_dec(&d->nfree); + + /* + * The entry we found may be an inactive entry that is + * presently in the hash table. We need to remove it. + */ + if (e->state < L2T_STATE_SWITCHING) + for (p = &d->l2tab[e->hash].first; *p; p = &(*p)->next) + if (*p == e) { + *p = e->next; + e->next = NULL; + break; + } + + e->state = L2T_STATE_UNUSED; + return e; +} + +/* + * Called when an L2T entry has no more users. + */ +static void t4_l2e_free(struct l2t_entry *e) +{ + struct l2t_data *d; + + spin_lock_bh(&e->lock); + if (atomic_read(&e->refcnt) == 0) { /* hasn't been recycled */ + if (e->neigh) { + neigh_release(e->neigh); + e->neigh = NULL; + } + while (e->arpq_head) { + struct sk_buff *skb = e->arpq_head; + + e->arpq_head = skb->next; + kfree_skb(skb); + } + e->arpq_tail = NULL; + } + spin_unlock_bh(&e->lock); + + d = container_of(e, struct l2t_data, l2tab[e->idx]); + atomic_inc(&d->nfree); +} + +void cxgb4_l2t_release(struct l2t_entry *e) +{ + if (atomic_dec_and_test(&e->refcnt)) + t4_l2e_free(e); +} +EXPORT_SYMBOL(cxgb4_l2t_release); + +/* + * Update an L2T entry that was previously used for the same next hop as neigh. + * Must be called with softirqs disabled. + */ +static void reuse_entry(struct l2t_entry *e, struct neighbour *neigh) +{ + unsigned int nud_state; + + spin_lock(&e->lock); /* avoid race with t4_l2t_free */ + if (neigh != e->neigh) + neigh_replace(e, neigh); + nud_state = neigh->nud_state; + if (memcmp(e->dmac, neigh->ha, sizeof(e->dmac)) || + !(nud_state & NUD_VALID)) + e->state = L2T_STATE_RESOLVING; + else if (nud_state & NUD_CONNECTED) + e->state = L2T_STATE_VALID; + else + e->state = L2T_STATE_STALE; + spin_unlock(&e->lock); +} + +struct l2t_entry *cxgb4_l2t_get(struct l2t_data *d, struct neighbour *neigh, + const struct net_device *physdev, + unsigned int priority) +{ + u8 lport; + u16 vlan; + struct l2t_entry *e; + int addr_len = neigh->tbl->key_len; + u32 *addr = (u32 *)neigh->primary_key; + int ifidx = neigh->dev->ifindex; + int hash = addr_hash(addr, addr_len, ifidx); + + if (neigh->dev->flags & IFF_LOOPBACK) + lport = netdev2pinfo(physdev)->tx_chan + 4; + else + lport = netdev2pinfo(physdev)->lport; + + if (neigh->dev->priv_flags & IFF_802_1Q_VLAN) + vlan = vlan_dev_vlan_id(neigh->dev); + else + vlan = VLAN_NONE; + + write_lock_bh(&d->lock); + for (e = d->l2tab[hash].first; e; e = e->next) + if (!addreq(e, addr) && e->ifindex == ifidx && + e->vlan == vlan && e->lport == lport) { + l2t_hold(d, e); + if (atomic_read(&e->refcnt) == 1) + reuse_entry(e, neigh); + goto done; + } + + /* Need to allocate a new entry */ + e = alloc_l2e(d); + if (e) { + spin_lock(&e->lock); /* avoid race with t4_l2t_free */ + e->state = L2T_STATE_RESOLVING; + memcpy(e->addr, addr, addr_len); + e->ifindex = ifidx; + e->hash = hash; + e->lport = lport; + e->v6 = addr_len == 16; + atomic_set(&e->refcnt, 1); + neigh_replace(e, neigh); + e->vlan = vlan; + e->next = d->l2tab[hash].first; + d->l2tab[hash].first = e; + spin_unlock(&e->lock); + } +done: + write_unlock_bh(&d->lock); + return e; +} +EXPORT_SYMBOL(cxgb4_l2t_get); + +/* + * Called when address resolution fails for an L2T entry to handle packets + * on the arpq head. If a packet specifies a failure handler it is invoked, + * otherwise the packet is sent to the device. + */ +static void handle_failed_resolution(struct adapter *adap, struct sk_buff *arpq) +{ + while (arpq) { + struct sk_buff *skb = arpq; + const struct l2t_skb_cb *cb = L2T_SKB_CB(skb); + + arpq = skb->next; + skb->next = NULL; + if (cb->arp_err_handler) + cb->arp_err_handler(cb->handle, skb); + else + t4_ofld_send(adap, skb); + } +} + +/* + * Called when the host's neighbor layer makes a change to some entry that is + * loaded into the HW L2 table. + */ +void t4_l2t_update(struct adapter *adap, struct neighbour *neigh) +{ + struct l2t_entry *e; + struct sk_buff *arpq = NULL; + struct l2t_data *d = adap->l2t; + int addr_len = neigh->tbl->key_len; + u32 *addr = (u32 *) neigh->primary_key; + int ifidx = neigh->dev->ifindex; + int hash = addr_hash(addr, addr_len, ifidx); + + read_lock_bh(&d->lock); + for (e = d->l2tab[hash].first; e; e = e->next) + if (!addreq(e, addr) && e->ifindex == ifidx) { + spin_lock(&e->lock); + if (atomic_read(&e->refcnt)) + goto found; + spin_unlock(&e->lock); + break; + } + read_unlock_bh(&d->lock); + return; + + found: + read_unlock(&d->lock); + + if (neigh != e->neigh) + neigh_replace(e, neigh); + + if (e->state == L2T_STATE_RESOLVING) { + if (neigh->nud_state & NUD_FAILED) { + arpq = e->arpq_head; + e->arpq_head = e->arpq_tail = NULL; + } else if ((neigh->nud_state & (NUD_CONNECTED | NUD_STALE)) && + e->arpq_head) { + write_l2e(adap, e, 1); + } + } else { + e->state = neigh->nud_state & NUD_CONNECTED ? + L2T_STATE_VALID : L2T_STATE_STALE; + if (memcmp(e->dmac, neigh->ha, sizeof(e->dmac))) + write_l2e(adap, e, 0); + } + + spin_unlock_bh(&e->lock); + + if (arpq) + handle_failed_resolution(adap, arpq); +} + +struct l2t_data *t4_init_l2t(void) +{ + int i; + struct l2t_data *d; + + d = t4_alloc_mem(sizeof(*d)); + if (!d) + return NULL; + + d->rover = d->l2tab; + atomic_set(&d->nfree, L2T_SIZE); + rwlock_init(&d->lock); + + for (i = 0; i < L2T_SIZE; ++i) { + d->l2tab[i].idx = i; + d->l2tab[i].state = L2T_STATE_UNUSED; + spin_lock_init(&d->l2tab[i].lock); + atomic_set(&d->l2tab[i].refcnt, 0); + } + return d; +} + +#include +#include +#include + +static inline void *l2t_get_idx(struct seq_file *seq, loff_t pos) +{ + struct l2t_entry *l2tab = seq->private; + + return pos >= L2T_SIZE ? NULL : &l2tab[pos]; +} + +static void *l2t_seq_start(struct seq_file *seq, loff_t *pos) +{ + return *pos ? l2t_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; +} + +static void *l2t_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + v = l2t_get_idx(seq, *pos); + if (v) + ++*pos; + return v; +} + +static void l2t_seq_stop(struct seq_file *seq, void *v) +{ +} + +static char l2e_state(const struct l2t_entry *e) +{ + switch (e->state) { + case L2T_STATE_VALID: return 'V'; + case L2T_STATE_STALE: return 'S'; + case L2T_STATE_SYNC_WRITE: return 'W'; + case L2T_STATE_RESOLVING: return e->arpq_head ? 'A' : 'R'; + case L2T_STATE_SWITCHING: return 'X'; + default: + return 'U'; + } +} + +static int l2t_seq_show(struct seq_file *seq, void *v) +{ + if (v == SEQ_START_TOKEN) + seq_puts(seq, " Idx IP address " + "Ethernet address VLAN/P LP State Users Port\n"); + else { + char ip[60]; + struct l2t_entry *e = v; + + spin_lock_bh(&e->lock); + if (e->state == L2T_STATE_SWITCHING) + ip[0] = '\0'; + else + sprintf(ip, e->v6 ? "%pI6c" : "%pI4", e->addr); + seq_printf(seq, "%4u %-25s %17pM %4d %u %2u %c %5u %s\n", + e->idx, ip, e->dmac, + e->vlan & VLAN_VID_MASK, vlan_prio(e), e->lport, + l2e_state(e), atomic_read(&e->refcnt), + e->neigh ? e->neigh->dev->name : ""); + spin_unlock_bh(&e->lock); + } + return 0; +} + +static const struct seq_operations l2t_seq_ops = { + .start = l2t_seq_start, + .next = l2t_seq_next, + .stop = l2t_seq_stop, + .show = l2t_seq_show +}; + +static int l2t_seq_open(struct inode *inode, struct file *file) +{ + int rc = seq_open(file, &l2t_seq_ops); + + if (!rc) { + struct adapter *adap = inode->i_private; + struct seq_file *seq = file->private_data; + + seq->private = adap->l2t->l2tab; + } + return rc; +} + +const struct file_operations t4_l2t_fops = { + .owner = THIS_MODULE, + .open = l2t_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.h b/drivers/net/ethernet/chelsio/cxgb4/l2t.h new file mode 100644 index 000000000000..02b31d0c6410 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.h @@ -0,0 +1,107 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __CXGB4_L2T_H +#define __CXGB4_L2T_H + +#include +#include +#include + +struct adapter; +struct l2t_data; +struct neighbour; +struct net_device; +struct file_operations; +struct cpl_l2t_write_rpl; + +/* + * Each L2T entry plays multiple roles. First of all, it keeps state for the + * corresponding entry of the HW L2 table and maintains a queue of offload + * packets awaiting address resolution. Second, it is a node of a hash table + * chain, where the nodes of the chain are linked together through their next + * pointer. Finally, each node is a bucket of a hash table, pointing to the + * first element in its chain through its first pointer. + */ +struct l2t_entry { + u16 state; /* entry state */ + u16 idx; /* entry index */ + u32 addr[4]; /* next hop IP or IPv6 address */ + int ifindex; /* neighbor's net_device's ifindex */ + struct neighbour *neigh; /* associated neighbour */ + struct l2t_entry *first; /* start of hash chain */ + struct l2t_entry *next; /* next l2t_entry on chain */ + struct sk_buff *arpq_head; /* queue of packets awaiting resolution */ + struct sk_buff *arpq_tail; + spinlock_t lock; + atomic_t refcnt; /* entry reference count */ + u16 hash; /* hash bucket the entry is on */ + u16 vlan; /* VLAN TCI (id: bits 0-11, prio: 13-15 */ + u8 v6; /* whether entry is for IPv6 */ + u8 lport; /* associated offload logical interface */ + u8 dmac[ETH_ALEN]; /* neighbour's MAC address */ +}; + +typedef void (*arp_err_handler_t)(void *handle, struct sk_buff *skb); + +/* + * Callback stored in an skb to handle address resolution failure. + */ +struct l2t_skb_cb { + void *handle; + arp_err_handler_t arp_err_handler; +}; + +#define L2T_SKB_CB(skb) ((struct l2t_skb_cb *)(skb)->cb) + +static inline void t4_set_arp_err_handler(struct sk_buff *skb, void *handle, + arp_err_handler_t handler) +{ + L2T_SKB_CB(skb)->handle = handle; + L2T_SKB_CB(skb)->arp_err_handler = handler; +} + +void cxgb4_l2t_release(struct l2t_entry *e); +int cxgb4_l2t_send(struct net_device *dev, struct sk_buff *skb, + struct l2t_entry *e); +struct l2t_entry *cxgb4_l2t_get(struct l2t_data *d, struct neighbour *neigh, + const struct net_device *physdev, + unsigned int priority); + +void t4_l2t_update(struct adapter *adap, struct neighbour *neigh); +struct l2t_data *t4_init_l2t(void); +void do_l2t_write_rpl(struct adapter *p, const struct cpl_l2t_write_rpl *rpl); + +extern const struct file_operations t4_l2t_fops; +#endif /* __CXGB4_L2T_H */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c new file mode 100644 index 000000000000..56adf448b9fe --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -0,0 +1,2442 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cxgb4.h" +#include "t4_regs.h" +#include "t4_msg.h" +#include "t4fw_api.h" + +/* + * Rx buffer size. We use largish buffers if possible but settle for single + * pages under memory shortage. + */ +#if PAGE_SHIFT >= 16 +# define FL_PG_ORDER 0 +#else +# define FL_PG_ORDER (16 - PAGE_SHIFT) +#endif + +/* RX_PULL_LEN should be <= RX_COPY_THRES */ +#define RX_COPY_THRES 256 +#define RX_PULL_LEN 128 + +/* + * Main body length for sk_buffs used for Rx Ethernet packets with fragments. + * Should be >= RX_PULL_LEN but possibly bigger to give pskb_may_pull some room. + */ +#define RX_PKT_SKB_LEN 512 + +/* Ethernet header padding prepended to RX_PKTs */ +#define RX_PKT_PAD 2 + +/* + * Max number of Tx descriptors we clean up at a time. Should be modest as + * freeing skbs isn't cheap and it happens while holding locks. We just need + * to free packets faster than they arrive, we eventually catch up and keep + * the amortized cost reasonable. Must be >= 2 * TXQ_STOP_THRES. + */ +#define MAX_TX_RECLAIM 16 + +/* + * Max number of Rx buffers we replenish at a time. Again keep this modest, + * allocating buffers isn't cheap either. + */ +#define MAX_RX_REFILL 16U + +/* + * Period of the Rx queue check timer. This timer is infrequent as it has + * something to do only when the system experiences severe memory shortage. + */ +#define RX_QCHECK_PERIOD (HZ / 2) + +/* + * Period of the Tx queue check timer. + */ +#define TX_QCHECK_PERIOD (HZ / 2) + +/* + * Max number of Tx descriptors to be reclaimed by the Tx timer. + */ +#define MAX_TIMER_TX_RECLAIM 100 + +/* + * Timer index used when backing off due to memory shortage. + */ +#define NOMEM_TMR_IDX (SGE_NTIMERS - 1) + +/* + * An FL with <= FL_STARVE_THRES buffers is starving and a periodic timer will + * attempt to refill it. + */ +#define FL_STARVE_THRES 4 + +/* + * Suspend an Ethernet Tx queue with fewer available descriptors than this. + * This is the same as calc_tx_descs() for a TSO packet with + * nr_frags == MAX_SKB_FRAGS. + */ +#define ETHTXQ_STOP_THRES \ + (1 + DIV_ROUND_UP((3 * MAX_SKB_FRAGS) / 2 + (MAX_SKB_FRAGS & 1), 8)) + +/* + * Suspension threshold for non-Ethernet Tx queues. We require enough room + * for a full sized WR. + */ +#define TXQ_STOP_THRES (SGE_MAX_WR_LEN / sizeof(struct tx_desc)) + +/* + * Max Tx descriptor space we allow for an Ethernet packet to be inlined + * into a WR. + */ +#define MAX_IMM_TX_PKT_LEN 128 + +/* + * Max size of a WR sent through a control Tx queue. + */ +#define MAX_CTRL_WR_LEN SGE_MAX_WR_LEN + +enum { + /* packet alignment in FL buffers */ + FL_ALIGN = L1_CACHE_BYTES < 32 ? 32 : L1_CACHE_BYTES, + /* egress status entry size */ + STAT_LEN = L1_CACHE_BYTES > 64 ? 128 : 64 +}; + +struct tx_sw_desc { /* SW state per Tx descriptor */ + struct sk_buff *skb; + struct ulptx_sgl *sgl; +}; + +struct rx_sw_desc { /* SW state per Rx descriptor */ + struct page *page; + dma_addr_t dma_addr; +}; + +/* + * The low bits of rx_sw_desc.dma_addr have special meaning. + */ +enum { + RX_LARGE_BUF = 1 << 0, /* buffer is larger than PAGE_SIZE */ + RX_UNMAPPED_BUF = 1 << 1, /* buffer is not mapped */ +}; + +static inline dma_addr_t get_buf_addr(const struct rx_sw_desc *d) +{ + return d->dma_addr & ~(dma_addr_t)(RX_LARGE_BUF | RX_UNMAPPED_BUF); +} + +static inline bool is_buf_mapped(const struct rx_sw_desc *d) +{ + return !(d->dma_addr & RX_UNMAPPED_BUF); +} + +/** + * txq_avail - return the number of available slots in a Tx queue + * @q: the Tx queue + * + * Returns the number of descriptors in a Tx queue available to write new + * packets. + */ +static inline unsigned int txq_avail(const struct sge_txq *q) +{ + return q->size - 1 - q->in_use; +} + +/** + * fl_cap - return the capacity of a free-buffer list + * @fl: the FL + * + * Returns the capacity of a free-buffer list. The capacity is less than + * the size because one descriptor needs to be left unpopulated, otherwise + * HW will think the FL is empty. + */ +static inline unsigned int fl_cap(const struct sge_fl *fl) +{ + return fl->size - 8; /* 1 descriptor = 8 buffers */ +} + +static inline bool fl_starving(const struct sge_fl *fl) +{ + return fl->avail - fl->pend_cred <= FL_STARVE_THRES; +} + +static int map_skb(struct device *dev, const struct sk_buff *skb, + dma_addr_t *addr) +{ + const skb_frag_t *fp, *end; + const struct skb_shared_info *si; + + *addr = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); + if (dma_mapping_error(dev, *addr)) + goto out_err; + + si = skb_shinfo(skb); + end = &si->frags[si->nr_frags]; + + for (fp = si->frags; fp < end; fp++) { + *++addr = dma_map_page(dev, fp->page, fp->page_offset, fp->size, + DMA_TO_DEVICE); + if (dma_mapping_error(dev, *addr)) + goto unwind; + } + return 0; + +unwind: + while (fp-- > si->frags) + dma_unmap_page(dev, *--addr, fp->size, DMA_TO_DEVICE); + + dma_unmap_single(dev, addr[-1], skb_headlen(skb), DMA_TO_DEVICE); +out_err: + return -ENOMEM; +} + +#ifdef CONFIG_NEED_DMA_MAP_STATE +static void unmap_skb(struct device *dev, const struct sk_buff *skb, + const dma_addr_t *addr) +{ + const skb_frag_t *fp, *end; + const struct skb_shared_info *si; + + dma_unmap_single(dev, *addr++, skb_headlen(skb), DMA_TO_DEVICE); + + si = skb_shinfo(skb); + end = &si->frags[si->nr_frags]; + for (fp = si->frags; fp < end; fp++) + dma_unmap_page(dev, *addr++, fp->size, DMA_TO_DEVICE); +} + +/** + * deferred_unmap_destructor - unmap a packet when it is freed + * @skb: the packet + * + * This is the packet destructor used for Tx packets that need to remain + * mapped until they are freed rather than until their Tx descriptors are + * freed. + */ +static void deferred_unmap_destructor(struct sk_buff *skb) +{ + unmap_skb(skb->dev->dev.parent, skb, (dma_addr_t *)skb->head); +} +#endif + +static void unmap_sgl(struct device *dev, const struct sk_buff *skb, + const struct ulptx_sgl *sgl, const struct sge_txq *q) +{ + const struct ulptx_sge_pair *p; + unsigned int nfrags = skb_shinfo(skb)->nr_frags; + + if (likely(skb_headlen(skb))) + dma_unmap_single(dev, be64_to_cpu(sgl->addr0), ntohl(sgl->len0), + DMA_TO_DEVICE); + else { + dma_unmap_page(dev, be64_to_cpu(sgl->addr0), ntohl(sgl->len0), + DMA_TO_DEVICE); + nfrags--; + } + + /* + * the complexity below is because of the possibility of a wrap-around + * in the middle of an SGL + */ + for (p = sgl->sge; nfrags >= 2; nfrags -= 2) { + if (likely((u8 *)(p + 1) <= (u8 *)q->stat)) { +unmap: dma_unmap_page(dev, be64_to_cpu(p->addr[0]), + ntohl(p->len[0]), DMA_TO_DEVICE); + dma_unmap_page(dev, be64_to_cpu(p->addr[1]), + ntohl(p->len[1]), DMA_TO_DEVICE); + p++; + } else if ((u8 *)p == (u8 *)q->stat) { + p = (const struct ulptx_sge_pair *)q->desc; + goto unmap; + } else if ((u8 *)p + 8 == (u8 *)q->stat) { + const __be64 *addr = (const __be64 *)q->desc; + + dma_unmap_page(dev, be64_to_cpu(addr[0]), + ntohl(p->len[0]), DMA_TO_DEVICE); + dma_unmap_page(dev, be64_to_cpu(addr[1]), + ntohl(p->len[1]), DMA_TO_DEVICE); + p = (const struct ulptx_sge_pair *)&addr[2]; + } else { + const __be64 *addr = (const __be64 *)q->desc; + + dma_unmap_page(dev, be64_to_cpu(p->addr[0]), + ntohl(p->len[0]), DMA_TO_DEVICE); + dma_unmap_page(dev, be64_to_cpu(addr[0]), + ntohl(p->len[1]), DMA_TO_DEVICE); + p = (const struct ulptx_sge_pair *)&addr[1]; + } + } + if (nfrags) { + __be64 addr; + + if ((u8 *)p == (u8 *)q->stat) + p = (const struct ulptx_sge_pair *)q->desc; + addr = (u8 *)p + 16 <= (u8 *)q->stat ? p->addr[0] : + *(const __be64 *)q->desc; + dma_unmap_page(dev, be64_to_cpu(addr), ntohl(p->len[0]), + DMA_TO_DEVICE); + } +} + +/** + * free_tx_desc - reclaims Tx descriptors and their buffers + * @adapter: the adapter + * @q: the Tx queue to reclaim descriptors from + * @n: the number of descriptors to reclaim + * @unmap: whether the buffers should be unmapped for DMA + * + * Reclaims Tx descriptors from an SGE Tx queue and frees the associated + * Tx buffers. Called with the Tx queue lock held. + */ +static void free_tx_desc(struct adapter *adap, struct sge_txq *q, + unsigned int n, bool unmap) +{ + struct tx_sw_desc *d; + unsigned int cidx = q->cidx; + struct device *dev = adap->pdev_dev; + + d = &q->sdesc[cidx]; + while (n--) { + if (d->skb) { /* an SGL is present */ + if (unmap) + unmap_sgl(dev, d->skb, d->sgl, q); + kfree_skb(d->skb); + d->skb = NULL; + } + ++d; + if (++cidx == q->size) { + cidx = 0; + d = q->sdesc; + } + } + q->cidx = cidx; +} + +/* + * Return the number of reclaimable descriptors in a Tx queue. + */ +static inline int reclaimable(const struct sge_txq *q) +{ + int hw_cidx = ntohs(q->stat->cidx); + hw_cidx -= q->cidx; + return hw_cidx < 0 ? hw_cidx + q->size : hw_cidx; +} + +/** + * reclaim_completed_tx - reclaims completed Tx descriptors + * @adap: the adapter + * @q: the Tx queue to reclaim completed descriptors from + * @unmap: whether the buffers should be unmapped for DMA + * + * Reclaims Tx descriptors that the SGE has indicated it has processed, + * and frees the associated buffers if possible. Called with the Tx + * queue locked. + */ +static inline void reclaim_completed_tx(struct adapter *adap, struct sge_txq *q, + bool unmap) +{ + int avail = reclaimable(q); + + if (avail) { + /* + * Limit the amount of clean up work we do at a time to keep + * the Tx lock hold time O(1). + */ + if (avail > MAX_TX_RECLAIM) + avail = MAX_TX_RECLAIM; + + free_tx_desc(adap, q, avail, unmap); + q->in_use -= avail; + } +} + +static inline int get_buf_size(const struct rx_sw_desc *d) +{ +#if FL_PG_ORDER > 0 + return (d->dma_addr & RX_LARGE_BUF) ? (PAGE_SIZE << FL_PG_ORDER) : + PAGE_SIZE; +#else + return PAGE_SIZE; +#endif +} + +/** + * free_rx_bufs - free the Rx buffers on an SGE free list + * @adap: the adapter + * @q: the SGE free list to free buffers from + * @n: how many buffers to free + * + * Release the next @n buffers on an SGE free-buffer Rx queue. The + * buffers must be made inaccessible to HW before calling this function. + */ +static void free_rx_bufs(struct adapter *adap, struct sge_fl *q, int n) +{ + while (n--) { + struct rx_sw_desc *d = &q->sdesc[q->cidx]; + + if (is_buf_mapped(d)) + dma_unmap_page(adap->pdev_dev, get_buf_addr(d), + get_buf_size(d), PCI_DMA_FROMDEVICE); + put_page(d->page); + d->page = NULL; + if (++q->cidx == q->size) + q->cidx = 0; + q->avail--; + } +} + +/** + * unmap_rx_buf - unmap the current Rx buffer on an SGE free list + * @adap: the adapter + * @q: the SGE free list + * + * Unmap the current buffer on an SGE free-buffer Rx queue. The + * buffer must be made inaccessible to HW before calling this function. + * + * This is similar to @free_rx_bufs above but does not free the buffer. + * Do note that the FL still loses any further access to the buffer. + */ +static void unmap_rx_buf(struct adapter *adap, struct sge_fl *q) +{ + struct rx_sw_desc *d = &q->sdesc[q->cidx]; + + if (is_buf_mapped(d)) + dma_unmap_page(adap->pdev_dev, get_buf_addr(d), + get_buf_size(d), PCI_DMA_FROMDEVICE); + d->page = NULL; + if (++q->cidx == q->size) + q->cidx = 0; + q->avail--; +} + +static inline void ring_fl_db(struct adapter *adap, struct sge_fl *q) +{ + if (q->pend_cred >= 8) { + wmb(); + t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL), DBPRIO | + QID(q->cntxt_id) | PIDX(q->pend_cred / 8)); + q->pend_cred &= 7; + } +} + +static inline void set_rx_sw_desc(struct rx_sw_desc *sd, struct page *pg, + dma_addr_t mapping) +{ + sd->page = pg; + sd->dma_addr = mapping; /* includes size low bits */ +} + +/** + * refill_fl - refill an SGE Rx buffer ring + * @adap: the adapter + * @q: the ring to refill + * @n: the number of new buffers to allocate + * @gfp: the gfp flags for the allocations + * + * (Re)populate an SGE free-buffer queue with up to @n new packet buffers, + * allocated with the supplied gfp flags. The caller must assure that + * @n does not exceed the queue's capacity. If afterwards the queue is + * found critically low mark it as starving in the bitmap of starving FLs. + * + * Returns the number of buffers allocated. + */ +static unsigned int refill_fl(struct adapter *adap, struct sge_fl *q, int n, + gfp_t gfp) +{ + struct page *pg; + dma_addr_t mapping; + unsigned int cred = q->avail; + __be64 *d = &q->desc[q->pidx]; + struct rx_sw_desc *sd = &q->sdesc[q->pidx]; + + gfp |= __GFP_NOWARN; /* failures are expected */ + +#if FL_PG_ORDER > 0 + /* + * Prefer large buffers + */ + while (n) { + pg = alloc_pages(gfp | __GFP_COMP, FL_PG_ORDER); + if (unlikely(!pg)) { + q->large_alloc_failed++; + break; /* fall back to single pages */ + } + + mapping = dma_map_page(adap->pdev_dev, pg, 0, + PAGE_SIZE << FL_PG_ORDER, + PCI_DMA_FROMDEVICE); + if (unlikely(dma_mapping_error(adap->pdev_dev, mapping))) { + __free_pages(pg, FL_PG_ORDER); + goto out; /* do not try small pages for this error */ + } + mapping |= RX_LARGE_BUF; + *d++ = cpu_to_be64(mapping); + + set_rx_sw_desc(sd, pg, mapping); + sd++; + + q->avail++; + if (++q->pidx == q->size) { + q->pidx = 0; + sd = q->sdesc; + d = q->desc; + } + n--; + } +#endif + + while (n--) { + pg = __netdev_alloc_page(adap->port[0], gfp); + if (unlikely(!pg)) { + q->alloc_failed++; + break; + } + + mapping = dma_map_page(adap->pdev_dev, pg, 0, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + if (unlikely(dma_mapping_error(adap->pdev_dev, mapping))) { + netdev_free_page(adap->port[0], pg); + goto out; + } + *d++ = cpu_to_be64(mapping); + + set_rx_sw_desc(sd, pg, mapping); + sd++; + + q->avail++; + if (++q->pidx == q->size) { + q->pidx = 0; + sd = q->sdesc; + d = q->desc; + } + } + +out: cred = q->avail - cred; + q->pend_cred += cred; + ring_fl_db(adap, q); + + if (unlikely(fl_starving(q))) { + smp_wmb(); + set_bit(q->cntxt_id - adap->sge.egr_start, + adap->sge.starving_fl); + } + + return cred; +} + +static inline void __refill_fl(struct adapter *adap, struct sge_fl *fl) +{ + refill_fl(adap, fl, min(MAX_RX_REFILL, fl_cap(fl) - fl->avail), + GFP_ATOMIC); +} + +/** + * alloc_ring - allocate resources for an SGE descriptor ring + * @dev: the PCI device's core device + * @nelem: the number of descriptors + * @elem_size: the size of each descriptor + * @sw_size: the size of the SW state associated with each ring element + * @phys: the physical address of the allocated ring + * @metadata: address of the array holding the SW state for the ring + * @stat_size: extra space in HW ring for status information + * @node: preferred node for memory allocations + * + * Allocates resources for an SGE descriptor ring, such as Tx queues, + * free buffer lists, or response queues. Each SGE ring requires + * space for its HW descriptors plus, optionally, space for the SW state + * associated with each HW entry (the metadata). The function returns + * three values: the virtual address for the HW ring (the return value + * of the function), the bus address of the HW ring, and the address + * of the SW ring. + */ +static void *alloc_ring(struct device *dev, size_t nelem, size_t elem_size, + size_t sw_size, dma_addr_t *phys, void *metadata, + size_t stat_size, int node) +{ + size_t len = nelem * elem_size + stat_size; + void *s = NULL; + void *p = dma_alloc_coherent(dev, len, phys, GFP_KERNEL); + + if (!p) + return NULL; + if (sw_size) { + s = kzalloc_node(nelem * sw_size, GFP_KERNEL, node); + + if (!s) { + dma_free_coherent(dev, len, p, *phys); + return NULL; + } + } + if (metadata) + *(void **)metadata = s; + memset(p, 0, len); + return p; +} + +/** + * sgl_len - calculates the size of an SGL of the given capacity + * @n: the number of SGL entries + * + * Calculates the number of flits needed for a scatter/gather list that + * can hold the given number of entries. + */ +static inline unsigned int sgl_len(unsigned int n) +{ + n--; + return (3 * n) / 2 + (n & 1) + 2; +} + +/** + * flits_to_desc - returns the num of Tx descriptors for the given flits + * @n: the number of flits + * + * Returns the number of Tx descriptors needed for the supplied number + * of flits. + */ +static inline unsigned int flits_to_desc(unsigned int n) +{ + BUG_ON(n > SGE_MAX_WR_LEN / 8); + return DIV_ROUND_UP(n, 8); +} + +/** + * is_eth_imm - can an Ethernet packet be sent as immediate data? + * @skb: the packet + * + * Returns whether an Ethernet packet is small enough to fit as + * immediate data. + */ +static inline int is_eth_imm(const struct sk_buff *skb) +{ + return skb->len <= MAX_IMM_TX_PKT_LEN - sizeof(struct cpl_tx_pkt); +} + +/** + * calc_tx_flits - calculate the number of flits for a packet Tx WR + * @skb: the packet + * + * Returns the number of flits needed for a Tx WR for the given Ethernet + * packet, including the needed WR and CPL headers. + */ +static inline unsigned int calc_tx_flits(const struct sk_buff *skb) +{ + unsigned int flits; + + if (is_eth_imm(skb)) + return DIV_ROUND_UP(skb->len + sizeof(struct cpl_tx_pkt), 8); + + flits = sgl_len(skb_shinfo(skb)->nr_frags + 1) + 4; + if (skb_shinfo(skb)->gso_size) + flits += 2; + return flits; +} + +/** + * calc_tx_descs - calculate the number of Tx descriptors for a packet + * @skb: the packet + * + * Returns the number of Tx descriptors needed for the given Ethernet + * packet, including the needed WR and CPL headers. + */ +static inline unsigned int calc_tx_descs(const struct sk_buff *skb) +{ + return flits_to_desc(calc_tx_flits(skb)); +} + +/** + * write_sgl - populate a scatter/gather list for a packet + * @skb: the packet + * @q: the Tx queue we are writing into + * @sgl: starting location for writing the SGL + * @end: points right after the end of the SGL + * @start: start offset into skb main-body data to include in the SGL + * @addr: the list of bus addresses for the SGL elements + * + * Generates a gather list for the buffers that make up a packet. + * The caller must provide adequate space for the SGL that will be written. + * The SGL includes all of the packet's page fragments and the data in its + * main body except for the first @start bytes. @sgl must be 16-byte + * aligned and within a Tx descriptor with available space. @end points + * right after the end of the SGL but does not account for any potential + * wrap around, i.e., @end > @sgl. + */ +static void write_sgl(const struct sk_buff *skb, struct sge_txq *q, + struct ulptx_sgl *sgl, u64 *end, unsigned int start, + const dma_addr_t *addr) +{ + unsigned int i, len; + struct ulptx_sge_pair *to; + const struct skb_shared_info *si = skb_shinfo(skb); + unsigned int nfrags = si->nr_frags; + struct ulptx_sge_pair buf[MAX_SKB_FRAGS / 2 + 1]; + + len = skb_headlen(skb) - start; + if (likely(len)) { + sgl->len0 = htonl(len); + sgl->addr0 = cpu_to_be64(addr[0] + start); + nfrags++; + } else { + sgl->len0 = htonl(si->frags[0].size); + sgl->addr0 = cpu_to_be64(addr[1]); + } + + sgl->cmd_nsge = htonl(ULPTX_CMD(ULP_TX_SC_DSGL) | ULPTX_NSGE(nfrags)); + if (likely(--nfrags == 0)) + return; + /* + * Most of the complexity below deals with the possibility we hit the + * end of the queue in the middle of writing the SGL. For this case + * only we create the SGL in a temporary buffer and then copy it. + */ + to = (u8 *)end > (u8 *)q->stat ? buf : sgl->sge; + + for (i = (nfrags != si->nr_frags); nfrags >= 2; nfrags -= 2, to++) { + to->len[0] = cpu_to_be32(si->frags[i].size); + to->len[1] = cpu_to_be32(si->frags[++i].size); + to->addr[0] = cpu_to_be64(addr[i]); + to->addr[1] = cpu_to_be64(addr[++i]); + } + if (nfrags) { + to->len[0] = cpu_to_be32(si->frags[i].size); + to->len[1] = cpu_to_be32(0); + to->addr[0] = cpu_to_be64(addr[i + 1]); + } + if (unlikely((u8 *)end > (u8 *)q->stat)) { + unsigned int part0 = (u8 *)q->stat - (u8 *)sgl->sge, part1; + + if (likely(part0)) + memcpy(sgl->sge, buf, part0); + part1 = (u8 *)end - (u8 *)q->stat; + memcpy(q->desc, (u8 *)buf + part0, part1); + end = (void *)q->desc + part1; + } + if ((uintptr_t)end & 8) /* 0-pad to multiple of 16 */ + *(u64 *)end = 0; +} + +/** + * ring_tx_db - check and potentially ring a Tx queue's doorbell + * @adap: the adapter + * @q: the Tx queue + * @n: number of new descriptors to give to HW + * + * Ring the doorbel for a Tx queue. + */ +static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n) +{ + wmb(); /* write descriptors before telling HW */ + t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL), + QID(q->cntxt_id) | PIDX(n)); +} + +/** + * inline_tx_skb - inline a packet's data into Tx descriptors + * @skb: the packet + * @q: the Tx queue where the packet will be inlined + * @pos: starting position in the Tx queue where to inline the packet + * + * Inline a packet's contents directly into Tx descriptors, starting at + * the given position within the Tx DMA ring. + * Most of the complexity of this operation is dealing with wrap arounds + * in the middle of the packet we want to inline. + */ +static void inline_tx_skb(const struct sk_buff *skb, const struct sge_txq *q, + void *pos) +{ + u64 *p; + int left = (void *)q->stat - pos; + + if (likely(skb->len <= left)) { + if (likely(!skb->data_len)) + skb_copy_from_linear_data(skb, pos, skb->len); + else + skb_copy_bits(skb, 0, pos, skb->len); + pos += skb->len; + } else { + skb_copy_bits(skb, 0, pos, left); + skb_copy_bits(skb, left, q->desc, skb->len - left); + pos = (void *)q->desc + (skb->len - left); + } + + /* 0-pad to multiple of 16 */ + p = PTR_ALIGN(pos, 8); + if ((uintptr_t)p & 8) + *p = 0; +} + +/* + * Figure out what HW csum a packet wants and return the appropriate control + * bits. + */ +static u64 hwcsum(const struct sk_buff *skb) +{ + int csum_type; + const struct iphdr *iph = ip_hdr(skb); + + if (iph->version == 4) { + if (iph->protocol == IPPROTO_TCP) + csum_type = TX_CSUM_TCPIP; + else if (iph->protocol == IPPROTO_UDP) + csum_type = TX_CSUM_UDPIP; + else { +nocsum: /* + * unknown protocol, disable HW csum + * and hope a bad packet is detected + */ + return TXPKT_L4CSUM_DIS; + } + } else { + /* + * this doesn't work with extension headers + */ + const struct ipv6hdr *ip6h = (const struct ipv6hdr *)iph; + + if (ip6h->nexthdr == IPPROTO_TCP) + csum_type = TX_CSUM_TCPIP6; + else if (ip6h->nexthdr == IPPROTO_UDP) + csum_type = TX_CSUM_UDPIP6; + else + goto nocsum; + } + + if (likely(csum_type >= TX_CSUM_TCPIP)) + return TXPKT_CSUM_TYPE(csum_type) | + TXPKT_IPHDR_LEN(skb_network_header_len(skb)) | + TXPKT_ETHHDR_LEN(skb_network_offset(skb) - ETH_HLEN); + else { + int start = skb_transport_offset(skb); + + return TXPKT_CSUM_TYPE(csum_type) | TXPKT_CSUM_START(start) | + TXPKT_CSUM_LOC(start + skb->csum_offset); + } +} + +static void eth_txq_stop(struct sge_eth_txq *q) +{ + netif_tx_stop_queue(q->txq); + q->q.stops++; +} + +static inline void txq_advance(struct sge_txq *q, unsigned int n) +{ + q->in_use += n; + q->pidx += n; + if (q->pidx >= q->size) + q->pidx -= q->size; +} + +/** + * t4_eth_xmit - add a packet to an Ethernet Tx queue + * @skb: the packet + * @dev: the egress net device + * + * Add a packet to an SGE Ethernet Tx queue. Runs with softirqs disabled. + */ +netdev_tx_t t4_eth_xmit(struct sk_buff *skb, struct net_device *dev) +{ + u32 wr_mid; + u64 cntrl, *end; + int qidx, credits; + unsigned int flits, ndesc; + struct adapter *adap; + struct sge_eth_txq *q; + const struct port_info *pi; + struct fw_eth_tx_pkt_wr *wr; + struct cpl_tx_pkt_core *cpl; + const struct skb_shared_info *ssi; + dma_addr_t addr[MAX_SKB_FRAGS + 1]; + + /* + * The chip min packet length is 10 octets but play safe and reject + * anything shorter than an Ethernet header. + */ + if (unlikely(skb->len < ETH_HLEN)) { +out_free: dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + + pi = netdev_priv(dev); + adap = pi->adapter; + qidx = skb_get_queue_mapping(skb); + q = &adap->sge.ethtxq[qidx + pi->first_qset]; + + reclaim_completed_tx(adap, &q->q, true); + + flits = calc_tx_flits(skb); + ndesc = flits_to_desc(flits); + credits = txq_avail(&q->q) - ndesc; + + if (unlikely(credits < 0)) { + eth_txq_stop(q); + dev_err(adap->pdev_dev, + "%s: Tx ring %u full while queue awake!\n", + dev->name, qidx); + return NETDEV_TX_BUSY; + } + + if (!is_eth_imm(skb) && + unlikely(map_skb(adap->pdev_dev, skb, addr) < 0)) { + q->mapping_err++; + goto out_free; + } + + wr_mid = FW_WR_LEN16(DIV_ROUND_UP(flits, 2)); + if (unlikely(credits < ETHTXQ_STOP_THRES)) { + eth_txq_stop(q); + wr_mid |= FW_WR_EQUEQ | FW_WR_EQUIQ; + } + + wr = (void *)&q->q.desc[q->q.pidx]; + wr->equiq_to_len16 = htonl(wr_mid); + wr->r3 = cpu_to_be64(0); + end = (u64 *)wr + flits; + + ssi = skb_shinfo(skb); + if (ssi->gso_size) { + struct cpl_tx_pkt_lso *lso = (void *)wr; + bool v6 = (ssi->gso_type & SKB_GSO_TCPV6) != 0; + int l3hdr_len = skb_network_header_len(skb); + int eth_xtra_len = skb_network_offset(skb) - ETH_HLEN; + + wr->op_immdlen = htonl(FW_WR_OP(FW_ETH_TX_PKT_WR) | + FW_WR_IMMDLEN(sizeof(*lso))); + lso->c.lso_ctrl = htonl(LSO_OPCODE(CPL_TX_PKT_LSO) | + LSO_FIRST_SLICE | LSO_LAST_SLICE | + LSO_IPV6(v6) | + LSO_ETHHDR_LEN(eth_xtra_len / 4) | + LSO_IPHDR_LEN(l3hdr_len / 4) | + LSO_TCPHDR_LEN(tcp_hdr(skb)->doff)); + lso->c.ipid_ofst = htons(0); + lso->c.mss = htons(ssi->gso_size); + lso->c.seqno_offset = htonl(0); + lso->c.len = htonl(skb->len); + cpl = (void *)(lso + 1); + cntrl = TXPKT_CSUM_TYPE(v6 ? TX_CSUM_TCPIP6 : TX_CSUM_TCPIP) | + TXPKT_IPHDR_LEN(l3hdr_len) | + TXPKT_ETHHDR_LEN(eth_xtra_len); + q->tso++; + q->tx_cso += ssi->gso_segs; + } else { + int len; + + len = is_eth_imm(skb) ? skb->len + sizeof(*cpl) : sizeof(*cpl); + wr->op_immdlen = htonl(FW_WR_OP(FW_ETH_TX_PKT_WR) | + FW_WR_IMMDLEN(len)); + cpl = (void *)(wr + 1); + if (skb->ip_summed == CHECKSUM_PARTIAL) { + cntrl = hwcsum(skb) | TXPKT_IPCSUM_DIS; + q->tx_cso++; + } else + cntrl = TXPKT_L4CSUM_DIS | TXPKT_IPCSUM_DIS; + } + + if (vlan_tx_tag_present(skb)) { + q->vlan_ins++; + cntrl |= TXPKT_VLAN_VLD | TXPKT_VLAN(vlan_tx_tag_get(skb)); + } + + cpl->ctrl0 = htonl(TXPKT_OPCODE(CPL_TX_PKT_XT) | + TXPKT_INTF(pi->tx_chan) | TXPKT_PF(adap->fn)); + cpl->pack = htons(0); + cpl->len = htons(skb->len); + cpl->ctrl1 = cpu_to_be64(cntrl); + + if (is_eth_imm(skb)) { + inline_tx_skb(skb, &q->q, cpl + 1); + dev_kfree_skb(skb); + } else { + int last_desc; + + write_sgl(skb, &q->q, (struct ulptx_sgl *)(cpl + 1), end, 0, + addr); + skb_orphan(skb); + + last_desc = q->q.pidx + ndesc - 1; + if (last_desc >= q->q.size) + last_desc -= q->q.size; + q->q.sdesc[last_desc].skb = skb; + q->q.sdesc[last_desc].sgl = (struct ulptx_sgl *)(cpl + 1); + } + + txq_advance(&q->q, ndesc); + + ring_tx_db(adap, &q->q, ndesc); + return NETDEV_TX_OK; +} + +/** + * reclaim_completed_tx_imm - reclaim completed control-queue Tx descs + * @q: the SGE control Tx queue + * + * This is a variant of reclaim_completed_tx() that is used for Tx queues + * that send only immediate data (presently just the control queues) and + * thus do not have any sk_buffs to release. + */ +static inline void reclaim_completed_tx_imm(struct sge_txq *q) +{ + int hw_cidx = ntohs(q->stat->cidx); + int reclaim = hw_cidx - q->cidx; + + if (reclaim < 0) + reclaim += q->size; + + q->in_use -= reclaim; + q->cidx = hw_cidx; +} + +/** + * is_imm - check whether a packet can be sent as immediate data + * @skb: the packet + * + * Returns true if a packet can be sent as a WR with immediate data. + */ +static inline int is_imm(const struct sk_buff *skb) +{ + return skb->len <= MAX_CTRL_WR_LEN; +} + +/** + * ctrlq_check_stop - check if a control queue is full and should stop + * @q: the queue + * @wr: most recent WR written to the queue + * + * Check if a control queue has become full and should be stopped. + * We clean up control queue descriptors very lazily, only when we are out. + * If the queue is still full after reclaiming any completed descriptors + * we suspend it and have the last WR wake it up. + */ +static void ctrlq_check_stop(struct sge_ctrl_txq *q, struct fw_wr_hdr *wr) +{ + reclaim_completed_tx_imm(&q->q); + if (unlikely(txq_avail(&q->q) < TXQ_STOP_THRES)) { + wr->lo |= htonl(FW_WR_EQUEQ | FW_WR_EQUIQ); + q->q.stops++; + q->full = 1; + } +} + +/** + * ctrl_xmit - send a packet through an SGE control Tx queue + * @q: the control queue + * @skb: the packet + * + * Send a packet through an SGE control Tx queue. Packets sent through + * a control queue must fit entirely as immediate data. + */ +static int ctrl_xmit(struct sge_ctrl_txq *q, struct sk_buff *skb) +{ + unsigned int ndesc; + struct fw_wr_hdr *wr; + + if (unlikely(!is_imm(skb))) { + WARN_ON(1); + dev_kfree_skb(skb); + return NET_XMIT_DROP; + } + + ndesc = DIV_ROUND_UP(skb->len, sizeof(struct tx_desc)); + spin_lock(&q->sendq.lock); + + if (unlikely(q->full)) { + skb->priority = ndesc; /* save for restart */ + __skb_queue_tail(&q->sendq, skb); + spin_unlock(&q->sendq.lock); + return NET_XMIT_CN; + } + + wr = (struct fw_wr_hdr *)&q->q.desc[q->q.pidx]; + inline_tx_skb(skb, &q->q, wr); + + txq_advance(&q->q, ndesc); + if (unlikely(txq_avail(&q->q) < TXQ_STOP_THRES)) + ctrlq_check_stop(q, wr); + + ring_tx_db(q->adap, &q->q, ndesc); + spin_unlock(&q->sendq.lock); + + kfree_skb(skb); + return NET_XMIT_SUCCESS; +} + +/** + * restart_ctrlq - restart a suspended control queue + * @data: the control queue to restart + * + * Resumes transmission on a suspended Tx control queue. + */ +static void restart_ctrlq(unsigned long data) +{ + struct sk_buff *skb; + unsigned int written = 0; + struct sge_ctrl_txq *q = (struct sge_ctrl_txq *)data; + + spin_lock(&q->sendq.lock); + reclaim_completed_tx_imm(&q->q); + BUG_ON(txq_avail(&q->q) < TXQ_STOP_THRES); /* q should be empty */ + + while ((skb = __skb_dequeue(&q->sendq)) != NULL) { + struct fw_wr_hdr *wr; + unsigned int ndesc = skb->priority; /* previously saved */ + + /* + * Write descriptors and free skbs outside the lock to limit + * wait times. q->full is still set so new skbs will be queued. + */ + spin_unlock(&q->sendq.lock); + + wr = (struct fw_wr_hdr *)&q->q.desc[q->q.pidx]; + inline_tx_skb(skb, &q->q, wr); + kfree_skb(skb); + + written += ndesc; + txq_advance(&q->q, ndesc); + if (unlikely(txq_avail(&q->q) < TXQ_STOP_THRES)) { + unsigned long old = q->q.stops; + + ctrlq_check_stop(q, wr); + if (q->q.stops != old) { /* suspended anew */ + spin_lock(&q->sendq.lock); + goto ringdb; + } + } + if (written > 16) { + ring_tx_db(q->adap, &q->q, written); + written = 0; + } + spin_lock(&q->sendq.lock); + } + q->full = 0; +ringdb: if (written) + ring_tx_db(q->adap, &q->q, written); + spin_unlock(&q->sendq.lock); +} + +/** + * t4_mgmt_tx - send a management message + * @adap: the adapter + * @skb: the packet containing the management message + * + * Send a management message through control queue 0. + */ +int t4_mgmt_tx(struct adapter *adap, struct sk_buff *skb) +{ + int ret; + + local_bh_disable(); + ret = ctrl_xmit(&adap->sge.ctrlq[0], skb); + local_bh_enable(); + return ret; +} + +/** + * is_ofld_imm - check whether a packet can be sent as immediate data + * @skb: the packet + * + * Returns true if a packet can be sent as an offload WR with immediate + * data. We currently use the same limit as for Ethernet packets. + */ +static inline int is_ofld_imm(const struct sk_buff *skb) +{ + return skb->len <= MAX_IMM_TX_PKT_LEN; +} + +/** + * calc_tx_flits_ofld - calculate # of flits for an offload packet + * @skb: the packet + * + * Returns the number of flits needed for the given offload packet. + * These packets are already fully constructed and no additional headers + * will be added. + */ +static inline unsigned int calc_tx_flits_ofld(const struct sk_buff *skb) +{ + unsigned int flits, cnt; + + if (is_ofld_imm(skb)) + return DIV_ROUND_UP(skb->len, 8); + + flits = skb_transport_offset(skb) / 8U; /* headers */ + cnt = skb_shinfo(skb)->nr_frags; + if (skb->tail != skb->transport_header) + cnt++; + return flits + sgl_len(cnt); +} + +/** + * txq_stop_maperr - stop a Tx queue due to I/O MMU exhaustion + * @adap: the adapter + * @q: the queue to stop + * + * Mark a Tx queue stopped due to I/O MMU exhaustion and resulting + * inability to map packets. A periodic timer attempts to restart + * queues so marked. + */ +static void txq_stop_maperr(struct sge_ofld_txq *q) +{ + q->mapping_err++; + q->q.stops++; + set_bit(q->q.cntxt_id - q->adap->sge.egr_start, + q->adap->sge.txq_maperr); +} + +/** + * ofldtxq_stop - stop an offload Tx queue that has become full + * @q: the queue to stop + * @skb: the packet causing the queue to become full + * + * Stops an offload Tx queue that has become full and modifies the packet + * being written to request a wakeup. + */ +static void ofldtxq_stop(struct sge_ofld_txq *q, struct sk_buff *skb) +{ + struct fw_wr_hdr *wr = (struct fw_wr_hdr *)skb->data; + + wr->lo |= htonl(FW_WR_EQUEQ | FW_WR_EQUIQ); + q->q.stops++; + q->full = 1; +} + +/** + * service_ofldq - restart a suspended offload queue + * @q: the offload queue + * + * Services an offload Tx queue by moving packets from its packet queue + * to the HW Tx ring. The function starts and ends with the queue locked. + */ +static void service_ofldq(struct sge_ofld_txq *q) +{ + u64 *pos; + int credits; + struct sk_buff *skb; + unsigned int written = 0; + unsigned int flits, ndesc; + + while ((skb = skb_peek(&q->sendq)) != NULL && !q->full) { + /* + * We drop the lock but leave skb on sendq, thus retaining + * exclusive access to the state of the queue. + */ + spin_unlock(&q->sendq.lock); + + reclaim_completed_tx(q->adap, &q->q, false); + + flits = skb->priority; /* previously saved */ + ndesc = flits_to_desc(flits); + credits = txq_avail(&q->q) - ndesc; + BUG_ON(credits < 0); + if (unlikely(credits < TXQ_STOP_THRES)) + ofldtxq_stop(q, skb); + + pos = (u64 *)&q->q.desc[q->q.pidx]; + if (is_ofld_imm(skb)) + inline_tx_skb(skb, &q->q, pos); + else if (map_skb(q->adap->pdev_dev, skb, + (dma_addr_t *)skb->head)) { + txq_stop_maperr(q); + spin_lock(&q->sendq.lock); + break; + } else { + int last_desc, hdr_len = skb_transport_offset(skb); + + memcpy(pos, skb->data, hdr_len); + write_sgl(skb, &q->q, (void *)pos + hdr_len, + pos + flits, hdr_len, + (dma_addr_t *)skb->head); +#ifdef CONFIG_NEED_DMA_MAP_STATE + skb->dev = q->adap->port[0]; + skb->destructor = deferred_unmap_destructor; +#endif + last_desc = q->q.pidx + ndesc - 1; + if (last_desc >= q->q.size) + last_desc -= q->q.size; + q->q.sdesc[last_desc].skb = skb; + } + + txq_advance(&q->q, ndesc); + written += ndesc; + if (unlikely(written > 32)) { + ring_tx_db(q->adap, &q->q, written); + written = 0; + } + + spin_lock(&q->sendq.lock); + __skb_unlink(skb, &q->sendq); + if (is_ofld_imm(skb)) + kfree_skb(skb); + } + if (likely(written)) + ring_tx_db(q->adap, &q->q, written); +} + +/** + * ofld_xmit - send a packet through an offload queue + * @q: the Tx offload queue + * @skb: the packet + * + * Send an offload packet through an SGE offload queue. + */ +static int ofld_xmit(struct sge_ofld_txq *q, struct sk_buff *skb) +{ + skb->priority = calc_tx_flits_ofld(skb); /* save for restart */ + spin_lock(&q->sendq.lock); + __skb_queue_tail(&q->sendq, skb); + if (q->sendq.qlen == 1) + service_ofldq(q); + spin_unlock(&q->sendq.lock); + return NET_XMIT_SUCCESS; +} + +/** + * restart_ofldq - restart a suspended offload queue + * @data: the offload queue to restart + * + * Resumes transmission on a suspended Tx offload queue. + */ +static void restart_ofldq(unsigned long data) +{ + struct sge_ofld_txq *q = (struct sge_ofld_txq *)data; + + spin_lock(&q->sendq.lock); + q->full = 0; /* the queue actually is completely empty now */ + service_ofldq(q); + spin_unlock(&q->sendq.lock); +} + +/** + * skb_txq - return the Tx queue an offload packet should use + * @skb: the packet + * + * Returns the Tx queue an offload packet should use as indicated by bits + * 1-15 in the packet's queue_mapping. + */ +static inline unsigned int skb_txq(const struct sk_buff *skb) +{ + return skb->queue_mapping >> 1; +} + +/** + * is_ctrl_pkt - return whether an offload packet is a control packet + * @skb: the packet + * + * Returns whether an offload packet should use an OFLD or a CTRL + * Tx queue as indicated by bit 0 in the packet's queue_mapping. + */ +static inline unsigned int is_ctrl_pkt(const struct sk_buff *skb) +{ + return skb->queue_mapping & 1; +} + +static inline int ofld_send(struct adapter *adap, struct sk_buff *skb) +{ + unsigned int idx = skb_txq(skb); + + if (unlikely(is_ctrl_pkt(skb))) + return ctrl_xmit(&adap->sge.ctrlq[idx], skb); + return ofld_xmit(&adap->sge.ofldtxq[idx], skb); +} + +/** + * t4_ofld_send - send an offload packet + * @adap: the adapter + * @skb: the packet + * + * Sends an offload packet. We use the packet queue_mapping to select the + * appropriate Tx queue as follows: bit 0 indicates whether the packet + * should be sent as regular or control, bits 1-15 select the queue. + */ +int t4_ofld_send(struct adapter *adap, struct sk_buff *skb) +{ + int ret; + + local_bh_disable(); + ret = ofld_send(adap, skb); + local_bh_enable(); + return ret; +} + +/** + * cxgb4_ofld_send - send an offload packet + * @dev: the net device + * @skb: the packet + * + * Sends an offload packet. This is an exported version of @t4_ofld_send, + * intended for ULDs. + */ +int cxgb4_ofld_send(struct net_device *dev, struct sk_buff *skb) +{ + return t4_ofld_send(netdev2adap(dev), skb); +} +EXPORT_SYMBOL(cxgb4_ofld_send); + +static inline void copy_frags(struct skb_shared_info *ssi, + const struct pkt_gl *gl, unsigned int offset) +{ + unsigned int n; + + /* usually there's just one frag */ + ssi->frags[0].page = gl->frags[0].page; + ssi->frags[0].page_offset = gl->frags[0].page_offset + offset; + ssi->frags[0].size = gl->frags[0].size - offset; + ssi->nr_frags = gl->nfrags; + n = gl->nfrags - 1; + if (n) + memcpy(&ssi->frags[1], &gl->frags[1], n * sizeof(skb_frag_t)); + + /* get a reference to the last page, we don't own it */ + get_page(gl->frags[n].page); +} + +/** + * cxgb4_pktgl_to_skb - build an sk_buff from a packet gather list + * @gl: the gather list + * @skb_len: size of sk_buff main body if it carries fragments + * @pull_len: amount of data to move to the sk_buff's main body + * + * Builds an sk_buff from the given packet gather list. Returns the + * sk_buff or %NULL if sk_buff allocation failed. + */ +struct sk_buff *cxgb4_pktgl_to_skb(const struct pkt_gl *gl, + unsigned int skb_len, unsigned int pull_len) +{ + struct sk_buff *skb; + + /* + * Below we rely on RX_COPY_THRES being less than the smallest Rx buffer + * size, which is expected since buffers are at least PAGE_SIZEd. + * In this case packets up to RX_COPY_THRES have only one fragment. + */ + if (gl->tot_len <= RX_COPY_THRES) { + skb = dev_alloc_skb(gl->tot_len); + if (unlikely(!skb)) + goto out; + __skb_put(skb, gl->tot_len); + skb_copy_to_linear_data(skb, gl->va, gl->tot_len); + } else { + skb = dev_alloc_skb(skb_len); + if (unlikely(!skb)) + goto out; + __skb_put(skb, pull_len); + skb_copy_to_linear_data(skb, gl->va, pull_len); + + copy_frags(skb_shinfo(skb), gl, pull_len); + skb->len = gl->tot_len; + skb->data_len = skb->len - pull_len; + skb->truesize += skb->data_len; + } +out: return skb; +} +EXPORT_SYMBOL(cxgb4_pktgl_to_skb); + +/** + * t4_pktgl_free - free a packet gather list + * @gl: the gather list + * + * Releases the pages of a packet gather list. We do not own the last + * page on the list and do not free it. + */ +static void t4_pktgl_free(const struct pkt_gl *gl) +{ + int n; + const skb_frag_t *p; + + for (p = gl->frags, n = gl->nfrags - 1; n--; p++) + put_page(p->page); +} + +/* + * Process an MPS trace packet. Give it an unused protocol number so it won't + * be delivered to anyone and send it to the stack for capture. + */ +static noinline int handle_trace_pkt(struct adapter *adap, + const struct pkt_gl *gl) +{ + struct sk_buff *skb; + struct cpl_trace_pkt *p; + + skb = cxgb4_pktgl_to_skb(gl, RX_PULL_LEN, RX_PULL_LEN); + if (unlikely(!skb)) { + t4_pktgl_free(gl); + return 0; + } + + p = (struct cpl_trace_pkt *)skb->data; + __skb_pull(skb, sizeof(*p)); + skb_reset_mac_header(skb); + skb->protocol = htons(0xffff); + skb->dev = adap->port[0]; + netif_receive_skb(skb); + return 0; +} + +static void do_gro(struct sge_eth_rxq *rxq, const struct pkt_gl *gl, + const struct cpl_rx_pkt *pkt) +{ + int ret; + struct sk_buff *skb; + + skb = napi_get_frags(&rxq->rspq.napi); + if (unlikely(!skb)) { + t4_pktgl_free(gl); + rxq->stats.rx_drops++; + return; + } + + copy_frags(skb_shinfo(skb), gl, RX_PKT_PAD); + skb->len = gl->tot_len - RX_PKT_PAD; + skb->data_len = skb->len; + skb->truesize += skb->data_len; + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb_record_rx_queue(skb, rxq->rspq.idx); + if (rxq->rspq.netdev->features & NETIF_F_RXHASH) + skb->rxhash = (__force u32)pkt->rsshdr.hash_val; + + if (unlikely(pkt->vlan_ex)) { + __vlan_hwaccel_put_tag(skb, ntohs(pkt->vlan)); + rxq->stats.vlan_ex++; + } + ret = napi_gro_frags(&rxq->rspq.napi); + if (ret == GRO_HELD) + rxq->stats.lro_pkts++; + else if (ret == GRO_MERGED || ret == GRO_MERGED_FREE) + rxq->stats.lro_merged++; + rxq->stats.pkts++; + rxq->stats.rx_cso++; +} + +/** + * t4_ethrx_handler - process an ingress ethernet packet + * @q: the response queue that received the packet + * @rsp: the response queue descriptor holding the RX_PKT message + * @si: the gather list of packet fragments + * + * Process an ingress ethernet packet and deliver it to the stack. + */ +int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, + const struct pkt_gl *si) +{ + bool csum_ok; + struct sk_buff *skb; + const struct cpl_rx_pkt *pkt; + struct sge_eth_rxq *rxq = container_of(q, struct sge_eth_rxq, rspq); + + if (unlikely(*(u8 *)rsp == CPL_TRACE_PKT)) + return handle_trace_pkt(q->adap, si); + + pkt = (const struct cpl_rx_pkt *)rsp; + csum_ok = pkt->csum_calc && !pkt->err_vec; + if ((pkt->l2info & htonl(RXF_TCP)) && + (q->netdev->features & NETIF_F_GRO) && csum_ok && !pkt->ip_frag) { + do_gro(rxq, si, pkt); + return 0; + } + + skb = cxgb4_pktgl_to_skb(si, RX_PKT_SKB_LEN, RX_PULL_LEN); + if (unlikely(!skb)) { + t4_pktgl_free(si); + rxq->stats.rx_drops++; + return 0; + } + + __skb_pull(skb, RX_PKT_PAD); /* remove ethernet header padding */ + skb->protocol = eth_type_trans(skb, q->netdev); + skb_record_rx_queue(skb, q->idx); + if (skb->dev->features & NETIF_F_RXHASH) + skb->rxhash = (__force u32)pkt->rsshdr.hash_val; + + rxq->stats.pkts++; + + if (csum_ok && (q->netdev->features & NETIF_F_RXCSUM) && + (pkt->l2info & htonl(RXF_UDP | RXF_TCP))) { + if (!pkt->ip_frag) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + rxq->stats.rx_cso++; + } else if (pkt->l2info & htonl(RXF_IP)) { + __sum16 c = (__force __sum16)pkt->csum; + skb->csum = csum_unfold(c); + skb->ip_summed = CHECKSUM_COMPLETE; + rxq->stats.rx_cso++; + } + } else + skb_checksum_none_assert(skb); + + if (unlikely(pkt->vlan_ex)) { + __vlan_hwaccel_put_tag(skb, ntohs(pkt->vlan)); + rxq->stats.vlan_ex++; + } + netif_receive_skb(skb); + return 0; +} + +/** + * restore_rx_bufs - put back a packet's Rx buffers + * @si: the packet gather list + * @q: the SGE free list + * @frags: number of FL buffers to restore + * + * Puts back on an FL the Rx buffers associated with @si. The buffers + * have already been unmapped and are left unmapped, we mark them so to + * prevent further unmapping attempts. + * + * This function undoes a series of @unmap_rx_buf calls when we find out + * that the current packet can't be processed right away afterall and we + * need to come back to it later. This is a very rare event and there's + * no effort to make this particularly efficient. + */ +static void restore_rx_bufs(const struct pkt_gl *si, struct sge_fl *q, + int frags) +{ + struct rx_sw_desc *d; + + while (frags--) { + if (q->cidx == 0) + q->cidx = q->size - 1; + else + q->cidx--; + d = &q->sdesc[q->cidx]; + d->page = si->frags[frags].page; + d->dma_addr |= RX_UNMAPPED_BUF; + q->avail++; + } +} + +/** + * is_new_response - check if a response is newly written + * @r: the response descriptor + * @q: the response queue + * + * Returns true if a response descriptor contains a yet unprocessed + * response. + */ +static inline bool is_new_response(const struct rsp_ctrl *r, + const struct sge_rspq *q) +{ + return RSPD_GEN(r->type_gen) == q->gen; +} + +/** + * rspq_next - advance to the next entry in a response queue + * @q: the queue + * + * Updates the state of a response queue to advance it to the next entry. + */ +static inline void rspq_next(struct sge_rspq *q) +{ + q->cur_desc = (void *)q->cur_desc + q->iqe_len; + if (unlikely(++q->cidx == q->size)) { + q->cidx = 0; + q->gen ^= 1; + q->cur_desc = q->desc; + } +} + +/** + * process_responses - process responses from an SGE response queue + * @q: the ingress queue to process + * @budget: how many responses can be processed in this round + * + * Process responses from an SGE response queue up to the supplied budget. + * Responses include received packets as well as control messages from FW + * or HW. + * + * Additionally choose the interrupt holdoff time for the next interrupt + * on this queue. If the system is under memory shortage use a fairly + * long delay to help recovery. + */ +static int process_responses(struct sge_rspq *q, int budget) +{ + int ret, rsp_type; + int budget_left = budget; + const struct rsp_ctrl *rc; + struct sge_eth_rxq *rxq = container_of(q, struct sge_eth_rxq, rspq); + + while (likely(budget_left)) { + rc = (void *)q->cur_desc + (q->iqe_len - sizeof(*rc)); + if (!is_new_response(rc, q)) + break; + + rmb(); + rsp_type = RSPD_TYPE(rc->type_gen); + if (likely(rsp_type == RSP_TYPE_FLBUF)) { + skb_frag_t *fp; + struct pkt_gl si; + const struct rx_sw_desc *rsd; + u32 len = ntohl(rc->pldbuflen_qid), bufsz, frags; + + if (len & RSPD_NEWBUF) { + if (likely(q->offset > 0)) { + free_rx_bufs(q->adap, &rxq->fl, 1); + q->offset = 0; + } + len = RSPD_LEN(len); + } + si.tot_len = len; + + /* gather packet fragments */ + for (frags = 0, fp = si.frags; ; frags++, fp++) { + rsd = &rxq->fl.sdesc[rxq->fl.cidx]; + bufsz = get_buf_size(rsd); + fp->page = rsd->page; + fp->page_offset = q->offset; + fp->size = min(bufsz, len); + len -= fp->size; + if (!len) + break; + unmap_rx_buf(q->adap, &rxq->fl); + } + + /* + * Last buffer remains mapped so explicitly make it + * coherent for CPU access. + */ + dma_sync_single_for_cpu(q->adap->pdev_dev, + get_buf_addr(rsd), + fp->size, DMA_FROM_DEVICE); + + si.va = page_address(si.frags[0].page) + + si.frags[0].page_offset; + prefetch(si.va); + + si.nfrags = frags + 1; + ret = q->handler(q, q->cur_desc, &si); + if (likely(ret == 0)) + q->offset += ALIGN(fp->size, FL_ALIGN); + else + restore_rx_bufs(&si, &rxq->fl, frags); + } else if (likely(rsp_type == RSP_TYPE_CPL)) { + ret = q->handler(q, q->cur_desc, NULL); + } else { + ret = q->handler(q, (const __be64 *)rc, CXGB4_MSG_AN); + } + + if (unlikely(ret)) { + /* couldn't process descriptor, back off for recovery */ + q->next_intr_params = QINTR_TIMER_IDX(NOMEM_TMR_IDX); + break; + } + + rspq_next(q); + budget_left--; + } + + if (q->offset >= 0 && rxq->fl.size - rxq->fl.avail >= 16) + __refill_fl(q->adap, &rxq->fl); + return budget - budget_left; +} + +/** + * napi_rx_handler - the NAPI handler for Rx processing + * @napi: the napi instance + * @budget: how many packets we can process in this round + * + * Handler for new data events when using NAPI. This does not need any + * locking or protection from interrupts as data interrupts are off at + * this point and other adapter interrupts do not interfere (the latter + * in not a concern at all with MSI-X as non-data interrupts then have + * a separate handler). + */ +static int napi_rx_handler(struct napi_struct *napi, int budget) +{ + unsigned int params; + struct sge_rspq *q = container_of(napi, struct sge_rspq, napi); + int work_done = process_responses(q, budget); + + if (likely(work_done < budget)) { + napi_complete(napi); + params = q->next_intr_params; + q->next_intr_params = q->intr_params; + } else + params = QINTR_TIMER_IDX(7); + + t4_write_reg(q->adap, MYPF_REG(SGE_PF_GTS), CIDXINC(work_done) | + INGRESSQID((u32)q->cntxt_id) | SEINTARM(params)); + return work_done; +} + +/* + * The MSI-X interrupt handler for an SGE response queue. + */ +irqreturn_t t4_sge_intr_msix(int irq, void *cookie) +{ + struct sge_rspq *q = cookie; + + napi_schedule(&q->napi); + return IRQ_HANDLED; +} + +/* + * Process the indirect interrupt entries in the interrupt queue and kick off + * NAPI for each queue that has generated an entry. + */ +static unsigned int process_intrq(struct adapter *adap) +{ + unsigned int credits; + const struct rsp_ctrl *rc; + struct sge_rspq *q = &adap->sge.intrq; + + spin_lock(&adap->sge.intrq_lock); + for (credits = 0; ; credits++) { + rc = (void *)q->cur_desc + (q->iqe_len - sizeof(*rc)); + if (!is_new_response(rc, q)) + break; + + rmb(); + if (RSPD_TYPE(rc->type_gen) == RSP_TYPE_INTR) { + unsigned int qid = ntohl(rc->pldbuflen_qid); + + qid -= adap->sge.ingr_start; + napi_schedule(&adap->sge.ingr_map[qid]->napi); + } + + rspq_next(q); + } + + t4_write_reg(adap, MYPF_REG(SGE_PF_GTS), CIDXINC(credits) | + INGRESSQID(q->cntxt_id) | SEINTARM(q->intr_params)); + spin_unlock(&adap->sge.intrq_lock); + return credits; +} + +/* + * The MSI interrupt handler, which handles data events from SGE response queues + * as well as error and other async events as they all use the same MSI vector. + */ +static irqreturn_t t4_intr_msi(int irq, void *cookie) +{ + struct adapter *adap = cookie; + + t4_slow_intr_handler(adap); + process_intrq(adap); + return IRQ_HANDLED; +} + +/* + * Interrupt handler for legacy INTx interrupts. + * Handles data events from SGE response queues as well as error and other + * async events as they all use the same interrupt line. + */ +static irqreturn_t t4_intr_intx(int irq, void *cookie) +{ + struct adapter *adap = cookie; + + t4_write_reg(adap, MYPF_REG(PCIE_PF_CLI), 0); + if (t4_slow_intr_handler(adap) | process_intrq(adap)) + return IRQ_HANDLED; + return IRQ_NONE; /* probably shared interrupt */ +} + +/** + * t4_intr_handler - select the top-level interrupt handler + * @adap: the adapter + * + * Selects the top-level interrupt handler based on the type of interrupts + * (MSI-X, MSI, or INTx). + */ +irq_handler_t t4_intr_handler(struct adapter *adap) +{ + if (adap->flags & USING_MSIX) + return t4_sge_intr_msix; + if (adap->flags & USING_MSI) + return t4_intr_msi; + return t4_intr_intx; +} + +static void sge_rx_timer_cb(unsigned long data) +{ + unsigned long m; + unsigned int i, cnt[2]; + struct adapter *adap = (struct adapter *)data; + struct sge *s = &adap->sge; + + for (i = 0; i < ARRAY_SIZE(s->starving_fl); i++) + for (m = s->starving_fl[i]; m; m &= m - 1) { + struct sge_eth_rxq *rxq; + unsigned int id = __ffs(m) + i * BITS_PER_LONG; + struct sge_fl *fl = s->egr_map[id]; + + clear_bit(id, s->starving_fl); + smp_mb__after_clear_bit(); + + if (fl_starving(fl)) { + rxq = container_of(fl, struct sge_eth_rxq, fl); + if (napi_reschedule(&rxq->rspq.napi)) + fl->starving++; + else + set_bit(id, s->starving_fl); + } + } + + t4_write_reg(adap, SGE_DEBUG_INDEX, 13); + cnt[0] = t4_read_reg(adap, SGE_DEBUG_DATA_HIGH); + cnt[1] = t4_read_reg(adap, SGE_DEBUG_DATA_LOW); + + for (i = 0; i < 2; i++) + if (cnt[i] >= s->starve_thres) { + if (s->idma_state[i] || cnt[i] == 0xffffffff) + continue; + s->idma_state[i] = 1; + t4_write_reg(adap, SGE_DEBUG_INDEX, 11); + m = t4_read_reg(adap, SGE_DEBUG_DATA_LOW) >> (i * 16); + dev_warn(adap->pdev_dev, + "SGE idma%u starvation detected for " + "queue %lu\n", i, m & 0xffff); + } else if (s->idma_state[i]) + s->idma_state[i] = 0; + + mod_timer(&s->rx_timer, jiffies + RX_QCHECK_PERIOD); +} + +static void sge_tx_timer_cb(unsigned long data) +{ + unsigned long m; + unsigned int i, budget; + struct adapter *adap = (struct adapter *)data; + struct sge *s = &adap->sge; + + for (i = 0; i < ARRAY_SIZE(s->txq_maperr); i++) + for (m = s->txq_maperr[i]; m; m &= m - 1) { + unsigned long id = __ffs(m) + i * BITS_PER_LONG; + struct sge_ofld_txq *txq = s->egr_map[id]; + + clear_bit(id, s->txq_maperr); + tasklet_schedule(&txq->qresume_tsk); + } + + budget = MAX_TIMER_TX_RECLAIM; + i = s->ethtxq_rover; + do { + struct sge_eth_txq *q = &s->ethtxq[i]; + + if (q->q.in_use && + time_after_eq(jiffies, q->txq->trans_start + HZ / 100) && + __netif_tx_trylock(q->txq)) { + int avail = reclaimable(&q->q); + + if (avail) { + if (avail > budget) + avail = budget; + + free_tx_desc(adap, &q->q, avail, true); + q->q.in_use -= avail; + budget -= avail; + } + __netif_tx_unlock(q->txq); + } + + if (++i >= s->ethqsets) + i = 0; + } while (budget && i != s->ethtxq_rover); + s->ethtxq_rover = i; + mod_timer(&s->tx_timer, jiffies + (budget ? TX_QCHECK_PERIOD : 2)); +} + +int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq, + struct net_device *dev, int intr_idx, + struct sge_fl *fl, rspq_handler_t hnd) +{ + int ret, flsz = 0; + struct fw_iq_cmd c; + struct port_info *pi = netdev_priv(dev); + + /* Size needs to be multiple of 16, including status entry. */ + iq->size = roundup(iq->size, 16); + + iq->desc = alloc_ring(adap->pdev_dev, iq->size, iq->iqe_len, 0, + &iq->phys_addr, NULL, 0, NUMA_NO_NODE); + if (!iq->desc) + return -ENOMEM; + + memset(&c, 0, sizeof(c)); + c.op_to_vfn = htonl(FW_CMD_OP(FW_IQ_CMD) | FW_CMD_REQUEST | + FW_CMD_WRITE | FW_CMD_EXEC | + FW_IQ_CMD_PFN(adap->fn) | FW_IQ_CMD_VFN(0)); + c.alloc_to_len16 = htonl(FW_IQ_CMD_ALLOC | FW_IQ_CMD_IQSTART(1) | + FW_LEN16(c)); + c.type_to_iqandstindex = htonl(FW_IQ_CMD_TYPE(FW_IQ_TYPE_FL_INT_CAP) | + FW_IQ_CMD_IQASYNCH(fwevtq) | FW_IQ_CMD_VIID(pi->viid) | + FW_IQ_CMD_IQANDST(intr_idx < 0) | FW_IQ_CMD_IQANUD(1) | + FW_IQ_CMD_IQANDSTINDEX(intr_idx >= 0 ? intr_idx : + -intr_idx - 1)); + c.iqdroprss_to_iqesize = htons(FW_IQ_CMD_IQPCIECH(pi->tx_chan) | + FW_IQ_CMD_IQGTSMODE | + FW_IQ_CMD_IQINTCNTTHRESH(iq->pktcnt_idx) | + FW_IQ_CMD_IQESIZE(ilog2(iq->iqe_len) - 4)); + c.iqsize = htons(iq->size); + c.iqaddr = cpu_to_be64(iq->phys_addr); + + if (fl) { + fl->size = roundup(fl->size, 8); + fl->desc = alloc_ring(adap->pdev_dev, fl->size, sizeof(__be64), + sizeof(struct rx_sw_desc), &fl->addr, + &fl->sdesc, STAT_LEN, NUMA_NO_NODE); + if (!fl->desc) + goto fl_nomem; + + flsz = fl->size / 8 + STAT_LEN / sizeof(struct tx_desc); + c.iqns_to_fl0congen = htonl(FW_IQ_CMD_FL0PACKEN | + FW_IQ_CMD_FL0FETCHRO(1) | + FW_IQ_CMD_FL0DATARO(1) | + FW_IQ_CMD_FL0PADEN); + c.fl0dcaen_to_fl0cidxfthresh = htons(FW_IQ_CMD_FL0FBMIN(2) | + FW_IQ_CMD_FL0FBMAX(3)); + c.fl0size = htons(flsz); + c.fl0addr = cpu_to_be64(fl->addr); + } + + ret = t4_wr_mbox(adap, adap->fn, &c, sizeof(c), &c); + if (ret) + goto err; + + netif_napi_add(dev, &iq->napi, napi_rx_handler, 64); + iq->cur_desc = iq->desc; + iq->cidx = 0; + iq->gen = 1; + iq->next_intr_params = iq->intr_params; + iq->cntxt_id = ntohs(c.iqid); + iq->abs_id = ntohs(c.physiqid); + iq->size--; /* subtract status entry */ + iq->adap = adap; + iq->netdev = dev; + iq->handler = hnd; + + /* set offset to -1 to distinguish ingress queues without FL */ + iq->offset = fl ? 0 : -1; + + adap->sge.ingr_map[iq->cntxt_id - adap->sge.ingr_start] = iq; + + if (fl) { + fl->cntxt_id = ntohs(c.fl0id); + fl->avail = fl->pend_cred = 0; + fl->pidx = fl->cidx = 0; + fl->alloc_failed = fl->large_alloc_failed = fl->starving = 0; + adap->sge.egr_map[fl->cntxt_id - adap->sge.egr_start] = fl; + refill_fl(adap, fl, fl_cap(fl), GFP_KERNEL); + } + return 0; + +fl_nomem: + ret = -ENOMEM; +err: + if (iq->desc) { + dma_free_coherent(adap->pdev_dev, iq->size * iq->iqe_len, + iq->desc, iq->phys_addr); + iq->desc = NULL; + } + if (fl && fl->desc) { + kfree(fl->sdesc); + fl->sdesc = NULL; + dma_free_coherent(adap->pdev_dev, flsz * sizeof(struct tx_desc), + fl->desc, fl->addr); + fl->desc = NULL; + } + return ret; +} + +static void init_txq(struct adapter *adap, struct sge_txq *q, unsigned int id) +{ + q->in_use = 0; + q->cidx = q->pidx = 0; + q->stops = q->restarts = 0; + q->stat = (void *)&q->desc[q->size]; + q->cntxt_id = id; + adap->sge.egr_map[id - adap->sge.egr_start] = q; +} + +int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq, + struct net_device *dev, struct netdev_queue *netdevq, + unsigned int iqid) +{ + int ret, nentries; + struct fw_eq_eth_cmd c; + struct port_info *pi = netdev_priv(dev); + + /* Add status entries */ + nentries = txq->q.size + STAT_LEN / sizeof(struct tx_desc); + + txq->q.desc = alloc_ring(adap->pdev_dev, txq->q.size, + sizeof(struct tx_desc), sizeof(struct tx_sw_desc), + &txq->q.phys_addr, &txq->q.sdesc, STAT_LEN, + netdev_queue_numa_node_read(netdevq)); + if (!txq->q.desc) + return -ENOMEM; + + memset(&c, 0, sizeof(c)); + c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_ETH_CMD) | FW_CMD_REQUEST | + FW_CMD_WRITE | FW_CMD_EXEC | + FW_EQ_ETH_CMD_PFN(adap->fn) | FW_EQ_ETH_CMD_VFN(0)); + c.alloc_to_len16 = htonl(FW_EQ_ETH_CMD_ALLOC | + FW_EQ_ETH_CMD_EQSTART | FW_LEN16(c)); + c.viid_pkd = htonl(FW_EQ_ETH_CMD_VIID(pi->viid)); + c.fetchszm_to_iqid = htonl(FW_EQ_ETH_CMD_HOSTFCMODE(2) | + FW_EQ_ETH_CMD_PCIECHN(pi->tx_chan) | + FW_EQ_ETH_CMD_FETCHRO(1) | + FW_EQ_ETH_CMD_IQID(iqid)); + c.dcaen_to_eqsize = htonl(FW_EQ_ETH_CMD_FBMIN(2) | + FW_EQ_ETH_CMD_FBMAX(3) | + FW_EQ_ETH_CMD_CIDXFTHRESH(5) | + FW_EQ_ETH_CMD_EQSIZE(nentries)); + c.eqaddr = cpu_to_be64(txq->q.phys_addr); + + ret = t4_wr_mbox(adap, adap->fn, &c, sizeof(c), &c); + if (ret) { + kfree(txq->q.sdesc); + txq->q.sdesc = NULL; + dma_free_coherent(adap->pdev_dev, + nentries * sizeof(struct tx_desc), + txq->q.desc, txq->q.phys_addr); + txq->q.desc = NULL; + return ret; + } + + init_txq(adap, &txq->q, FW_EQ_ETH_CMD_EQID_GET(ntohl(c.eqid_pkd))); + txq->txq = netdevq; + txq->tso = txq->tx_cso = txq->vlan_ins = 0; + txq->mapping_err = 0; + return 0; +} + +int t4_sge_alloc_ctrl_txq(struct adapter *adap, struct sge_ctrl_txq *txq, + struct net_device *dev, unsigned int iqid, + unsigned int cmplqid) +{ + int ret, nentries; + struct fw_eq_ctrl_cmd c; + struct port_info *pi = netdev_priv(dev); + + /* Add status entries */ + nentries = txq->q.size + STAT_LEN / sizeof(struct tx_desc); + + txq->q.desc = alloc_ring(adap->pdev_dev, nentries, + sizeof(struct tx_desc), 0, &txq->q.phys_addr, + NULL, 0, NUMA_NO_NODE); + if (!txq->q.desc) + return -ENOMEM; + + c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_CTRL_CMD) | FW_CMD_REQUEST | + FW_CMD_WRITE | FW_CMD_EXEC | + FW_EQ_CTRL_CMD_PFN(adap->fn) | + FW_EQ_CTRL_CMD_VFN(0)); + c.alloc_to_len16 = htonl(FW_EQ_CTRL_CMD_ALLOC | + FW_EQ_CTRL_CMD_EQSTART | FW_LEN16(c)); + c.cmpliqid_eqid = htonl(FW_EQ_CTRL_CMD_CMPLIQID(cmplqid)); + c.physeqid_pkd = htonl(0); + c.fetchszm_to_iqid = htonl(FW_EQ_CTRL_CMD_HOSTFCMODE(2) | + FW_EQ_CTRL_CMD_PCIECHN(pi->tx_chan) | + FW_EQ_CTRL_CMD_FETCHRO | + FW_EQ_CTRL_CMD_IQID(iqid)); + c.dcaen_to_eqsize = htonl(FW_EQ_CTRL_CMD_FBMIN(2) | + FW_EQ_CTRL_CMD_FBMAX(3) | + FW_EQ_CTRL_CMD_CIDXFTHRESH(5) | + FW_EQ_CTRL_CMD_EQSIZE(nentries)); + c.eqaddr = cpu_to_be64(txq->q.phys_addr); + + ret = t4_wr_mbox(adap, adap->fn, &c, sizeof(c), &c); + if (ret) { + dma_free_coherent(adap->pdev_dev, + nentries * sizeof(struct tx_desc), + txq->q.desc, txq->q.phys_addr); + txq->q.desc = NULL; + return ret; + } + + init_txq(adap, &txq->q, FW_EQ_CTRL_CMD_EQID_GET(ntohl(c.cmpliqid_eqid))); + txq->adap = adap; + skb_queue_head_init(&txq->sendq); + tasklet_init(&txq->qresume_tsk, restart_ctrlq, (unsigned long)txq); + txq->full = 0; + return 0; +} + +int t4_sge_alloc_ofld_txq(struct adapter *adap, struct sge_ofld_txq *txq, + struct net_device *dev, unsigned int iqid) +{ + int ret, nentries; + struct fw_eq_ofld_cmd c; + struct port_info *pi = netdev_priv(dev); + + /* Add status entries */ + nentries = txq->q.size + STAT_LEN / sizeof(struct tx_desc); + + txq->q.desc = alloc_ring(adap->pdev_dev, txq->q.size, + sizeof(struct tx_desc), sizeof(struct tx_sw_desc), + &txq->q.phys_addr, &txq->q.sdesc, STAT_LEN, + NUMA_NO_NODE); + if (!txq->q.desc) + return -ENOMEM; + + memset(&c, 0, sizeof(c)); + c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_OFLD_CMD) | FW_CMD_REQUEST | + FW_CMD_WRITE | FW_CMD_EXEC | + FW_EQ_OFLD_CMD_PFN(adap->fn) | + FW_EQ_OFLD_CMD_VFN(0)); + c.alloc_to_len16 = htonl(FW_EQ_OFLD_CMD_ALLOC | + FW_EQ_OFLD_CMD_EQSTART | FW_LEN16(c)); + c.fetchszm_to_iqid = htonl(FW_EQ_OFLD_CMD_HOSTFCMODE(2) | + FW_EQ_OFLD_CMD_PCIECHN(pi->tx_chan) | + FW_EQ_OFLD_CMD_FETCHRO(1) | + FW_EQ_OFLD_CMD_IQID(iqid)); + c.dcaen_to_eqsize = htonl(FW_EQ_OFLD_CMD_FBMIN(2) | + FW_EQ_OFLD_CMD_FBMAX(3) | + FW_EQ_OFLD_CMD_CIDXFTHRESH(5) | + FW_EQ_OFLD_CMD_EQSIZE(nentries)); + c.eqaddr = cpu_to_be64(txq->q.phys_addr); + + ret = t4_wr_mbox(adap, adap->fn, &c, sizeof(c), &c); + if (ret) { + kfree(txq->q.sdesc); + txq->q.sdesc = NULL; + dma_free_coherent(adap->pdev_dev, + nentries * sizeof(struct tx_desc), + txq->q.desc, txq->q.phys_addr); + txq->q.desc = NULL; + return ret; + } + + init_txq(adap, &txq->q, FW_EQ_OFLD_CMD_EQID_GET(ntohl(c.eqid_pkd))); + txq->adap = adap; + skb_queue_head_init(&txq->sendq); + tasklet_init(&txq->qresume_tsk, restart_ofldq, (unsigned long)txq); + txq->full = 0; + txq->mapping_err = 0; + return 0; +} + +static void free_txq(struct adapter *adap, struct sge_txq *q) +{ + dma_free_coherent(adap->pdev_dev, + q->size * sizeof(struct tx_desc) + STAT_LEN, + q->desc, q->phys_addr); + q->cntxt_id = 0; + q->sdesc = NULL; + q->desc = NULL; +} + +static void free_rspq_fl(struct adapter *adap, struct sge_rspq *rq, + struct sge_fl *fl) +{ + unsigned int fl_id = fl ? fl->cntxt_id : 0xffff; + + adap->sge.ingr_map[rq->cntxt_id - adap->sge.ingr_start] = NULL; + t4_iq_free(adap, adap->fn, adap->fn, 0, FW_IQ_TYPE_FL_INT_CAP, + rq->cntxt_id, fl_id, 0xffff); + dma_free_coherent(adap->pdev_dev, (rq->size + 1) * rq->iqe_len, + rq->desc, rq->phys_addr); + netif_napi_del(&rq->napi); + rq->netdev = NULL; + rq->cntxt_id = rq->abs_id = 0; + rq->desc = NULL; + + if (fl) { + free_rx_bufs(adap, fl, fl->avail); + dma_free_coherent(adap->pdev_dev, fl->size * 8 + STAT_LEN, + fl->desc, fl->addr); + kfree(fl->sdesc); + fl->sdesc = NULL; + fl->cntxt_id = 0; + fl->desc = NULL; + } +} + +/** + * t4_free_sge_resources - free SGE resources + * @adap: the adapter + * + * Frees resources used by the SGE queue sets. + */ +void t4_free_sge_resources(struct adapter *adap) +{ + int i; + struct sge_eth_rxq *eq = adap->sge.ethrxq; + struct sge_eth_txq *etq = adap->sge.ethtxq; + struct sge_ofld_rxq *oq = adap->sge.ofldrxq; + + /* clean up Ethernet Tx/Rx queues */ + for (i = 0; i < adap->sge.ethqsets; i++, eq++, etq++) { + if (eq->rspq.desc) + free_rspq_fl(adap, &eq->rspq, &eq->fl); + if (etq->q.desc) { + t4_eth_eq_free(adap, adap->fn, adap->fn, 0, + etq->q.cntxt_id); + free_tx_desc(adap, &etq->q, etq->q.in_use, true); + kfree(etq->q.sdesc); + free_txq(adap, &etq->q); + } + } + + /* clean up RDMA and iSCSI Rx queues */ + for (i = 0; i < adap->sge.ofldqsets; i++, oq++) { + if (oq->rspq.desc) + free_rspq_fl(adap, &oq->rspq, &oq->fl); + } + for (i = 0, oq = adap->sge.rdmarxq; i < adap->sge.rdmaqs; i++, oq++) { + if (oq->rspq.desc) + free_rspq_fl(adap, &oq->rspq, &oq->fl); + } + + /* clean up offload Tx queues */ + for (i = 0; i < ARRAY_SIZE(adap->sge.ofldtxq); i++) { + struct sge_ofld_txq *q = &adap->sge.ofldtxq[i]; + + if (q->q.desc) { + tasklet_kill(&q->qresume_tsk); + t4_ofld_eq_free(adap, adap->fn, adap->fn, 0, + q->q.cntxt_id); + free_tx_desc(adap, &q->q, q->q.in_use, false); + kfree(q->q.sdesc); + __skb_queue_purge(&q->sendq); + free_txq(adap, &q->q); + } + } + + /* clean up control Tx queues */ + for (i = 0; i < ARRAY_SIZE(adap->sge.ctrlq); i++) { + struct sge_ctrl_txq *cq = &adap->sge.ctrlq[i]; + + if (cq->q.desc) { + tasklet_kill(&cq->qresume_tsk); + t4_ctrl_eq_free(adap, adap->fn, adap->fn, 0, + cq->q.cntxt_id); + __skb_queue_purge(&cq->sendq); + free_txq(adap, &cq->q); + } + } + + if (adap->sge.fw_evtq.desc) + free_rspq_fl(adap, &adap->sge.fw_evtq, NULL); + + if (adap->sge.intrq.desc) + free_rspq_fl(adap, &adap->sge.intrq, NULL); + + /* clear the reverse egress queue map */ + memset(adap->sge.egr_map, 0, sizeof(adap->sge.egr_map)); +} + +void t4_sge_start(struct adapter *adap) +{ + adap->sge.ethtxq_rover = 0; + mod_timer(&adap->sge.rx_timer, jiffies + RX_QCHECK_PERIOD); + mod_timer(&adap->sge.tx_timer, jiffies + TX_QCHECK_PERIOD); +} + +/** + * t4_sge_stop - disable SGE operation + * @adap: the adapter + * + * Stop tasklets and timers associated with the DMA engine. Note that + * this is effective only if measures have been taken to disable any HW + * events that may restart them. + */ +void t4_sge_stop(struct adapter *adap) +{ + int i; + struct sge *s = &adap->sge; + + if (in_interrupt()) /* actions below require waiting */ + return; + + if (s->rx_timer.function) + del_timer_sync(&s->rx_timer); + if (s->tx_timer.function) + del_timer_sync(&s->tx_timer); + + for (i = 0; i < ARRAY_SIZE(s->ofldtxq); i++) { + struct sge_ofld_txq *q = &s->ofldtxq[i]; + + if (q->q.desc) + tasklet_kill(&q->qresume_tsk); + } + for (i = 0; i < ARRAY_SIZE(s->ctrlq); i++) { + struct sge_ctrl_txq *cq = &s->ctrlq[i]; + + if (cq->q.desc) + tasklet_kill(&cq->qresume_tsk); + } +} + +/** + * t4_sge_init - initialize SGE + * @adap: the adapter + * + * Performs SGE initialization needed every time after a chip reset. + * We do not initialize any of the queues here, instead the driver + * top-level must request them individually. + */ +void t4_sge_init(struct adapter *adap) +{ + unsigned int i, v; + struct sge *s = &adap->sge; + unsigned int fl_align_log = ilog2(FL_ALIGN); + + t4_set_reg_field(adap, SGE_CONTROL, PKTSHIFT_MASK | + INGPADBOUNDARY_MASK | EGRSTATUSPAGESIZE, + INGPADBOUNDARY(fl_align_log - 5) | PKTSHIFT(2) | + RXPKTCPLMODE | + (STAT_LEN == 128 ? EGRSTATUSPAGESIZE : 0)); + + for (i = v = 0; i < 32; i += 4) + v |= (PAGE_SHIFT - 10) << i; + t4_write_reg(adap, SGE_HOST_PAGE_SIZE, v); + t4_write_reg(adap, SGE_FL_BUFFER_SIZE0, PAGE_SIZE); +#if FL_PG_ORDER > 0 + t4_write_reg(adap, SGE_FL_BUFFER_SIZE1, PAGE_SIZE << FL_PG_ORDER); +#endif + t4_write_reg(adap, SGE_INGRESS_RX_THRESHOLD, + THRESHOLD_0(s->counter_val[0]) | + THRESHOLD_1(s->counter_val[1]) | + THRESHOLD_2(s->counter_val[2]) | + THRESHOLD_3(s->counter_val[3])); + t4_write_reg(adap, SGE_TIMER_VALUE_0_AND_1, + TIMERVALUE0(us_to_core_ticks(adap, s->timer_val[0])) | + TIMERVALUE1(us_to_core_ticks(adap, s->timer_val[1]))); + t4_write_reg(adap, SGE_TIMER_VALUE_2_AND_3, + TIMERVALUE0(us_to_core_ticks(adap, s->timer_val[2])) | + TIMERVALUE1(us_to_core_ticks(adap, s->timer_val[3]))); + t4_write_reg(adap, SGE_TIMER_VALUE_4_AND_5, + TIMERVALUE0(us_to_core_ticks(adap, s->timer_val[4])) | + TIMERVALUE1(us_to_core_ticks(adap, s->timer_val[5]))); + setup_timer(&s->rx_timer, sge_rx_timer_cb, (unsigned long)adap); + setup_timer(&s->tx_timer, sge_tx_timer_cb, (unsigned long)adap); + s->starve_thres = core_ticks_per_usec(adap) * 1000000; /* 1 s */ + s->idma_state[0] = s->idma_state[1] = 0; + spin_lock_init(&s->intrq_lock); +} diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c new file mode 100644 index 000000000000..d1ec111aebd8 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -0,0 +1,2856 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include "cxgb4.h" +#include "t4_regs.h" +#include "t4fw_api.h" + +/** + * t4_wait_op_done_val - wait until an operation is completed + * @adapter: the adapter performing the operation + * @reg: the register to check for completion + * @mask: a single-bit field within @reg that indicates completion + * @polarity: the value of the field when the operation is completed + * @attempts: number of check iterations + * @delay: delay in usecs between iterations + * @valp: where to store the value of the register at completion time + * + * Wait until an operation is completed by checking a bit in a register + * up to @attempts times. If @valp is not NULL the value of the register + * at the time it indicated completion is stored there. Returns 0 if the + * operation completes and -EAGAIN otherwise. + */ +static int t4_wait_op_done_val(struct adapter *adapter, int reg, u32 mask, + int polarity, int attempts, int delay, u32 *valp) +{ + while (1) { + u32 val = t4_read_reg(adapter, reg); + + if (!!(val & mask) == polarity) { + if (valp) + *valp = val; + return 0; + } + if (--attempts == 0) + return -EAGAIN; + if (delay) + udelay(delay); + } +} + +static inline int t4_wait_op_done(struct adapter *adapter, int reg, u32 mask, + int polarity, int attempts, int delay) +{ + return t4_wait_op_done_val(adapter, reg, mask, polarity, attempts, + delay, NULL); +} + +/** + * t4_set_reg_field - set a register field to a value + * @adapter: the adapter to program + * @addr: the register address + * @mask: specifies the portion of the register to modify + * @val: the new value for the register field + * + * Sets a register field specified by the supplied mask to the + * given value. + */ +void t4_set_reg_field(struct adapter *adapter, unsigned int addr, u32 mask, + u32 val) +{ + u32 v = t4_read_reg(adapter, addr) & ~mask; + + t4_write_reg(adapter, addr, v | val); + (void) t4_read_reg(adapter, addr); /* flush */ +} + +/** + * t4_read_indirect - read indirectly addressed registers + * @adap: the adapter + * @addr_reg: register holding the indirect address + * @data_reg: register holding the value of the indirect register + * @vals: where the read register values are stored + * @nregs: how many indirect registers to read + * @start_idx: index of first indirect register to read + * + * Reads registers that are accessed indirectly through an address/data + * register pair. + */ +static void t4_read_indirect(struct adapter *adap, unsigned int addr_reg, + unsigned int data_reg, u32 *vals, + unsigned int nregs, unsigned int start_idx) +{ + while (nregs--) { + t4_write_reg(adap, addr_reg, start_idx); + *vals++ = t4_read_reg(adap, data_reg); + start_idx++; + } +} + +/* + * Get the reply to a mailbox command and store it in @rpl in big-endian order. + */ +static void get_mbox_rpl(struct adapter *adap, __be64 *rpl, int nflit, + u32 mbox_addr) +{ + for ( ; nflit; nflit--, mbox_addr += 8) + *rpl++ = cpu_to_be64(t4_read_reg64(adap, mbox_addr)); +} + +/* + * Handle a FW assertion reported in a mailbox. + */ +static void fw_asrt(struct adapter *adap, u32 mbox_addr) +{ + struct fw_debug_cmd asrt; + + get_mbox_rpl(adap, (__be64 *)&asrt, sizeof(asrt) / 8, mbox_addr); + dev_alert(adap->pdev_dev, + "FW assertion at %.16s:%u, val0 %#x, val1 %#x\n", + asrt.u.assert.filename_0_7, ntohl(asrt.u.assert.line), + ntohl(asrt.u.assert.x), ntohl(asrt.u.assert.y)); +} + +static void dump_mbox(struct adapter *adap, int mbox, u32 data_reg) +{ + dev_err(adap->pdev_dev, + "mbox %d: %llx %llx %llx %llx %llx %llx %llx %llx\n", mbox, + (unsigned long long)t4_read_reg64(adap, data_reg), + (unsigned long long)t4_read_reg64(adap, data_reg + 8), + (unsigned long long)t4_read_reg64(adap, data_reg + 16), + (unsigned long long)t4_read_reg64(adap, data_reg + 24), + (unsigned long long)t4_read_reg64(adap, data_reg + 32), + (unsigned long long)t4_read_reg64(adap, data_reg + 40), + (unsigned long long)t4_read_reg64(adap, data_reg + 48), + (unsigned long long)t4_read_reg64(adap, data_reg + 56)); +} + +/** + * t4_wr_mbox_meat - send a command to FW through the given mailbox + * @adap: the adapter + * @mbox: index of the mailbox to use + * @cmd: the command to write + * @size: command length in bytes + * @rpl: where to optionally store the reply + * @sleep_ok: if true we may sleep while awaiting command completion + * + * Sends the given command to FW through the selected mailbox and waits + * for the FW to execute the command. If @rpl is not %NULL it is used to + * store the FW's reply to the command. The command and its optional + * reply are of the same length. FW can take up to %FW_CMD_MAX_TIMEOUT ms + * to respond. @sleep_ok determines whether we may sleep while awaiting + * the response. If sleeping is allowed we use progressive backoff + * otherwise we spin. + * + * The return value is 0 on success or a negative errno on failure. A + * failure can happen either because we are not able to execute the + * command or FW executes it but signals an error. In the latter case + * the return value is the error code indicated by FW (negated). + */ +int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size, + void *rpl, bool sleep_ok) +{ + static const int delay[] = { + 1, 1, 3, 5, 10, 10, 20, 50, 100, 200 + }; + + u32 v; + u64 res; + int i, ms, delay_idx; + const __be64 *p = cmd; + u32 data_reg = PF_REG(mbox, CIM_PF_MAILBOX_DATA); + u32 ctl_reg = PF_REG(mbox, CIM_PF_MAILBOX_CTRL); + + if ((size & 15) || size > MBOX_LEN) + return -EINVAL; + + /* + * If the device is off-line, as in EEH, commands will time out. + * Fail them early so we don't waste time waiting. + */ + if (adap->pdev->error_state != pci_channel_io_normal) + return -EIO; + + v = MBOWNER_GET(t4_read_reg(adap, ctl_reg)); + for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++) + v = MBOWNER_GET(t4_read_reg(adap, ctl_reg)); + + if (v != MBOX_OWNER_DRV) + return v ? -EBUSY : -ETIMEDOUT; + + for (i = 0; i < size; i += 8) + t4_write_reg64(adap, data_reg + i, be64_to_cpu(*p++)); + + t4_write_reg(adap, ctl_reg, MBMSGVALID | MBOWNER(MBOX_OWNER_FW)); + t4_read_reg(adap, ctl_reg); /* flush write */ + + delay_idx = 0; + ms = delay[0]; + + for (i = 0; i < FW_CMD_MAX_TIMEOUT; i += ms) { + if (sleep_ok) { + ms = delay[delay_idx]; /* last element may repeat */ + if (delay_idx < ARRAY_SIZE(delay) - 1) + delay_idx++; + msleep(ms); + } else + mdelay(ms); + + v = t4_read_reg(adap, ctl_reg); + if (MBOWNER_GET(v) == MBOX_OWNER_DRV) { + if (!(v & MBMSGVALID)) { + t4_write_reg(adap, ctl_reg, 0); + continue; + } + + res = t4_read_reg64(adap, data_reg); + if (FW_CMD_OP_GET(res >> 32) == FW_DEBUG_CMD) { + fw_asrt(adap, data_reg); + res = FW_CMD_RETVAL(EIO); + } else if (rpl) + get_mbox_rpl(adap, rpl, size / 8, data_reg); + + if (FW_CMD_RETVAL_GET((int)res)) + dump_mbox(adap, mbox, data_reg); + t4_write_reg(adap, ctl_reg, 0); + return -FW_CMD_RETVAL_GET((int)res); + } + } + + dump_mbox(adap, mbox, data_reg); + dev_err(adap->pdev_dev, "command %#x in mailbox %d timed out\n", + *(const u8 *)cmd, mbox); + return -ETIMEDOUT; +} + +/** + * t4_mc_read - read from MC through backdoor accesses + * @adap: the adapter + * @addr: address of first byte requested + * @data: 64 bytes of data containing the requested address + * @ecc: where to store the corresponding 64-bit ECC word + * + * Read 64 bytes of data from MC starting at a 64-byte-aligned address + * that covers the requested address @addr. If @parity is not %NULL it + * is assigned the 64-bit ECC word for the read data. + */ +int t4_mc_read(struct adapter *adap, u32 addr, __be32 *data, u64 *ecc) +{ + int i; + + if (t4_read_reg(adap, MC_BIST_CMD) & START_BIST) + return -EBUSY; + t4_write_reg(adap, MC_BIST_CMD_ADDR, addr & ~0x3fU); + t4_write_reg(adap, MC_BIST_CMD_LEN, 64); + t4_write_reg(adap, MC_BIST_DATA_PATTERN, 0xc); + t4_write_reg(adap, MC_BIST_CMD, BIST_OPCODE(1) | START_BIST | + BIST_CMD_GAP(1)); + i = t4_wait_op_done(adap, MC_BIST_CMD, START_BIST, 0, 10, 1); + if (i) + return i; + +#define MC_DATA(i) MC_BIST_STATUS_REG(MC_BIST_STATUS_RDATA, i) + + for (i = 15; i >= 0; i--) + *data++ = htonl(t4_read_reg(adap, MC_DATA(i))); + if (ecc) + *ecc = t4_read_reg64(adap, MC_DATA(16)); +#undef MC_DATA + return 0; +} + +/** + * t4_edc_read - read from EDC through backdoor accesses + * @adap: the adapter + * @idx: which EDC to access + * @addr: address of first byte requested + * @data: 64 bytes of data containing the requested address + * @ecc: where to store the corresponding 64-bit ECC word + * + * Read 64 bytes of data from EDC starting at a 64-byte-aligned address + * that covers the requested address @addr. If @parity is not %NULL it + * is assigned the 64-bit ECC word for the read data. + */ +int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc) +{ + int i; + + idx *= EDC_STRIDE; + if (t4_read_reg(adap, EDC_BIST_CMD + idx) & START_BIST) + return -EBUSY; + t4_write_reg(adap, EDC_BIST_CMD_ADDR + idx, addr & ~0x3fU); + t4_write_reg(adap, EDC_BIST_CMD_LEN + idx, 64); + t4_write_reg(adap, EDC_BIST_DATA_PATTERN + idx, 0xc); + t4_write_reg(adap, EDC_BIST_CMD + idx, + BIST_OPCODE(1) | BIST_CMD_GAP(1) | START_BIST); + i = t4_wait_op_done(adap, EDC_BIST_CMD + idx, START_BIST, 0, 10, 1); + if (i) + return i; + +#define EDC_DATA(i) (EDC_BIST_STATUS_REG(EDC_BIST_STATUS_RDATA, i) + idx) + + for (i = 15; i >= 0; i--) + *data++ = htonl(t4_read_reg(adap, EDC_DATA(i))); + if (ecc) + *ecc = t4_read_reg64(adap, EDC_DATA(16)); +#undef EDC_DATA + return 0; +} + +#define EEPROM_STAT_ADDR 0x7bfc +#define VPD_BASE 0 +#define VPD_LEN 512 + +/** + * t4_seeprom_wp - enable/disable EEPROM write protection + * @adapter: the adapter + * @enable: whether to enable or disable write protection + * + * Enables or disables write protection on the serial EEPROM. + */ +int t4_seeprom_wp(struct adapter *adapter, bool enable) +{ + unsigned int v = enable ? 0xc : 0; + int ret = pci_write_vpd(adapter->pdev, EEPROM_STAT_ADDR, 4, &v); + return ret < 0 ? ret : 0; +} + +/** + * get_vpd_params - read VPD parameters from VPD EEPROM + * @adapter: adapter to read + * @p: where to store the parameters + * + * Reads card parameters stored in VPD EEPROM. + */ +static int get_vpd_params(struct adapter *adapter, struct vpd_params *p) +{ + int i, ret; + int ec, sn; + u8 vpd[VPD_LEN], csum; + unsigned int vpdr_len, kw_offset, id_len; + + ret = pci_read_vpd(adapter->pdev, VPD_BASE, sizeof(vpd), vpd); + if (ret < 0) + return ret; + + if (vpd[0] != PCI_VPD_LRDT_ID_STRING) { + dev_err(adapter->pdev_dev, "missing VPD ID string\n"); + return -EINVAL; + } + + id_len = pci_vpd_lrdt_size(vpd); + if (id_len > ID_LEN) + id_len = ID_LEN; + + i = pci_vpd_find_tag(vpd, 0, VPD_LEN, PCI_VPD_LRDT_RO_DATA); + if (i < 0) { + dev_err(adapter->pdev_dev, "missing VPD-R section\n"); + return -EINVAL; + } + + vpdr_len = pci_vpd_lrdt_size(&vpd[i]); + kw_offset = i + PCI_VPD_LRDT_TAG_SIZE; + if (vpdr_len + kw_offset > VPD_LEN) { + dev_err(adapter->pdev_dev, "bad VPD-R length %u\n", vpdr_len); + return -EINVAL; + } + +#define FIND_VPD_KW(var, name) do { \ + var = pci_vpd_find_info_keyword(vpd, kw_offset, vpdr_len, name); \ + if (var < 0) { \ + dev_err(adapter->pdev_dev, "missing VPD keyword " name "\n"); \ + return -EINVAL; \ + } \ + var += PCI_VPD_INFO_FLD_HDR_SIZE; \ +} while (0) + + FIND_VPD_KW(i, "RV"); + for (csum = 0; i >= 0; i--) + csum += vpd[i]; + + if (csum) { + dev_err(adapter->pdev_dev, + "corrupted VPD EEPROM, actual csum %u\n", csum); + return -EINVAL; + } + + FIND_VPD_KW(ec, "EC"); + FIND_VPD_KW(sn, "SN"); +#undef FIND_VPD_KW + + memcpy(p->id, vpd + PCI_VPD_LRDT_TAG_SIZE, id_len); + strim(p->id); + memcpy(p->ec, vpd + ec, EC_LEN); + strim(p->ec); + i = pci_vpd_info_field_size(vpd + sn - PCI_VPD_INFO_FLD_HDR_SIZE); + memcpy(p->sn, vpd + sn, min(i, SERNUM_LEN)); + strim(p->sn); + return 0; +} + +/* serial flash and firmware constants */ +enum { + SF_ATTEMPTS = 10, /* max retries for SF operations */ + + /* flash command opcodes */ + SF_PROG_PAGE = 2, /* program page */ + SF_WR_DISABLE = 4, /* disable writes */ + SF_RD_STATUS = 5, /* read status register */ + SF_WR_ENABLE = 6, /* enable writes */ + SF_RD_DATA_FAST = 0xb, /* read flash */ + SF_RD_ID = 0x9f, /* read ID */ + SF_ERASE_SECTOR = 0xd8, /* erase sector */ + + FW_MAX_SIZE = 512 * 1024, +}; + +/** + * sf1_read - read data from the serial flash + * @adapter: the adapter + * @byte_cnt: number of bytes to read + * @cont: whether another operation will be chained + * @lock: whether to lock SF for PL access only + * @valp: where to store the read data + * + * Reads up to 4 bytes of data from the serial flash. The location of + * the read needs to be specified prior to calling this by issuing the + * appropriate commands to the serial flash. + */ +static int sf1_read(struct adapter *adapter, unsigned int byte_cnt, int cont, + int lock, u32 *valp) +{ + int ret; + + if (!byte_cnt || byte_cnt > 4) + return -EINVAL; + if (t4_read_reg(adapter, SF_OP) & BUSY) + return -EBUSY; + cont = cont ? SF_CONT : 0; + lock = lock ? SF_LOCK : 0; + t4_write_reg(adapter, SF_OP, lock | cont | BYTECNT(byte_cnt - 1)); + ret = t4_wait_op_done(adapter, SF_OP, BUSY, 0, SF_ATTEMPTS, 5); + if (!ret) + *valp = t4_read_reg(adapter, SF_DATA); + return ret; +} + +/** + * sf1_write - write data to the serial flash + * @adapter: the adapter + * @byte_cnt: number of bytes to write + * @cont: whether another operation will be chained + * @lock: whether to lock SF for PL access only + * @val: value to write + * + * Writes up to 4 bytes of data to the serial flash. The location of + * the write needs to be specified prior to calling this by issuing the + * appropriate commands to the serial flash. + */ +static int sf1_write(struct adapter *adapter, unsigned int byte_cnt, int cont, + int lock, u32 val) +{ + if (!byte_cnt || byte_cnt > 4) + return -EINVAL; + if (t4_read_reg(adapter, SF_OP) & BUSY) + return -EBUSY; + cont = cont ? SF_CONT : 0; + lock = lock ? SF_LOCK : 0; + t4_write_reg(adapter, SF_DATA, val); + t4_write_reg(adapter, SF_OP, lock | + cont | BYTECNT(byte_cnt - 1) | OP_WR); + return t4_wait_op_done(adapter, SF_OP, BUSY, 0, SF_ATTEMPTS, 5); +} + +/** + * flash_wait_op - wait for a flash operation to complete + * @adapter: the adapter + * @attempts: max number of polls of the status register + * @delay: delay between polls in ms + * + * Wait for a flash operation to complete by polling the status register. + */ +static int flash_wait_op(struct adapter *adapter, int attempts, int delay) +{ + int ret; + u32 status; + + while (1) { + if ((ret = sf1_write(adapter, 1, 1, 1, SF_RD_STATUS)) != 0 || + (ret = sf1_read(adapter, 1, 0, 1, &status)) != 0) + return ret; + if (!(status & 1)) + return 0; + if (--attempts == 0) + return -EAGAIN; + if (delay) + msleep(delay); + } +} + +/** + * t4_read_flash - read words from serial flash + * @adapter: the adapter + * @addr: the start address for the read + * @nwords: how many 32-bit words to read + * @data: where to store the read data + * @byte_oriented: whether to store data as bytes or as words + * + * Read the specified number of 32-bit words from the serial flash. + * If @byte_oriented is set the read data is stored as a byte array + * (i.e., big-endian), otherwise as 32-bit words in the platform's + * natural endianess. + */ +static int t4_read_flash(struct adapter *adapter, unsigned int addr, + unsigned int nwords, u32 *data, int byte_oriented) +{ + int ret; + + if (addr + nwords * sizeof(u32) > adapter->params.sf_size || (addr & 3)) + return -EINVAL; + + addr = swab32(addr) | SF_RD_DATA_FAST; + + if ((ret = sf1_write(adapter, 4, 1, 0, addr)) != 0 || + (ret = sf1_read(adapter, 1, 1, 0, data)) != 0) + return ret; + + for ( ; nwords; nwords--, data++) { + ret = sf1_read(adapter, 4, nwords > 1, nwords == 1, data); + if (nwords == 1) + t4_write_reg(adapter, SF_OP, 0); /* unlock SF */ + if (ret) + return ret; + if (byte_oriented) + *data = htonl(*data); + } + return 0; +} + +/** + * t4_write_flash - write up to a page of data to the serial flash + * @adapter: the adapter + * @addr: the start address to write + * @n: length of data to write in bytes + * @data: the data to write + * + * Writes up to a page of data (256 bytes) to the serial flash starting + * at the given address. All the data must be written to the same page. + */ +static int t4_write_flash(struct adapter *adapter, unsigned int addr, + unsigned int n, const u8 *data) +{ + int ret; + u32 buf[64]; + unsigned int i, c, left, val, offset = addr & 0xff; + + if (addr >= adapter->params.sf_size || offset + n > SF_PAGE_SIZE) + return -EINVAL; + + val = swab32(addr) | SF_PROG_PAGE; + + if ((ret = sf1_write(adapter, 1, 0, 1, SF_WR_ENABLE)) != 0 || + (ret = sf1_write(adapter, 4, 1, 1, val)) != 0) + goto unlock; + + for (left = n; left; left -= c) { + c = min(left, 4U); + for (val = 0, i = 0; i < c; ++i) + val = (val << 8) + *data++; + + ret = sf1_write(adapter, c, c != left, 1, val); + if (ret) + goto unlock; + } + ret = flash_wait_op(adapter, 8, 1); + if (ret) + goto unlock; + + t4_write_reg(adapter, SF_OP, 0); /* unlock SF */ + + /* Read the page to verify the write succeeded */ + ret = t4_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf, 1); + if (ret) + return ret; + + if (memcmp(data - n, (u8 *)buf + offset, n)) { + dev_err(adapter->pdev_dev, + "failed to correctly write the flash page at %#x\n", + addr); + return -EIO; + } + return 0; + +unlock: + t4_write_reg(adapter, SF_OP, 0); /* unlock SF */ + return ret; +} + +/** + * get_fw_version - read the firmware version + * @adapter: the adapter + * @vers: where to place the version + * + * Reads the FW version from flash. + */ +static int get_fw_version(struct adapter *adapter, u32 *vers) +{ + return t4_read_flash(adapter, adapter->params.sf_fw_start + + offsetof(struct fw_hdr, fw_ver), 1, vers, 0); +} + +/** + * get_tp_version - read the TP microcode version + * @adapter: the adapter + * @vers: where to place the version + * + * Reads the TP microcode version from flash. + */ +static int get_tp_version(struct adapter *adapter, u32 *vers) +{ + return t4_read_flash(adapter, adapter->params.sf_fw_start + + offsetof(struct fw_hdr, tp_microcode_ver), + 1, vers, 0); +} + +/** + * t4_check_fw_version - check if the FW is compatible with this driver + * @adapter: the adapter + * + * Checks if an adapter's FW is compatible with the driver. Returns 0 + * if there's exact match, a negative error if the version could not be + * read or there's a major version mismatch, and a positive value if the + * expected major version is found but there's a minor version mismatch. + */ +int t4_check_fw_version(struct adapter *adapter) +{ + u32 api_vers[2]; + int ret, major, minor, micro; + + ret = get_fw_version(adapter, &adapter->params.fw_vers); + if (!ret) + ret = get_tp_version(adapter, &adapter->params.tp_vers); + if (!ret) + ret = t4_read_flash(adapter, adapter->params.sf_fw_start + + offsetof(struct fw_hdr, intfver_nic), + 2, api_vers, 1); + if (ret) + return ret; + + major = FW_HDR_FW_VER_MAJOR_GET(adapter->params.fw_vers); + minor = FW_HDR_FW_VER_MINOR_GET(adapter->params.fw_vers); + micro = FW_HDR_FW_VER_MICRO_GET(adapter->params.fw_vers); + memcpy(adapter->params.api_vers, api_vers, + sizeof(adapter->params.api_vers)); + + if (major != FW_VERSION_MAJOR) { /* major mismatch - fail */ + dev_err(adapter->pdev_dev, + "card FW has major version %u, driver wants %u\n", + major, FW_VERSION_MAJOR); + return -EINVAL; + } + + if (minor == FW_VERSION_MINOR && micro == FW_VERSION_MICRO) + return 0; /* perfect match */ + + /* Minor/micro version mismatch. Report it but often it's OK. */ + return 1; +} + +/** + * t4_flash_erase_sectors - erase a range of flash sectors + * @adapter: the adapter + * @start: the first sector to erase + * @end: the last sector to erase + * + * Erases the sectors in the given inclusive range. + */ +static int t4_flash_erase_sectors(struct adapter *adapter, int start, int end) +{ + int ret = 0; + + while (start <= end) { + if ((ret = sf1_write(adapter, 1, 0, 1, SF_WR_ENABLE)) != 0 || + (ret = sf1_write(adapter, 4, 0, 1, + SF_ERASE_SECTOR | (start << 8))) != 0 || + (ret = flash_wait_op(adapter, 14, 500)) != 0) { + dev_err(adapter->pdev_dev, + "erase of flash sector %d failed, error %d\n", + start, ret); + break; + } + start++; + } + t4_write_reg(adapter, SF_OP, 0); /* unlock SF */ + return ret; +} + +/** + * t4_load_fw - download firmware + * @adap: the adapter + * @fw_data: the firmware image to write + * @size: image size + * + * Write the supplied firmware image to the card's serial flash. + */ +int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size) +{ + u32 csum; + int ret, addr; + unsigned int i; + u8 first_page[SF_PAGE_SIZE]; + const u32 *p = (const u32 *)fw_data; + const struct fw_hdr *hdr = (const struct fw_hdr *)fw_data; + unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec; + unsigned int fw_img_start = adap->params.sf_fw_start; + unsigned int fw_start_sec = fw_img_start / sf_sec_size; + + if (!size) { + dev_err(adap->pdev_dev, "FW image has no data\n"); + return -EINVAL; + } + if (size & 511) { + dev_err(adap->pdev_dev, + "FW image size not multiple of 512 bytes\n"); + return -EINVAL; + } + if (ntohs(hdr->len512) * 512 != size) { + dev_err(adap->pdev_dev, + "FW image size differs from size in FW header\n"); + return -EINVAL; + } + if (size > FW_MAX_SIZE) { + dev_err(adap->pdev_dev, "FW image too large, max is %u bytes\n", + FW_MAX_SIZE); + return -EFBIG; + } + + for (csum = 0, i = 0; i < size / sizeof(csum); i++) + csum += ntohl(p[i]); + + if (csum != 0xffffffff) { + dev_err(adap->pdev_dev, + "corrupted firmware image, checksum %#x\n", csum); + return -EINVAL; + } + + i = DIV_ROUND_UP(size, sf_sec_size); /* # of sectors spanned */ + ret = t4_flash_erase_sectors(adap, fw_start_sec, fw_start_sec + i - 1); + if (ret) + goto out; + + /* + * We write the correct version at the end so the driver can see a bad + * version if the FW write fails. Start by writing a copy of the + * first page with a bad version. + */ + memcpy(first_page, fw_data, SF_PAGE_SIZE); + ((struct fw_hdr *)first_page)->fw_ver = htonl(0xffffffff); + ret = t4_write_flash(adap, fw_img_start, SF_PAGE_SIZE, first_page); + if (ret) + goto out; + + addr = fw_img_start; + for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) { + addr += SF_PAGE_SIZE; + fw_data += SF_PAGE_SIZE; + ret = t4_write_flash(adap, addr, SF_PAGE_SIZE, fw_data); + if (ret) + goto out; + } + + ret = t4_write_flash(adap, + fw_img_start + offsetof(struct fw_hdr, fw_ver), + sizeof(hdr->fw_ver), (const u8 *)&hdr->fw_ver); +out: + if (ret) + dev_err(adap->pdev_dev, "firmware download failed, error %d\n", + ret); + return ret; +} + +#define ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\ + FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_ANEG) + +/** + * t4_link_start - apply link configuration to MAC/PHY + * @phy: the PHY to setup + * @mac: the MAC to setup + * @lc: the requested link configuration + * + * Set up a port's MAC and PHY according to a desired link configuration. + * - If the PHY can auto-negotiate first decide what to advertise, then + * enable/disable auto-negotiation as desired, and reset. + * - If the PHY does not auto-negotiate just reset it. + * - If auto-negotiation is off set the MAC to the proper speed/duplex/FC, + * otherwise do it later based on the outcome of auto-negotiation. + */ +int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port, + struct link_config *lc) +{ + struct fw_port_cmd c; + unsigned int fc = 0, mdi = FW_PORT_MDI(FW_PORT_MDI_AUTO); + + lc->link_ok = 0; + if (lc->requested_fc & PAUSE_RX) + fc |= FW_PORT_CAP_FC_RX; + if (lc->requested_fc & PAUSE_TX) + fc |= FW_PORT_CAP_FC_TX; + + memset(&c, 0, sizeof(c)); + c.op_to_portid = htonl(FW_CMD_OP(FW_PORT_CMD) | FW_CMD_REQUEST | + FW_CMD_EXEC | FW_PORT_CMD_PORTID(port)); + c.action_to_len16 = htonl(FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) | + FW_LEN16(c)); + + if (!(lc->supported & FW_PORT_CAP_ANEG)) { + c.u.l1cfg.rcap = htonl((lc->supported & ADVERT_MASK) | fc); + lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); + } else if (lc->autoneg == AUTONEG_DISABLE) { + c.u.l1cfg.rcap = htonl(lc->requested_speed | fc | mdi); + lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); + } else + c.u.l1cfg.rcap = htonl(lc->advertising | fc | mdi); + + return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + * t4_restart_aneg - restart autonegotiation + * @adap: the adapter + * @mbox: mbox to use for the FW command + * @port: the port id + * + * Restarts autonegotiation for the selected port. + */ +int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port) +{ + struct fw_port_cmd c; + + memset(&c, 0, sizeof(c)); + c.op_to_portid = htonl(FW_CMD_OP(FW_PORT_CMD) | FW_CMD_REQUEST | + FW_CMD_EXEC | FW_PORT_CMD_PORTID(port)); + c.action_to_len16 = htonl(FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) | + FW_LEN16(c)); + c.u.l1cfg.rcap = htonl(FW_PORT_CAP_ANEG); + return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +struct intr_info { + unsigned int mask; /* bits to check in interrupt status */ + const char *msg; /* message to print or NULL */ + short stat_idx; /* stat counter to increment or -1 */ + unsigned short fatal; /* whether the condition reported is fatal */ +}; + +/** + * t4_handle_intr_status - table driven interrupt handler + * @adapter: the adapter that generated the interrupt + * @reg: the interrupt status register to process + * @acts: table of interrupt actions + * + * A table driven interrupt handler that applies a set of masks to an + * interrupt status word and performs the corresponding actions if the + * interrupts described by the mask have occurred. The actions include + * optionally emitting a warning or alert message. The table is terminated + * by an entry specifying mask 0. Returns the number of fatal interrupt + * conditions. + */ +static int t4_handle_intr_status(struct adapter *adapter, unsigned int reg, + const struct intr_info *acts) +{ + int fatal = 0; + unsigned int mask = 0; + unsigned int status = t4_read_reg(adapter, reg); + + for ( ; acts->mask; ++acts) { + if (!(status & acts->mask)) + continue; + if (acts->fatal) { + fatal++; + dev_alert(adapter->pdev_dev, "%s (0x%x)\n", acts->msg, + status & acts->mask); + } else if (acts->msg && printk_ratelimit()) + dev_warn(adapter->pdev_dev, "%s (0x%x)\n", acts->msg, + status & acts->mask); + mask |= acts->mask; + } + status &= mask; + if (status) /* clear processed interrupts */ + t4_write_reg(adapter, reg, status); + return fatal; +} + +/* + * Interrupt handler for the PCIE module. + */ +static void pcie_intr_handler(struct adapter *adapter) +{ + static const struct intr_info sysbus_intr_info[] = { + { RNPP, "RXNP array parity error", -1, 1 }, + { RPCP, "RXPC array parity error", -1, 1 }, + { RCIP, "RXCIF array parity error", -1, 1 }, + { RCCP, "Rx completions control array parity error", -1, 1 }, + { RFTP, "RXFT array parity error", -1, 1 }, + { 0 } + }; + static const struct intr_info pcie_port_intr_info[] = { + { TPCP, "TXPC array parity error", -1, 1 }, + { TNPP, "TXNP array parity error", -1, 1 }, + { TFTP, "TXFT array parity error", -1, 1 }, + { TCAP, "TXCA array parity error", -1, 1 }, + { TCIP, "TXCIF array parity error", -1, 1 }, + { RCAP, "RXCA array parity error", -1, 1 }, + { OTDD, "outbound request TLP discarded", -1, 1 }, + { RDPE, "Rx data parity error", -1, 1 }, + { TDUE, "Tx uncorrectable data error", -1, 1 }, + { 0 } + }; + static const struct intr_info pcie_intr_info[] = { + { MSIADDRLPERR, "MSI AddrL parity error", -1, 1 }, + { MSIADDRHPERR, "MSI AddrH parity error", -1, 1 }, + { MSIDATAPERR, "MSI data parity error", -1, 1 }, + { MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 }, + { MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 }, + { MSIXDATAPERR, "MSI-X data parity error", -1, 1 }, + { MSIXDIPERR, "MSI-X DI parity error", -1, 1 }, + { PIOCPLPERR, "PCI PIO completion FIFO parity error", -1, 1 }, + { PIOREQPERR, "PCI PIO request FIFO parity error", -1, 1 }, + { TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 }, + { CCNTPERR, "PCI CMD channel count parity error", -1, 1 }, + { CREQPERR, "PCI CMD channel request parity error", -1, 1 }, + { CRSPPERR, "PCI CMD channel response parity error", -1, 1 }, + { DCNTPERR, "PCI DMA channel count parity error", -1, 1 }, + { DREQPERR, "PCI DMA channel request parity error", -1, 1 }, + { DRSPPERR, "PCI DMA channel response parity error", -1, 1 }, + { HCNTPERR, "PCI HMA channel count parity error", -1, 1 }, + { HREQPERR, "PCI HMA channel request parity error", -1, 1 }, + { HRSPPERR, "PCI HMA channel response parity error", -1, 1 }, + { CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 }, + { FIDPERR, "PCI FID parity error", -1, 1 }, + { INTXCLRPERR, "PCI INTx clear parity error", -1, 1 }, + { MATAGPERR, "PCI MA tag parity error", -1, 1 }, + { PIOTAGPERR, "PCI PIO tag parity error", -1, 1 }, + { RXCPLPERR, "PCI Rx completion parity error", -1, 1 }, + { RXWRPERR, "PCI Rx write parity error", -1, 1 }, + { RPLPERR, "PCI replay buffer parity error", -1, 1 }, + { PCIESINT, "PCI core secondary fault", -1, 1 }, + { PCIEPINT, "PCI core primary fault", -1, 1 }, + { UNXSPLCPLERR, "PCI unexpected split completion error", -1, 0 }, + { 0 } + }; + + int fat; + + fat = t4_handle_intr_status(adapter, + PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS, + sysbus_intr_info) + + t4_handle_intr_status(adapter, + PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS, + pcie_port_intr_info) + + t4_handle_intr_status(adapter, PCIE_INT_CAUSE, pcie_intr_info); + if (fat) + t4_fatal_err(adapter); +} + +/* + * TP interrupt handler. + */ +static void tp_intr_handler(struct adapter *adapter) +{ + static const struct intr_info tp_intr_info[] = { + { 0x3fffffff, "TP parity error", -1, 1 }, + { FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1 }, + { 0 } + }; + + if (t4_handle_intr_status(adapter, TP_INT_CAUSE, tp_intr_info)) + t4_fatal_err(adapter); +} + +/* + * SGE interrupt handler. + */ +static void sge_intr_handler(struct adapter *adapter) +{ + u64 v; + + static const struct intr_info sge_intr_info[] = { + { ERR_CPL_EXCEED_IQE_SIZE, + "SGE received CPL exceeding IQE size", -1, 1 }, + { ERR_INVALID_CIDX_INC, + "SGE GTS CIDX increment too large", -1, 0 }, + { ERR_CPL_OPCODE_0, "SGE received 0-length CPL", -1, 0 }, + { ERR_DROPPED_DB, "SGE doorbell dropped", -1, 0 }, + { ERR_DATA_CPL_ON_HIGH_QID1 | ERR_DATA_CPL_ON_HIGH_QID0, + "SGE IQID > 1023 received CPL for FL", -1, 0 }, + { ERR_BAD_DB_PIDX3, "SGE DBP 3 pidx increment too large", -1, + 0 }, + { ERR_BAD_DB_PIDX2, "SGE DBP 2 pidx increment too large", -1, + 0 }, + { ERR_BAD_DB_PIDX1, "SGE DBP 1 pidx increment too large", -1, + 0 }, + { ERR_BAD_DB_PIDX0, "SGE DBP 0 pidx increment too large", -1, + 0 }, + { ERR_ING_CTXT_PRIO, + "SGE too many priority ingress contexts", -1, 0 }, + { ERR_EGR_CTXT_PRIO, + "SGE too many priority egress contexts", -1, 0 }, + { INGRESS_SIZE_ERR, "SGE illegal ingress QID", -1, 0 }, + { EGRESS_SIZE_ERR, "SGE illegal egress QID", -1, 0 }, + { 0 } + }; + + v = (u64)t4_read_reg(adapter, SGE_INT_CAUSE1) | + ((u64)t4_read_reg(adapter, SGE_INT_CAUSE2) << 32); + if (v) { + dev_alert(adapter->pdev_dev, "SGE parity error (%#llx)\n", + (unsigned long long)v); + t4_write_reg(adapter, SGE_INT_CAUSE1, v); + t4_write_reg(adapter, SGE_INT_CAUSE2, v >> 32); + } + + if (t4_handle_intr_status(adapter, SGE_INT_CAUSE3, sge_intr_info) || + v != 0) + t4_fatal_err(adapter); +} + +/* + * CIM interrupt handler. + */ +static void cim_intr_handler(struct adapter *adapter) +{ + static const struct intr_info cim_intr_info[] = { + { PREFDROPINT, "CIM control register prefetch drop", -1, 1 }, + { OBQPARERR, "CIM OBQ parity error", -1, 1 }, + { IBQPARERR, "CIM IBQ parity error", -1, 1 }, + { MBUPPARERR, "CIM mailbox uP parity error", -1, 1 }, + { MBHOSTPARERR, "CIM mailbox host parity error", -1, 1 }, + { TIEQINPARERRINT, "CIM TIEQ outgoing parity error", -1, 1 }, + { TIEQOUTPARERRINT, "CIM TIEQ incoming parity error", -1, 1 }, + { 0 } + }; + static const struct intr_info cim_upintr_info[] = { + { RSVDSPACEINT, "CIM reserved space access", -1, 1 }, + { ILLTRANSINT, "CIM illegal transaction", -1, 1 }, + { ILLWRINT, "CIM illegal write", -1, 1 }, + { ILLRDINT, "CIM illegal read", -1, 1 }, + { ILLRDBEINT, "CIM illegal read BE", -1, 1 }, + { ILLWRBEINT, "CIM illegal write BE", -1, 1 }, + { SGLRDBOOTINT, "CIM single read from boot space", -1, 1 }, + { SGLWRBOOTINT, "CIM single write to boot space", -1, 1 }, + { BLKWRBOOTINT, "CIM block write to boot space", -1, 1 }, + { SGLRDFLASHINT, "CIM single read from flash space", -1, 1 }, + { SGLWRFLASHINT, "CIM single write to flash space", -1, 1 }, + { BLKWRFLASHINT, "CIM block write to flash space", -1, 1 }, + { SGLRDEEPROMINT, "CIM single EEPROM read", -1, 1 }, + { SGLWREEPROMINT, "CIM single EEPROM write", -1, 1 }, + { BLKRDEEPROMINT, "CIM block EEPROM read", -1, 1 }, + { BLKWREEPROMINT, "CIM block EEPROM write", -1, 1 }, + { SGLRDCTLINT , "CIM single read from CTL space", -1, 1 }, + { SGLWRCTLINT , "CIM single write to CTL space", -1, 1 }, + { BLKRDCTLINT , "CIM block read from CTL space", -1, 1 }, + { BLKWRCTLINT , "CIM block write to CTL space", -1, 1 }, + { SGLRDPLINT , "CIM single read from PL space", -1, 1 }, + { SGLWRPLINT , "CIM single write to PL space", -1, 1 }, + { BLKRDPLINT , "CIM block read from PL space", -1, 1 }, + { BLKWRPLINT , "CIM block write to PL space", -1, 1 }, + { REQOVRLOOKUPINT , "CIM request FIFO overwrite", -1, 1 }, + { RSPOVRLOOKUPINT , "CIM response FIFO overwrite", -1, 1 }, + { TIMEOUTINT , "CIM PIF timeout", -1, 1 }, + { TIMEOUTMAINT , "CIM PIF MA timeout", -1, 1 }, + { 0 } + }; + + int fat; + + fat = t4_handle_intr_status(adapter, CIM_HOST_INT_CAUSE, + cim_intr_info) + + t4_handle_intr_status(adapter, CIM_HOST_UPACC_INT_CAUSE, + cim_upintr_info); + if (fat) + t4_fatal_err(adapter); +} + +/* + * ULP RX interrupt handler. + */ +static void ulprx_intr_handler(struct adapter *adapter) +{ + static const struct intr_info ulprx_intr_info[] = { + { 0x1800000, "ULPRX context error", -1, 1 }, + { 0x7fffff, "ULPRX parity error", -1, 1 }, + { 0 } + }; + + if (t4_handle_intr_status(adapter, ULP_RX_INT_CAUSE, ulprx_intr_info)) + t4_fatal_err(adapter); +} + +/* + * ULP TX interrupt handler. + */ +static void ulptx_intr_handler(struct adapter *adapter) +{ + static const struct intr_info ulptx_intr_info[] = { + { PBL_BOUND_ERR_CH3, "ULPTX channel 3 PBL out of bounds", -1, + 0 }, + { PBL_BOUND_ERR_CH2, "ULPTX channel 2 PBL out of bounds", -1, + 0 }, + { PBL_BOUND_ERR_CH1, "ULPTX channel 1 PBL out of bounds", -1, + 0 }, + { PBL_BOUND_ERR_CH0, "ULPTX channel 0 PBL out of bounds", -1, + 0 }, + { 0xfffffff, "ULPTX parity error", -1, 1 }, + { 0 } + }; + + if (t4_handle_intr_status(adapter, ULP_TX_INT_CAUSE, ulptx_intr_info)) + t4_fatal_err(adapter); +} + +/* + * PM TX interrupt handler. + */ +static void pmtx_intr_handler(struct adapter *adapter) +{ + static const struct intr_info pmtx_intr_info[] = { + { PCMD_LEN_OVFL0, "PMTX channel 0 pcmd too large", -1, 1 }, + { PCMD_LEN_OVFL1, "PMTX channel 1 pcmd too large", -1, 1 }, + { PCMD_LEN_OVFL2, "PMTX channel 2 pcmd too large", -1, 1 }, + { ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1 }, + { PMTX_FRAMING_ERROR, "PMTX framing error", -1, 1 }, + { OESPI_PAR_ERROR, "PMTX oespi parity error", -1, 1 }, + { DB_OPTIONS_PAR_ERROR, "PMTX db_options parity error", -1, 1 }, + { ICSPI_PAR_ERROR, "PMTX icspi parity error", -1, 1 }, + { C_PCMD_PAR_ERROR, "PMTX c_pcmd parity error", -1, 1}, + { 0 } + }; + + if (t4_handle_intr_status(adapter, PM_TX_INT_CAUSE, pmtx_intr_info)) + t4_fatal_err(adapter); +} + +/* + * PM RX interrupt handler. + */ +static void pmrx_intr_handler(struct adapter *adapter) +{ + static const struct intr_info pmrx_intr_info[] = { + { ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1 }, + { PMRX_FRAMING_ERROR, "PMRX framing error", -1, 1 }, + { OCSPI_PAR_ERROR, "PMRX ocspi parity error", -1, 1 }, + { DB_OPTIONS_PAR_ERROR, "PMRX db_options parity error", -1, 1 }, + { IESPI_PAR_ERROR, "PMRX iespi parity error", -1, 1 }, + { E_PCMD_PAR_ERROR, "PMRX e_pcmd parity error", -1, 1}, + { 0 } + }; + + if (t4_handle_intr_status(adapter, PM_RX_INT_CAUSE, pmrx_intr_info)) + t4_fatal_err(adapter); +} + +/* + * CPL switch interrupt handler. + */ +static void cplsw_intr_handler(struct adapter *adapter) +{ + static const struct intr_info cplsw_intr_info[] = { + { CIM_OP_MAP_PERR, "CPLSW CIM op_map parity error", -1, 1 }, + { CIM_OVFL_ERROR, "CPLSW CIM overflow", -1, 1 }, + { TP_FRAMING_ERROR, "CPLSW TP framing error", -1, 1 }, + { SGE_FRAMING_ERROR, "CPLSW SGE framing error", -1, 1 }, + { CIM_FRAMING_ERROR, "CPLSW CIM framing error", -1, 1 }, + { ZERO_SWITCH_ERROR, "CPLSW no-switch error", -1, 1 }, + { 0 } + }; + + if (t4_handle_intr_status(adapter, CPL_INTR_CAUSE, cplsw_intr_info)) + t4_fatal_err(adapter); +} + +/* + * LE interrupt handler. + */ +static void le_intr_handler(struct adapter *adap) +{ + static const struct intr_info le_intr_info[] = { + { LIPMISS, "LE LIP miss", -1, 0 }, + { LIP0, "LE 0 LIP error", -1, 0 }, + { PARITYERR, "LE parity error", -1, 1 }, + { UNKNOWNCMD, "LE unknown command", -1, 1 }, + { REQQPARERR, "LE request queue parity error", -1, 1 }, + { 0 } + }; + + if (t4_handle_intr_status(adap, LE_DB_INT_CAUSE, le_intr_info)) + t4_fatal_err(adap); +} + +/* + * MPS interrupt handler. + */ +static void mps_intr_handler(struct adapter *adapter) +{ + static const struct intr_info mps_rx_intr_info[] = { + { 0xffffff, "MPS Rx parity error", -1, 1 }, + { 0 } + }; + static const struct intr_info mps_tx_intr_info[] = { + { TPFIFO, "MPS Tx TP FIFO parity error", -1, 1 }, + { NCSIFIFO, "MPS Tx NC-SI FIFO parity error", -1, 1 }, + { TXDATAFIFO, "MPS Tx data FIFO parity error", -1, 1 }, + { TXDESCFIFO, "MPS Tx desc FIFO parity error", -1, 1 }, + { BUBBLE, "MPS Tx underflow", -1, 1 }, + { SECNTERR, "MPS Tx SOP/EOP error", -1, 1 }, + { FRMERR, "MPS Tx framing error", -1, 1 }, + { 0 } + }; + static const struct intr_info mps_trc_intr_info[] = { + { FILTMEM, "MPS TRC filter parity error", -1, 1 }, + { PKTFIFO, "MPS TRC packet FIFO parity error", -1, 1 }, + { MISCPERR, "MPS TRC misc parity error", -1, 1 }, + { 0 } + }; + static const struct intr_info mps_stat_sram_intr_info[] = { + { 0x1fffff, "MPS statistics SRAM parity error", -1, 1 }, + { 0 } + }; + static const struct intr_info mps_stat_tx_intr_info[] = { + { 0xfffff, "MPS statistics Tx FIFO parity error", -1, 1 }, + { 0 } + }; + static const struct intr_info mps_stat_rx_intr_info[] = { + { 0xffffff, "MPS statistics Rx FIFO parity error", -1, 1 }, + { 0 } + }; + static const struct intr_info mps_cls_intr_info[] = { + { MATCHSRAM, "MPS match SRAM parity error", -1, 1 }, + { MATCHTCAM, "MPS match TCAM parity error", -1, 1 }, + { HASHSRAM, "MPS hash SRAM parity error", -1, 1 }, + { 0 } + }; + + int fat; + + fat = t4_handle_intr_status(adapter, MPS_RX_PERR_INT_CAUSE, + mps_rx_intr_info) + + t4_handle_intr_status(adapter, MPS_TX_INT_CAUSE, + mps_tx_intr_info) + + t4_handle_intr_status(adapter, MPS_TRC_INT_CAUSE, + mps_trc_intr_info) + + t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_SRAM, + mps_stat_sram_intr_info) + + t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_TX_FIFO, + mps_stat_tx_intr_info) + + t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_RX_FIFO, + mps_stat_rx_intr_info) + + t4_handle_intr_status(adapter, MPS_CLS_INT_CAUSE, + mps_cls_intr_info); + + t4_write_reg(adapter, MPS_INT_CAUSE, CLSINT | TRCINT | + RXINT | TXINT | STATINT); + t4_read_reg(adapter, MPS_INT_CAUSE); /* flush */ + if (fat) + t4_fatal_err(adapter); +} + +#define MEM_INT_MASK (PERR_INT_CAUSE | ECC_CE_INT_CAUSE | ECC_UE_INT_CAUSE) + +/* + * EDC/MC interrupt handler. + */ +static void mem_intr_handler(struct adapter *adapter, int idx) +{ + static const char name[3][5] = { "EDC0", "EDC1", "MC" }; + + unsigned int addr, cnt_addr, v; + + if (idx <= MEM_EDC1) { + addr = EDC_REG(EDC_INT_CAUSE, idx); + cnt_addr = EDC_REG(EDC_ECC_STATUS, idx); + } else { + addr = MC_INT_CAUSE; + cnt_addr = MC_ECC_STATUS; + } + + v = t4_read_reg(adapter, addr) & MEM_INT_MASK; + if (v & PERR_INT_CAUSE) + dev_alert(adapter->pdev_dev, "%s FIFO parity error\n", + name[idx]); + if (v & ECC_CE_INT_CAUSE) { + u32 cnt = ECC_CECNT_GET(t4_read_reg(adapter, cnt_addr)); + + t4_write_reg(adapter, cnt_addr, ECC_CECNT_MASK); + if (printk_ratelimit()) + dev_warn(adapter->pdev_dev, + "%u %s correctable ECC data error%s\n", + cnt, name[idx], cnt > 1 ? "s" : ""); + } + if (v & ECC_UE_INT_CAUSE) + dev_alert(adapter->pdev_dev, + "%s uncorrectable ECC data error\n", name[idx]); + + t4_write_reg(adapter, addr, v); + if (v & (PERR_INT_CAUSE | ECC_UE_INT_CAUSE)) + t4_fatal_err(adapter); +} + +/* + * MA interrupt handler. + */ +static void ma_intr_handler(struct adapter *adap) +{ + u32 v, status = t4_read_reg(adap, MA_INT_CAUSE); + + if (status & MEM_PERR_INT_CAUSE) + dev_alert(adap->pdev_dev, + "MA parity error, parity status %#x\n", + t4_read_reg(adap, MA_PARITY_ERROR_STATUS)); + if (status & MEM_WRAP_INT_CAUSE) { + v = t4_read_reg(adap, MA_INT_WRAP_STATUS); + dev_alert(adap->pdev_dev, "MA address wrap-around error by " + "client %u to address %#x\n", + MEM_WRAP_CLIENT_NUM_GET(v), + MEM_WRAP_ADDRESS_GET(v) << 4); + } + t4_write_reg(adap, MA_INT_CAUSE, status); + t4_fatal_err(adap); +} + +/* + * SMB interrupt handler. + */ +static void smb_intr_handler(struct adapter *adap) +{ + static const struct intr_info smb_intr_info[] = { + { MSTTXFIFOPARINT, "SMB master Tx FIFO parity error", -1, 1 }, + { MSTRXFIFOPARINT, "SMB master Rx FIFO parity error", -1, 1 }, + { SLVFIFOPARINT, "SMB slave FIFO parity error", -1, 1 }, + { 0 } + }; + + if (t4_handle_intr_status(adap, SMB_INT_CAUSE, smb_intr_info)) + t4_fatal_err(adap); +} + +/* + * NC-SI interrupt handler. + */ +static void ncsi_intr_handler(struct adapter *adap) +{ + static const struct intr_info ncsi_intr_info[] = { + { CIM_DM_PRTY_ERR, "NC-SI CIM parity error", -1, 1 }, + { MPS_DM_PRTY_ERR, "NC-SI MPS parity error", -1, 1 }, + { TXFIFO_PRTY_ERR, "NC-SI Tx FIFO parity error", -1, 1 }, + { RXFIFO_PRTY_ERR, "NC-SI Rx FIFO parity error", -1, 1 }, + { 0 } + }; + + if (t4_handle_intr_status(adap, NCSI_INT_CAUSE, ncsi_intr_info)) + t4_fatal_err(adap); +} + +/* + * XGMAC interrupt handler. + */ +static void xgmac_intr_handler(struct adapter *adap, int port) +{ + u32 v = t4_read_reg(adap, PORT_REG(port, XGMAC_PORT_INT_CAUSE)); + + v &= TXFIFO_PRTY_ERR | RXFIFO_PRTY_ERR; + if (!v) + return; + + if (v & TXFIFO_PRTY_ERR) + dev_alert(adap->pdev_dev, "XGMAC %d Tx FIFO parity error\n", + port); + if (v & RXFIFO_PRTY_ERR) + dev_alert(adap->pdev_dev, "XGMAC %d Rx FIFO parity error\n", + port); + t4_write_reg(adap, PORT_REG(port, XGMAC_PORT_INT_CAUSE), v); + t4_fatal_err(adap); +} + +/* + * PL interrupt handler. + */ +static void pl_intr_handler(struct adapter *adap) +{ + static const struct intr_info pl_intr_info[] = { + { FATALPERR, "T4 fatal parity error", -1, 1 }, + { PERRVFID, "PL VFID_MAP parity error", -1, 1 }, + { 0 } + }; + + if (t4_handle_intr_status(adap, PL_PL_INT_CAUSE, pl_intr_info)) + t4_fatal_err(adap); +} + +#define PF_INTR_MASK (PFSW) +#define GLBL_INTR_MASK (CIM | MPS | PL | PCIE | MC | EDC0 | \ + EDC1 | LE | TP | MA | PM_TX | PM_RX | ULP_RX | \ + CPL_SWITCH | SGE | ULP_TX) + +/** + * t4_slow_intr_handler - control path interrupt handler + * @adapter: the adapter + * + * T4 interrupt handler for non-data global interrupt events, e.g., errors. + * The designation 'slow' is because it involves register reads, while + * data interrupts typically don't involve any MMIOs. + */ +int t4_slow_intr_handler(struct adapter *adapter) +{ + u32 cause = t4_read_reg(adapter, PL_INT_CAUSE); + + if (!(cause & GLBL_INTR_MASK)) + return 0; + if (cause & CIM) + cim_intr_handler(adapter); + if (cause & MPS) + mps_intr_handler(adapter); + if (cause & NCSI) + ncsi_intr_handler(adapter); + if (cause & PL) + pl_intr_handler(adapter); + if (cause & SMB) + smb_intr_handler(adapter); + if (cause & XGMAC0) + xgmac_intr_handler(adapter, 0); + if (cause & XGMAC1) + xgmac_intr_handler(adapter, 1); + if (cause & XGMAC_KR0) + xgmac_intr_handler(adapter, 2); + if (cause & XGMAC_KR1) + xgmac_intr_handler(adapter, 3); + if (cause & PCIE) + pcie_intr_handler(adapter); + if (cause & MC) + mem_intr_handler(adapter, MEM_MC); + if (cause & EDC0) + mem_intr_handler(adapter, MEM_EDC0); + if (cause & EDC1) + mem_intr_handler(adapter, MEM_EDC1); + if (cause & LE) + le_intr_handler(adapter); + if (cause & TP) + tp_intr_handler(adapter); + if (cause & MA) + ma_intr_handler(adapter); + if (cause & PM_TX) + pmtx_intr_handler(adapter); + if (cause & PM_RX) + pmrx_intr_handler(adapter); + if (cause & ULP_RX) + ulprx_intr_handler(adapter); + if (cause & CPL_SWITCH) + cplsw_intr_handler(adapter); + if (cause & SGE) + sge_intr_handler(adapter); + if (cause & ULP_TX) + ulptx_intr_handler(adapter); + + /* Clear the interrupts just processed for which we are the master. */ + t4_write_reg(adapter, PL_INT_CAUSE, cause & GLBL_INTR_MASK); + (void) t4_read_reg(adapter, PL_INT_CAUSE); /* flush */ + return 1; +} + +/** + * t4_intr_enable - enable interrupts + * @adapter: the adapter whose interrupts should be enabled + * + * Enable PF-specific interrupts for the calling function and the top-level + * interrupt concentrator for global interrupts. Interrupts are already + * enabled at each module, here we just enable the roots of the interrupt + * hierarchies. + * + * Note: this function should be called only when the driver manages + * non PF-specific interrupts from the various HW modules. Only one PCI + * function at a time should be doing this. + */ +void t4_intr_enable(struct adapter *adapter) +{ + u32 pf = SOURCEPF_GET(t4_read_reg(adapter, PL_WHOAMI)); + + t4_write_reg(adapter, SGE_INT_ENABLE3, ERR_CPL_EXCEED_IQE_SIZE | + ERR_INVALID_CIDX_INC | ERR_CPL_OPCODE_0 | + ERR_DROPPED_DB | ERR_DATA_CPL_ON_HIGH_QID1 | + ERR_DATA_CPL_ON_HIGH_QID0 | ERR_BAD_DB_PIDX3 | + ERR_BAD_DB_PIDX2 | ERR_BAD_DB_PIDX1 | + ERR_BAD_DB_PIDX0 | ERR_ING_CTXT_PRIO | + ERR_EGR_CTXT_PRIO | INGRESS_SIZE_ERR | + EGRESS_SIZE_ERR); + t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE), PF_INTR_MASK); + t4_set_reg_field(adapter, PL_INT_MAP0, 0, 1 << pf); +} + +/** + * t4_intr_disable - disable interrupts + * @adapter: the adapter whose interrupts should be disabled + * + * Disable interrupts. We only disable the top-level interrupt + * concentrators. The caller must be a PCI function managing global + * interrupts. + */ +void t4_intr_disable(struct adapter *adapter) +{ + u32 pf = SOURCEPF_GET(t4_read_reg(adapter, PL_WHOAMI)); + + t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE), 0); + t4_set_reg_field(adapter, PL_INT_MAP0, 1 << pf, 0); +} + +/** + * hash_mac_addr - return the hash value of a MAC address + * @addr: the 48-bit Ethernet MAC address + * + * Hashes a MAC address according to the hash function used by HW inexact + * (hash) address matching. + */ +static int hash_mac_addr(const u8 *addr) +{ + u32 a = ((u32)addr[0] << 16) | ((u32)addr[1] << 8) | addr[2]; + u32 b = ((u32)addr[3] << 16) | ((u32)addr[4] << 8) | addr[5]; + a ^= b; + a ^= (a >> 12); + a ^= (a >> 6); + return a & 0x3f; +} + +/** + * t4_config_rss_range - configure a portion of the RSS mapping table + * @adapter: the adapter + * @mbox: mbox to use for the FW command + * @viid: virtual interface whose RSS subtable is to be written + * @start: start entry in the table to write + * @n: how many table entries to write + * @rspq: values for the response queue lookup table + * @nrspq: number of values in @rspq + * + * Programs the selected part of the VI's RSS mapping table with the + * provided values. If @nrspq < @n the supplied values are used repeatedly + * until the full table range is populated. + * + * The caller must ensure the values in @rspq are in the range allowed for + * @viid. + */ +int t4_config_rss_range(struct adapter *adapter, int mbox, unsigned int viid, + int start, int n, const u16 *rspq, unsigned int nrspq) +{ + int ret; + const u16 *rsp = rspq; + const u16 *rsp_end = rspq + nrspq; + struct fw_rss_ind_tbl_cmd cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_viid = htonl(FW_CMD_OP(FW_RSS_IND_TBL_CMD) | + FW_CMD_REQUEST | FW_CMD_WRITE | + FW_RSS_IND_TBL_CMD_VIID(viid)); + cmd.retval_len16 = htonl(FW_LEN16(cmd)); + + /* each fw_rss_ind_tbl_cmd takes up to 32 entries */ + while (n > 0) { + int nq = min(n, 32); + __be32 *qp = &cmd.iq0_to_iq2; + + cmd.niqid = htons(nq); + cmd.startidx = htons(start); + + start += nq; + n -= nq; + + while (nq > 0) { + unsigned int v; + + v = FW_RSS_IND_TBL_CMD_IQ0(*rsp); + if (++rsp >= rsp_end) + rsp = rspq; + v |= FW_RSS_IND_TBL_CMD_IQ1(*rsp); + if (++rsp >= rsp_end) + rsp = rspq; + v |= FW_RSS_IND_TBL_CMD_IQ2(*rsp); + if (++rsp >= rsp_end) + rsp = rspq; + + *qp++ = htonl(v); + nq -= 3; + } + + ret = t4_wr_mbox(adapter, mbox, &cmd, sizeof(cmd), NULL); + if (ret) + return ret; + } + return 0; +} + +/** + * t4_config_glbl_rss - configure the global RSS mode + * @adapter: the adapter + * @mbox: mbox to use for the FW command + * @mode: global RSS mode + * @flags: mode-specific flags + * + * Sets the global RSS mode. + */ +int t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode, + unsigned int flags) +{ + struct fw_rss_glb_config_cmd c; + + memset(&c, 0, sizeof(c)); + c.op_to_write = htonl(FW_CMD_OP(FW_RSS_GLB_CONFIG_CMD) | + FW_CMD_REQUEST | FW_CMD_WRITE); + c.retval_len16 = htonl(FW_LEN16(c)); + if (mode == FW_RSS_GLB_CONFIG_CMD_MODE_MANUAL) { + c.u.manual.mode_pkd = htonl(FW_RSS_GLB_CONFIG_CMD_MODE(mode)); + } else if (mode == FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL) { + c.u.basicvirtual.mode_pkd = + htonl(FW_RSS_GLB_CONFIG_CMD_MODE(mode)); + c.u.basicvirtual.synmapen_to_hashtoeplitz = htonl(flags); + } else + return -EINVAL; + return t4_wr_mbox(adapter, mbox, &c, sizeof(c), NULL); +} + +/** + * t4_tp_get_tcp_stats - read TP's TCP MIB counters + * @adap: the adapter + * @v4: holds the TCP/IP counter values + * @v6: holds the TCP/IPv6 counter values + * + * Returns the values of TP's TCP/IP and TCP/IPv6 MIB counters. + * Either @v4 or @v6 may be %NULL to skip the corresponding stats. + */ +void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4, + struct tp_tcp_stats *v6) +{ + u32 val[TP_MIB_TCP_RXT_SEG_LO - TP_MIB_TCP_OUT_RST + 1]; + +#define STAT_IDX(x) ((TP_MIB_TCP_##x) - TP_MIB_TCP_OUT_RST) +#define STAT(x) val[STAT_IDX(x)] +#define STAT64(x) (((u64)STAT(x##_HI) << 32) | STAT(x##_LO)) + + if (v4) { + t4_read_indirect(adap, TP_MIB_INDEX, TP_MIB_DATA, val, + ARRAY_SIZE(val), TP_MIB_TCP_OUT_RST); + v4->tcpOutRsts = STAT(OUT_RST); + v4->tcpInSegs = STAT64(IN_SEG); + v4->tcpOutSegs = STAT64(OUT_SEG); + v4->tcpRetransSegs = STAT64(RXT_SEG); + } + if (v6) { + t4_read_indirect(adap, TP_MIB_INDEX, TP_MIB_DATA, val, + ARRAY_SIZE(val), TP_MIB_TCP_V6OUT_RST); + v6->tcpOutRsts = STAT(OUT_RST); + v6->tcpInSegs = STAT64(IN_SEG); + v6->tcpOutSegs = STAT64(OUT_SEG); + v6->tcpRetransSegs = STAT64(RXT_SEG); + } +#undef STAT64 +#undef STAT +#undef STAT_IDX +} + +/** + * t4_read_mtu_tbl - returns the values in the HW path MTU table + * @adap: the adapter + * @mtus: where to store the MTU values + * @mtu_log: where to store the MTU base-2 log (may be %NULL) + * + * Reads the HW path MTU table. + */ +void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log) +{ + u32 v; + int i; + + for (i = 0; i < NMTUS; ++i) { + t4_write_reg(adap, TP_MTU_TABLE, + MTUINDEX(0xff) | MTUVALUE(i)); + v = t4_read_reg(adap, TP_MTU_TABLE); + mtus[i] = MTUVALUE_GET(v); + if (mtu_log) + mtu_log[i] = MTUWIDTH_GET(v); + } +} + +/** + * init_cong_ctrl - initialize congestion control parameters + * @a: the alpha values for congestion control + * @b: the beta values for congestion control + * + * Initialize the congestion control parameters. + */ +static void __devinit init_cong_ctrl(unsigned short *a, unsigned short *b) +{ + a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1; + a[9] = 2; + a[10] = 3; + a[11] = 4; + a[12] = 5; + a[13] = 6; + a[14] = 7; + a[15] = 8; + a[16] = 9; + a[17] = 10; + a[18] = 14; + a[19] = 17; + a[20] = 21; + a[21] = 25; + a[22] = 30; + a[23] = 35; + a[24] = 45; + a[25] = 60; + a[26] = 80; + a[27] = 100; + a[28] = 200; + a[29] = 300; + a[30] = 400; + a[31] = 500; + + b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0; + b[9] = b[10] = 1; + b[11] = b[12] = 2; + b[13] = b[14] = b[15] = b[16] = 3; + b[17] = b[18] = b[19] = b[20] = b[21] = 4; + b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5; + b[28] = b[29] = 6; + b[30] = b[31] = 7; +} + +/* The minimum additive increment value for the congestion control table */ +#define CC_MIN_INCR 2U + +/** + * t4_load_mtus - write the MTU and congestion control HW tables + * @adap: the adapter + * @mtus: the values for the MTU table + * @alpha: the values for the congestion control alpha parameter + * @beta: the values for the congestion control beta parameter + * + * Write the HW MTU table with the supplied MTUs and the high-speed + * congestion control table with the supplied alpha, beta, and MTUs. + * We write the two tables together because the additive increments + * depend on the MTUs. + */ +void t4_load_mtus(struct adapter *adap, const unsigned short *mtus, + const unsigned short *alpha, const unsigned short *beta) +{ + static const unsigned int avg_pkts[NCCTRL_WIN] = { + 2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640, + 896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480, + 28672, 40960, 57344, 81920, 114688, 163840, 229376 + }; + + unsigned int i, w; + + for (i = 0; i < NMTUS; ++i) { + unsigned int mtu = mtus[i]; + unsigned int log2 = fls(mtu); + + if (!(mtu & ((1 << log2) >> 2))) /* round */ + log2--; + t4_write_reg(adap, TP_MTU_TABLE, MTUINDEX(i) | + MTUWIDTH(log2) | MTUVALUE(mtu)); + + for (w = 0; w < NCCTRL_WIN; ++w) { + unsigned int inc; + + inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w], + CC_MIN_INCR); + + t4_write_reg(adap, TP_CCTRL_TABLE, (i << 21) | + (w << 16) | (beta[w] << 13) | inc); + } + } +} + +/** + * get_mps_bg_map - return the buffer groups associated with a port + * @adap: the adapter + * @idx: the port index + * + * Returns a bitmap indicating which MPS buffer groups are associated + * with the given port. Bit i is set if buffer group i is used by the + * port. + */ +static unsigned int get_mps_bg_map(struct adapter *adap, int idx) +{ + u32 n = NUMPORTS_GET(t4_read_reg(adap, MPS_CMN_CTL)); + + if (n == 0) + return idx == 0 ? 0xf : 0; + if (n == 1) + return idx < 2 ? (3 << (2 * idx)) : 0; + return 1 << idx; +} + +/** + * t4_get_port_stats - collect port statistics + * @adap: the adapter + * @idx: the port index + * @p: the stats structure to fill + * + * Collect statistics related to the given port from HW. + */ +void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p) +{ + u32 bgmap = get_mps_bg_map(adap, idx); + +#define GET_STAT(name) \ + t4_read_reg64(adap, PORT_REG(idx, MPS_PORT_STAT_##name##_L)) +#define GET_STAT_COM(name) t4_read_reg64(adap, MPS_STAT_##name##_L) + + p->tx_octets = GET_STAT(TX_PORT_BYTES); + p->tx_frames = GET_STAT(TX_PORT_FRAMES); + p->tx_bcast_frames = GET_STAT(TX_PORT_BCAST); + p->tx_mcast_frames = GET_STAT(TX_PORT_MCAST); + p->tx_ucast_frames = GET_STAT(TX_PORT_UCAST); + p->tx_error_frames = GET_STAT(TX_PORT_ERROR); + p->tx_frames_64 = GET_STAT(TX_PORT_64B); + p->tx_frames_65_127 = GET_STAT(TX_PORT_65B_127B); + p->tx_frames_128_255 = GET_STAT(TX_PORT_128B_255B); + p->tx_frames_256_511 = GET_STAT(TX_PORT_256B_511B); + p->tx_frames_512_1023 = GET_STAT(TX_PORT_512B_1023B); + p->tx_frames_1024_1518 = GET_STAT(TX_PORT_1024B_1518B); + p->tx_frames_1519_max = GET_STAT(TX_PORT_1519B_MAX); + p->tx_drop = GET_STAT(TX_PORT_DROP); + p->tx_pause = GET_STAT(TX_PORT_PAUSE); + p->tx_ppp0 = GET_STAT(TX_PORT_PPP0); + p->tx_ppp1 = GET_STAT(TX_PORT_PPP1); + p->tx_ppp2 = GET_STAT(TX_PORT_PPP2); + p->tx_ppp3 = GET_STAT(TX_PORT_PPP3); + p->tx_ppp4 = GET_STAT(TX_PORT_PPP4); + p->tx_ppp5 = GET_STAT(TX_PORT_PPP5); + p->tx_ppp6 = GET_STAT(TX_PORT_PPP6); + p->tx_ppp7 = GET_STAT(TX_PORT_PPP7); + + p->rx_octets = GET_STAT(RX_PORT_BYTES); + p->rx_frames = GET_STAT(RX_PORT_FRAMES); + p->rx_bcast_frames = GET_STAT(RX_PORT_BCAST); + p->rx_mcast_frames = GET_STAT(RX_PORT_MCAST); + p->rx_ucast_frames = GET_STAT(RX_PORT_UCAST); + p->rx_too_long = GET_STAT(RX_PORT_MTU_ERROR); + p->rx_jabber = GET_STAT(RX_PORT_MTU_CRC_ERROR); + p->rx_fcs_err = GET_STAT(RX_PORT_CRC_ERROR); + p->rx_len_err = GET_STAT(RX_PORT_LEN_ERROR); + p->rx_symbol_err = GET_STAT(RX_PORT_SYM_ERROR); + p->rx_runt = GET_STAT(RX_PORT_LESS_64B); + p->rx_frames_64 = GET_STAT(RX_PORT_64B); + p->rx_frames_65_127 = GET_STAT(RX_PORT_65B_127B); + p->rx_frames_128_255 = GET_STAT(RX_PORT_128B_255B); + p->rx_frames_256_511 = GET_STAT(RX_PORT_256B_511B); + p->rx_frames_512_1023 = GET_STAT(RX_PORT_512B_1023B); + p->rx_frames_1024_1518 = GET_STAT(RX_PORT_1024B_1518B); + p->rx_frames_1519_max = GET_STAT(RX_PORT_1519B_MAX); + p->rx_pause = GET_STAT(RX_PORT_PAUSE); + p->rx_ppp0 = GET_STAT(RX_PORT_PPP0); + p->rx_ppp1 = GET_STAT(RX_PORT_PPP1); + p->rx_ppp2 = GET_STAT(RX_PORT_PPP2); + p->rx_ppp3 = GET_STAT(RX_PORT_PPP3); + p->rx_ppp4 = GET_STAT(RX_PORT_PPP4); + p->rx_ppp5 = GET_STAT(RX_PORT_PPP5); + p->rx_ppp6 = GET_STAT(RX_PORT_PPP6); + p->rx_ppp7 = GET_STAT(RX_PORT_PPP7); + + p->rx_ovflow0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_MAC_DROP_FRAME) : 0; + p->rx_ovflow1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_MAC_DROP_FRAME) : 0; + p->rx_ovflow2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_MAC_DROP_FRAME) : 0; + p->rx_ovflow3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_MAC_DROP_FRAME) : 0; + p->rx_trunc0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_MAC_TRUNC_FRAME) : 0; + p->rx_trunc1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_MAC_TRUNC_FRAME) : 0; + p->rx_trunc2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_MAC_TRUNC_FRAME) : 0; + p->rx_trunc3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_MAC_TRUNC_FRAME) : 0; + +#undef GET_STAT +#undef GET_STAT_COM +} + +/** + * t4_wol_magic_enable - enable/disable magic packet WoL + * @adap: the adapter + * @port: the physical port index + * @addr: MAC address expected in magic packets, %NULL to disable + * + * Enables/disables magic packet wake-on-LAN for the selected port. + */ +void t4_wol_magic_enable(struct adapter *adap, unsigned int port, + const u8 *addr) +{ + if (addr) { + t4_write_reg(adap, PORT_REG(port, XGMAC_PORT_MAGIC_MACID_LO), + (addr[2] << 24) | (addr[3] << 16) | + (addr[4] << 8) | addr[5]); + t4_write_reg(adap, PORT_REG(port, XGMAC_PORT_MAGIC_MACID_HI), + (addr[0] << 8) | addr[1]); + } + t4_set_reg_field(adap, PORT_REG(port, XGMAC_PORT_CFG2), MAGICEN, + addr ? MAGICEN : 0); +} + +/** + * t4_wol_pat_enable - enable/disable pattern-based WoL + * @adap: the adapter + * @port: the physical port index + * @map: bitmap of which HW pattern filters to set + * @mask0: byte mask for bytes 0-63 of a packet + * @mask1: byte mask for bytes 64-127 of a packet + * @crc: Ethernet CRC for selected bytes + * @enable: enable/disable switch + * + * Sets the pattern filters indicated in @map to mask out the bytes + * specified in @mask0/@mask1 in received packets and compare the CRC of + * the resulting packet against @crc. If @enable is %true pattern-based + * WoL is enabled, otherwise disabled. + */ +int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map, + u64 mask0, u64 mask1, unsigned int crc, bool enable) +{ + int i; + + if (!enable) { + t4_set_reg_field(adap, PORT_REG(port, XGMAC_PORT_CFG2), + PATEN, 0); + return 0; + } + if (map > 0xff) + return -EINVAL; + +#define EPIO_REG(name) PORT_REG(port, XGMAC_PORT_EPIO_##name) + + t4_write_reg(adap, EPIO_REG(DATA1), mask0 >> 32); + t4_write_reg(adap, EPIO_REG(DATA2), mask1); + t4_write_reg(adap, EPIO_REG(DATA3), mask1 >> 32); + + for (i = 0; i < NWOL_PAT; i++, map >>= 1) { + if (!(map & 1)) + continue; + + /* write byte masks */ + t4_write_reg(adap, EPIO_REG(DATA0), mask0); + t4_write_reg(adap, EPIO_REG(OP), ADDRESS(i) | EPIOWR); + t4_read_reg(adap, EPIO_REG(OP)); /* flush */ + if (t4_read_reg(adap, EPIO_REG(OP)) & BUSY) + return -ETIMEDOUT; + + /* write CRC */ + t4_write_reg(adap, EPIO_REG(DATA0), crc); + t4_write_reg(adap, EPIO_REG(OP), ADDRESS(i + 32) | EPIOWR); + t4_read_reg(adap, EPIO_REG(OP)); /* flush */ + if (t4_read_reg(adap, EPIO_REG(OP)) & BUSY) + return -ETIMEDOUT; + } +#undef EPIO_REG + + t4_set_reg_field(adap, PORT_REG(port, XGMAC_PORT_CFG2), 0, PATEN); + return 0; +} + +#define INIT_CMD(var, cmd, rd_wr) do { \ + (var).op_to_write = htonl(FW_CMD_OP(FW_##cmd##_CMD) | \ + FW_CMD_REQUEST | FW_CMD_##rd_wr); \ + (var).retval_len16 = htonl(FW_LEN16(var)); \ +} while (0) + +/** + * t4_mdio_rd - read a PHY register through MDIO + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @phy_addr: the PHY address + * @mmd: the PHY MMD to access (0 for clause 22 PHYs) + * @reg: the register to read + * @valp: where to store the value + * + * Issues a FW command through the given mailbox to read a PHY register. + */ +int t4_mdio_rd(struct adapter *adap, unsigned int mbox, unsigned int phy_addr, + unsigned int mmd, unsigned int reg, u16 *valp) +{ + int ret; + struct fw_ldst_cmd c; + + memset(&c, 0, sizeof(c)); + c.op_to_addrspace = htonl(FW_CMD_OP(FW_LDST_CMD) | FW_CMD_REQUEST | + FW_CMD_READ | FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO)); + c.cycles_to_len16 = htonl(FW_LEN16(c)); + c.u.mdio.paddr_mmd = htons(FW_LDST_CMD_PADDR(phy_addr) | + FW_LDST_CMD_MMD(mmd)); + c.u.mdio.raddr = htons(reg); + + ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); + if (ret == 0) + *valp = ntohs(c.u.mdio.rval); + return ret; +} + +/** + * t4_mdio_wr - write a PHY register through MDIO + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @phy_addr: the PHY address + * @mmd: the PHY MMD to access (0 for clause 22 PHYs) + * @reg: the register to write + * @valp: value to write + * + * Issues a FW command through the given mailbox to write a PHY register. + */ +int t4_mdio_wr(struct adapter *adap, unsigned int mbox, unsigned int phy_addr, + unsigned int mmd, unsigned int reg, u16 val) +{ + struct fw_ldst_cmd c; + + memset(&c, 0, sizeof(c)); + c.op_to_addrspace = htonl(FW_CMD_OP(FW_LDST_CMD) | FW_CMD_REQUEST | + FW_CMD_WRITE | FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO)); + c.cycles_to_len16 = htonl(FW_LEN16(c)); + c.u.mdio.paddr_mmd = htons(FW_LDST_CMD_PADDR(phy_addr) | + FW_LDST_CMD_MMD(mmd)); + c.u.mdio.raddr = htons(reg); + c.u.mdio.rval = htons(val); + + return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + * t4_fw_hello - establish communication with FW + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @evt_mbox: mailbox to receive async FW events + * @master: specifies the caller's willingness to be the device master + * @state: returns the current device state + * + * Issues a command to establish communication with FW. + */ +int t4_fw_hello(struct adapter *adap, unsigned int mbox, unsigned int evt_mbox, + enum dev_master master, enum dev_state *state) +{ + int ret; + struct fw_hello_cmd c; + + INIT_CMD(c, HELLO, WRITE); + c.err_to_mbasyncnot = htonl( + FW_HELLO_CMD_MASTERDIS(master == MASTER_CANT) | + FW_HELLO_CMD_MASTERFORCE(master == MASTER_MUST) | + FW_HELLO_CMD_MBMASTER(master == MASTER_MUST ? mbox : 0xff) | + FW_HELLO_CMD_MBASYNCNOT(evt_mbox)); + + ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); + if (ret == 0 && state) { + u32 v = ntohl(c.err_to_mbasyncnot); + if (v & FW_HELLO_CMD_INIT) + *state = DEV_STATE_INIT; + else if (v & FW_HELLO_CMD_ERR) + *state = DEV_STATE_ERR; + else + *state = DEV_STATE_UNINIT; + } + return ret; +} + +/** + * t4_fw_bye - end communication with FW + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * + * Issues a command to terminate communication with FW. + */ +int t4_fw_bye(struct adapter *adap, unsigned int mbox) +{ + struct fw_bye_cmd c; + + INIT_CMD(c, BYE, WRITE); + return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + * t4_init_cmd - ask FW to initialize the device + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * + * Issues a command to FW to partially initialize the device. This + * performs initialization that generally doesn't depend on user input. + */ +int t4_early_init(struct adapter *adap, unsigned int mbox) +{ + struct fw_initialize_cmd c; + + INIT_CMD(c, INITIALIZE, WRITE); + return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + * t4_fw_reset - issue a reset to FW + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @reset: specifies the type of reset to perform + * + * Issues a reset command of the specified type to FW. + */ +int t4_fw_reset(struct adapter *adap, unsigned int mbox, int reset) +{ + struct fw_reset_cmd c; + + INIT_CMD(c, RESET, WRITE); + c.val = htonl(reset); + return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + * t4_query_params - query FW or device parameters + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @pf: the PF + * @vf: the VF + * @nparams: the number of parameters + * @params: the parameter names + * @val: the parameter values + * + * Reads the value of FW or device parameters. Up to 7 parameters can be + * queried at once. + */ +int t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf, + unsigned int vf, unsigned int nparams, const u32 *params, + u32 *val) +{ + int i, ret; + struct fw_params_cmd c; + __be32 *p = &c.param[0].mnem; + + if (nparams > 7) + return -EINVAL; + + memset(&c, 0, sizeof(c)); + c.op_to_vfn = htonl(FW_CMD_OP(FW_PARAMS_CMD) | FW_CMD_REQUEST | + FW_CMD_READ | FW_PARAMS_CMD_PFN(pf) | + FW_PARAMS_CMD_VFN(vf)); + c.retval_len16 = htonl(FW_LEN16(c)); + for (i = 0; i < nparams; i++, p += 2) + *p = htonl(*params++); + + ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); + if (ret == 0) + for (i = 0, p = &c.param[0].val; i < nparams; i++, p += 2) + *val++ = ntohl(*p); + return ret; +} + +/** + * t4_set_params - sets FW or device parameters + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @pf: the PF + * @vf: the VF + * @nparams: the number of parameters + * @params: the parameter names + * @val: the parameter values + * + * Sets the value of FW or device parameters. Up to 7 parameters can be + * specified at once. + */ +int t4_set_params(struct adapter *adap, unsigned int mbox, unsigned int pf, + unsigned int vf, unsigned int nparams, const u32 *params, + const u32 *val) +{ + struct fw_params_cmd c; + __be32 *p = &c.param[0].mnem; + + if (nparams > 7) + return -EINVAL; + + memset(&c, 0, sizeof(c)); + c.op_to_vfn = htonl(FW_CMD_OP(FW_PARAMS_CMD) | FW_CMD_REQUEST | + FW_CMD_WRITE | FW_PARAMS_CMD_PFN(pf) | + FW_PARAMS_CMD_VFN(vf)); + c.retval_len16 = htonl(FW_LEN16(c)); + while (nparams--) { + *p++ = htonl(*params++); + *p++ = htonl(*val++); + } + + return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + * t4_cfg_pfvf - configure PF/VF resource limits + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @pf: the PF being configured + * @vf: the VF being configured + * @txq: the max number of egress queues + * @txq_eth_ctrl: the max number of egress Ethernet or control queues + * @rxqi: the max number of interrupt-capable ingress queues + * @rxq: the max number of interruptless ingress queues + * @tc: the PCI traffic class + * @vi: the max number of virtual interfaces + * @cmask: the channel access rights mask for the PF/VF + * @pmask: the port access rights mask for the PF/VF + * @nexact: the maximum number of exact MPS filters + * @rcaps: read capabilities + * @wxcaps: write/execute capabilities + * + * Configures resource limits and capabilities for a physical or virtual + * function. + */ +int t4_cfg_pfvf(struct adapter *adap, unsigned int mbox, unsigned int pf, + unsigned int vf, unsigned int txq, unsigned int txq_eth_ctrl, + unsigned int rxqi, unsigned int rxq, unsigned int tc, + unsigned int vi, unsigned int cmask, unsigned int pmask, + unsigned int nexact, unsigned int rcaps, unsigned int wxcaps) +{ + struct fw_pfvf_cmd c; + + memset(&c, 0, sizeof(c)); + c.op_to_vfn = htonl(FW_CMD_OP(FW_PFVF_CMD) | FW_CMD_REQUEST | + FW_CMD_WRITE | FW_PFVF_CMD_PFN(pf) | + FW_PFVF_CMD_VFN(vf)); + c.retval_len16 = htonl(FW_LEN16(c)); + c.niqflint_niq = htonl(FW_PFVF_CMD_NIQFLINT(rxqi) | + FW_PFVF_CMD_NIQ(rxq)); + c.type_to_neq = htonl(FW_PFVF_CMD_CMASK(cmask) | + FW_PFVF_CMD_PMASK(pmask) | + FW_PFVF_CMD_NEQ(txq)); + c.tc_to_nexactf = htonl(FW_PFVF_CMD_TC(tc) | FW_PFVF_CMD_NVI(vi) | + FW_PFVF_CMD_NEXACTF(nexact)); + c.r_caps_to_nethctrl = htonl(FW_PFVF_CMD_R_CAPS(rcaps) | + FW_PFVF_CMD_WX_CAPS(wxcaps) | + FW_PFVF_CMD_NETHCTRL(txq_eth_ctrl)); + return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + * t4_alloc_vi - allocate a virtual interface + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @port: physical port associated with the VI + * @pf: the PF owning the VI + * @vf: the VF owning the VI + * @nmac: number of MAC addresses needed (1 to 5) + * @mac: the MAC addresses of the VI + * @rss_size: size of RSS table slice associated with this VI + * + * Allocates a virtual interface for the given physical port. If @mac is + * not %NULL it contains the MAC addresses of the VI as assigned by FW. + * @mac should be large enough to hold @nmac Ethernet addresses, they are + * stored consecutively so the space needed is @nmac * 6 bytes. + * Returns a negative error number or the non-negative VI id. + */ +int t4_alloc_vi(struct adapter *adap, unsigned int mbox, unsigned int port, + unsigned int pf, unsigned int vf, unsigned int nmac, u8 *mac, + unsigned int *rss_size) +{ + int ret; + struct fw_vi_cmd c; + + memset(&c, 0, sizeof(c)); + c.op_to_vfn = htonl(FW_CMD_OP(FW_VI_CMD) | FW_CMD_REQUEST | + FW_CMD_WRITE | FW_CMD_EXEC | + FW_VI_CMD_PFN(pf) | FW_VI_CMD_VFN(vf)); + c.alloc_to_len16 = htonl(FW_VI_CMD_ALLOC | FW_LEN16(c)); + c.portid_pkd = FW_VI_CMD_PORTID(port); + c.nmac = nmac - 1; + + ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); + if (ret) + return ret; + + if (mac) { + memcpy(mac, c.mac, sizeof(c.mac)); + switch (nmac) { + case 5: + memcpy(mac + 24, c.nmac3, sizeof(c.nmac3)); + case 4: + memcpy(mac + 18, c.nmac2, sizeof(c.nmac2)); + case 3: + memcpy(mac + 12, c.nmac1, sizeof(c.nmac1)); + case 2: + memcpy(mac + 6, c.nmac0, sizeof(c.nmac0)); + } + } + if (rss_size) + *rss_size = FW_VI_CMD_RSSSIZE_GET(ntohs(c.rsssize_pkd)); + return FW_VI_CMD_VIID_GET(ntohs(c.type_viid)); +} + +/** + * t4_set_rxmode - set Rx properties of a virtual interface + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @viid: the VI id + * @mtu: the new MTU or -1 + * @promisc: 1 to enable promiscuous mode, 0 to disable it, -1 no change + * @all_multi: 1 to enable all-multi mode, 0 to disable it, -1 no change + * @bcast: 1 to enable broadcast Rx, 0 to disable it, -1 no change + * @vlanex: 1 to enable HW VLAN extraction, 0 to disable it, -1 no change + * @sleep_ok: if true we may sleep while awaiting command completion + * + * Sets Rx properties of a virtual interface. + */ +int t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid, + int mtu, int promisc, int all_multi, int bcast, int vlanex, + bool sleep_ok) +{ + struct fw_vi_rxmode_cmd c; + + /* convert to FW values */ + if (mtu < 0) + mtu = FW_RXMODE_MTU_NO_CHG; + if (promisc < 0) + promisc = FW_VI_RXMODE_CMD_PROMISCEN_MASK; + if (all_multi < 0) + all_multi = FW_VI_RXMODE_CMD_ALLMULTIEN_MASK; + if (bcast < 0) + bcast = FW_VI_RXMODE_CMD_BROADCASTEN_MASK; + if (vlanex < 0) + vlanex = FW_VI_RXMODE_CMD_VLANEXEN_MASK; + + memset(&c, 0, sizeof(c)); + c.op_to_viid = htonl(FW_CMD_OP(FW_VI_RXMODE_CMD) | FW_CMD_REQUEST | + FW_CMD_WRITE | FW_VI_RXMODE_CMD_VIID(viid)); + c.retval_len16 = htonl(FW_LEN16(c)); + c.mtu_to_vlanexen = htonl(FW_VI_RXMODE_CMD_MTU(mtu) | + FW_VI_RXMODE_CMD_PROMISCEN(promisc) | + FW_VI_RXMODE_CMD_ALLMULTIEN(all_multi) | + FW_VI_RXMODE_CMD_BROADCASTEN(bcast) | + FW_VI_RXMODE_CMD_VLANEXEN(vlanex)); + return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok); +} + +/** + * t4_alloc_mac_filt - allocates exact-match filters for MAC addresses + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @viid: the VI id + * @free: if true any existing filters for this VI id are first removed + * @naddr: the number of MAC addresses to allocate filters for (up to 7) + * @addr: the MAC address(es) + * @idx: where to store the index of each allocated filter + * @hash: pointer to hash address filter bitmap + * @sleep_ok: call is allowed to sleep + * + * Allocates an exact-match filter for each of the supplied addresses and + * sets it to the corresponding address. If @idx is not %NULL it should + * have at least @naddr entries, each of which will be set to the index of + * the filter allocated for the corresponding MAC address. If a filter + * could not be allocated for an address its index is set to 0xffff. + * If @hash is not %NULL addresses that fail to allocate an exact filter + * are hashed and update the hash filter bitmap pointed at by @hash. + * + * Returns a negative error number or the number of filters allocated. + */ +int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox, + unsigned int viid, bool free, unsigned int naddr, + const u8 **addr, u16 *idx, u64 *hash, bool sleep_ok) +{ + int i, ret; + struct fw_vi_mac_cmd c; + struct fw_vi_mac_exact *p; + + if (naddr > 7) + return -EINVAL; + + memset(&c, 0, sizeof(c)); + c.op_to_viid = htonl(FW_CMD_OP(FW_VI_MAC_CMD) | FW_CMD_REQUEST | + FW_CMD_WRITE | (free ? FW_CMD_EXEC : 0) | + FW_VI_MAC_CMD_VIID(viid)); + c.freemacs_to_len16 = htonl(FW_VI_MAC_CMD_FREEMACS(free) | + FW_CMD_LEN16((naddr + 2) / 2)); + + for (i = 0, p = c.u.exact; i < naddr; i++, p++) { + p->valid_to_idx = htons(FW_VI_MAC_CMD_VALID | + FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC)); + memcpy(p->macaddr, addr[i], sizeof(p->macaddr)); + } + + ret = t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), &c, sleep_ok); + if (ret) + return ret; + + for (i = 0, p = c.u.exact; i < naddr; i++, p++) { + u16 index = FW_VI_MAC_CMD_IDX_GET(ntohs(p->valid_to_idx)); + + if (idx) + idx[i] = index >= NEXACT_MAC ? 0xffff : index; + if (index < NEXACT_MAC) + ret++; + else if (hash) + *hash |= (1ULL << hash_mac_addr(addr[i])); + } + return ret; +} + +/** + * t4_change_mac - modifies the exact-match filter for a MAC address + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @viid: the VI id + * @idx: index of existing filter for old value of MAC address, or -1 + * @addr: the new MAC address value + * @persist: whether a new MAC allocation should be persistent + * @add_smt: if true also add the address to the HW SMT + * + * Modifies an exact-match filter and sets it to the new MAC address. + * Note that in general it is not possible to modify the value of a given + * filter so the generic way to modify an address filter is to free the one + * being used by the old address value and allocate a new filter for the + * new address value. @idx can be -1 if the address is a new addition. + * + * Returns a negative error number or the index of the filter with the new + * MAC value. + */ +int t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid, + int idx, const u8 *addr, bool persist, bool add_smt) +{ + int ret, mode; + struct fw_vi_mac_cmd c; + struct fw_vi_mac_exact *p = c.u.exact; + + if (idx < 0) /* new allocation */ + idx = persist ? FW_VI_MAC_ADD_PERSIST_MAC : FW_VI_MAC_ADD_MAC; + mode = add_smt ? FW_VI_MAC_SMT_AND_MPSTCAM : FW_VI_MAC_MPS_TCAM_ENTRY; + + memset(&c, 0, sizeof(c)); + c.op_to_viid = htonl(FW_CMD_OP(FW_VI_MAC_CMD) | FW_CMD_REQUEST | + FW_CMD_WRITE | FW_VI_MAC_CMD_VIID(viid)); + c.freemacs_to_len16 = htonl(FW_CMD_LEN16(1)); + p->valid_to_idx = htons(FW_VI_MAC_CMD_VALID | + FW_VI_MAC_CMD_SMAC_RESULT(mode) | + FW_VI_MAC_CMD_IDX(idx)); + memcpy(p->macaddr, addr, sizeof(p->macaddr)); + + ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); + if (ret == 0) { + ret = FW_VI_MAC_CMD_IDX_GET(ntohs(p->valid_to_idx)); + if (ret >= NEXACT_MAC) + ret = -ENOMEM; + } + return ret; +} + +/** + * t4_set_addr_hash - program the MAC inexact-match hash filter + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @viid: the VI id + * @ucast: whether the hash filter should also match unicast addresses + * @vec: the value to be written to the hash filter + * @sleep_ok: call is allowed to sleep + * + * Sets the 64-bit inexact-match hash filter for a virtual interface. + */ +int t4_set_addr_hash(struct adapter *adap, unsigned int mbox, unsigned int viid, + bool ucast, u64 vec, bool sleep_ok) +{ + struct fw_vi_mac_cmd c; + + memset(&c, 0, sizeof(c)); + c.op_to_viid = htonl(FW_CMD_OP(FW_VI_MAC_CMD) | FW_CMD_REQUEST | + FW_CMD_WRITE | FW_VI_ENABLE_CMD_VIID(viid)); + c.freemacs_to_len16 = htonl(FW_VI_MAC_CMD_HASHVECEN | + FW_VI_MAC_CMD_HASHUNIEN(ucast) | + FW_CMD_LEN16(1)); + c.u.hash.hashvec = cpu_to_be64(vec); + return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok); +} + +/** + * t4_enable_vi - enable/disable a virtual interface + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @viid: the VI id + * @rx_en: 1=enable Rx, 0=disable Rx + * @tx_en: 1=enable Tx, 0=disable Tx + * + * Enables/disables a virtual interface. + */ +int t4_enable_vi(struct adapter *adap, unsigned int mbox, unsigned int viid, + bool rx_en, bool tx_en) +{ + struct fw_vi_enable_cmd c; + + memset(&c, 0, sizeof(c)); + c.op_to_viid = htonl(FW_CMD_OP(FW_VI_ENABLE_CMD) | FW_CMD_REQUEST | + FW_CMD_EXEC | FW_VI_ENABLE_CMD_VIID(viid)); + c.ien_to_len16 = htonl(FW_VI_ENABLE_CMD_IEN(rx_en) | + FW_VI_ENABLE_CMD_EEN(tx_en) | FW_LEN16(c)); + return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + * t4_identify_port - identify a VI's port by blinking its LED + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @viid: the VI id + * @nblinks: how many times to blink LED at 2.5 Hz + * + * Identifies a VI's port by blinking its LED. + */ +int t4_identify_port(struct adapter *adap, unsigned int mbox, unsigned int viid, + unsigned int nblinks) +{ + struct fw_vi_enable_cmd c; + + c.op_to_viid = htonl(FW_CMD_OP(FW_VI_ENABLE_CMD) | FW_CMD_REQUEST | + FW_CMD_EXEC | FW_VI_ENABLE_CMD_VIID(viid)); + c.ien_to_len16 = htonl(FW_VI_ENABLE_CMD_LED | FW_LEN16(c)); + c.blinkdur = htons(nblinks); + return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + * t4_iq_free - free an ingress queue and its FLs + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @pf: the PF owning the queues + * @vf: the VF owning the queues + * @iqtype: the ingress queue type + * @iqid: ingress queue id + * @fl0id: FL0 queue id or 0xffff if no attached FL0 + * @fl1id: FL1 queue id or 0xffff if no attached FL1 + * + * Frees an ingress queue and its associated FLs, if any. + */ +int t4_iq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, + unsigned int vf, unsigned int iqtype, unsigned int iqid, + unsigned int fl0id, unsigned int fl1id) +{ + struct fw_iq_cmd c; + + memset(&c, 0, sizeof(c)); + c.op_to_vfn = htonl(FW_CMD_OP(FW_IQ_CMD) | FW_CMD_REQUEST | + FW_CMD_EXEC | FW_IQ_CMD_PFN(pf) | + FW_IQ_CMD_VFN(vf)); + c.alloc_to_len16 = htonl(FW_IQ_CMD_FREE | FW_LEN16(c)); + c.type_to_iqandstindex = htonl(FW_IQ_CMD_TYPE(iqtype)); + c.iqid = htons(iqid); + c.fl0id = htons(fl0id); + c.fl1id = htons(fl1id); + return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + * t4_eth_eq_free - free an Ethernet egress queue + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @pf: the PF owning the queue + * @vf: the VF owning the queue + * @eqid: egress queue id + * + * Frees an Ethernet egress queue. + */ +int t4_eth_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, + unsigned int vf, unsigned int eqid) +{ + struct fw_eq_eth_cmd c; + + memset(&c, 0, sizeof(c)); + c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_ETH_CMD) | FW_CMD_REQUEST | + FW_CMD_EXEC | FW_EQ_ETH_CMD_PFN(pf) | + FW_EQ_ETH_CMD_VFN(vf)); + c.alloc_to_len16 = htonl(FW_EQ_ETH_CMD_FREE | FW_LEN16(c)); + c.eqid_pkd = htonl(FW_EQ_ETH_CMD_EQID(eqid)); + return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + * t4_ctrl_eq_free - free a control egress queue + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @pf: the PF owning the queue + * @vf: the VF owning the queue + * @eqid: egress queue id + * + * Frees a control egress queue. + */ +int t4_ctrl_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, + unsigned int vf, unsigned int eqid) +{ + struct fw_eq_ctrl_cmd c; + + memset(&c, 0, sizeof(c)); + c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_CTRL_CMD) | FW_CMD_REQUEST | + FW_CMD_EXEC | FW_EQ_CTRL_CMD_PFN(pf) | + FW_EQ_CTRL_CMD_VFN(vf)); + c.alloc_to_len16 = htonl(FW_EQ_CTRL_CMD_FREE | FW_LEN16(c)); + c.cmpliqid_eqid = htonl(FW_EQ_CTRL_CMD_EQID(eqid)); + return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + * t4_ofld_eq_free - free an offload egress queue + * @adap: the adapter + * @mbox: mailbox to use for the FW command + * @pf: the PF owning the queue + * @vf: the VF owning the queue + * @eqid: egress queue id + * + * Frees a control egress queue. + */ +int t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, + unsigned int vf, unsigned int eqid) +{ + struct fw_eq_ofld_cmd c; + + memset(&c, 0, sizeof(c)); + c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_OFLD_CMD) | FW_CMD_REQUEST | + FW_CMD_EXEC | FW_EQ_OFLD_CMD_PFN(pf) | + FW_EQ_OFLD_CMD_VFN(vf)); + c.alloc_to_len16 = htonl(FW_EQ_OFLD_CMD_FREE | FW_LEN16(c)); + c.eqid_pkd = htonl(FW_EQ_OFLD_CMD_EQID(eqid)); + return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL); +} + +/** + * t4_handle_fw_rpl - process a FW reply message + * @adap: the adapter + * @rpl: start of the FW message + * + * Processes a FW message, such as link state change messages. + */ +int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl) +{ + u8 opcode = *(const u8 *)rpl; + + if (opcode == FW_PORT_CMD) { /* link/module state change message */ + int speed = 0, fc = 0; + const struct fw_port_cmd *p = (void *)rpl; + int chan = FW_PORT_CMD_PORTID_GET(ntohl(p->op_to_portid)); + int port = adap->chan_map[chan]; + struct port_info *pi = adap2pinfo(adap, port); + struct link_config *lc = &pi->link_cfg; + u32 stat = ntohl(p->u.info.lstatus_to_modtype); + int link_ok = (stat & FW_PORT_CMD_LSTATUS) != 0; + u32 mod = FW_PORT_CMD_MODTYPE_GET(stat); + + if (stat & FW_PORT_CMD_RXPAUSE) + fc |= PAUSE_RX; + if (stat & FW_PORT_CMD_TXPAUSE) + fc |= PAUSE_TX; + if (stat & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100M)) + speed = SPEED_100; + else if (stat & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_1G)) + speed = SPEED_1000; + else if (stat & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_10G)) + speed = SPEED_10000; + + if (link_ok != lc->link_ok || speed != lc->speed || + fc != lc->fc) { /* something changed */ + lc->link_ok = link_ok; + lc->speed = speed; + lc->fc = fc; + t4_os_link_changed(adap, port, link_ok); + } + if (mod != pi->mod_type) { + pi->mod_type = mod; + t4_os_portmod_changed(adap, port); + } + } + return 0; +} + +static void __devinit get_pci_mode(struct adapter *adapter, + struct pci_params *p) +{ + u16 val; + u32 pcie_cap = pci_pcie_cap(adapter->pdev); + + if (pcie_cap) { + pci_read_config_word(adapter->pdev, pcie_cap + PCI_EXP_LNKSTA, + &val); + p->speed = val & PCI_EXP_LNKSTA_CLS; + p->width = (val & PCI_EXP_LNKSTA_NLW) >> 4; + } +} + +/** + * init_link_config - initialize a link's SW state + * @lc: structure holding the link state + * @caps: link capabilities + * + * Initializes the SW state maintained for each link, including the link's + * capabilities and default speed/flow-control/autonegotiation settings. + */ +static void __devinit init_link_config(struct link_config *lc, + unsigned int caps) +{ + lc->supported = caps; + lc->requested_speed = 0; + lc->speed = 0; + lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX; + if (lc->supported & FW_PORT_CAP_ANEG) { + lc->advertising = lc->supported & ADVERT_MASK; + lc->autoneg = AUTONEG_ENABLE; + lc->requested_fc |= PAUSE_AUTONEG; + } else { + lc->advertising = 0; + lc->autoneg = AUTONEG_DISABLE; + } +} + +int t4_wait_dev_ready(struct adapter *adap) +{ + if (t4_read_reg(adap, PL_WHOAMI) != 0xffffffff) + return 0; + msleep(500); + return t4_read_reg(adap, PL_WHOAMI) != 0xffffffff ? 0 : -EIO; +} + +static int __devinit get_flash_params(struct adapter *adap) +{ + int ret; + u32 info; + + ret = sf1_write(adap, 1, 1, 0, SF_RD_ID); + if (!ret) + ret = sf1_read(adap, 3, 0, 1, &info); + t4_write_reg(adap, SF_OP, 0); /* unlock SF */ + if (ret) + return ret; + + if ((info & 0xff) != 0x20) /* not a Numonix flash */ + return -EINVAL; + info >>= 16; /* log2 of size */ + if (info >= 0x14 && info < 0x18) + adap->params.sf_nsec = 1 << (info - 16); + else if (info == 0x18) + adap->params.sf_nsec = 64; + else + return -EINVAL; + adap->params.sf_size = 1 << info; + adap->params.sf_fw_start = + t4_read_reg(adap, CIM_BOOT_CFG) & BOOTADDR_MASK; + return 0; +} + +/** + * t4_prep_adapter - prepare SW and HW for operation + * @adapter: the adapter + * @reset: if true perform a HW reset + * + * Initialize adapter SW state for the various HW modules, set initial + * values for some adapter tunables, take PHYs out of reset, and + * initialize the MDIO interface. + */ +int __devinit t4_prep_adapter(struct adapter *adapter) +{ + int ret; + + ret = t4_wait_dev_ready(adapter); + if (ret < 0) + return ret; + + get_pci_mode(adapter, &adapter->params.pci); + adapter->params.rev = t4_read_reg(adapter, PL_REV); + + ret = get_flash_params(adapter); + if (ret < 0) { + dev_err(adapter->pdev_dev, "error %d identifying flash\n", ret); + return ret; + } + + ret = get_vpd_params(adapter, &adapter->params.vpd); + if (ret < 0) + return ret; + + init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd); + + /* + * Default port for debugging in case we can't reach FW. + */ + adapter->params.nports = 1; + adapter->params.portvec = 1; + return 0; +} + +int __devinit t4_port_init(struct adapter *adap, int mbox, int pf, int vf) +{ + u8 addr[6]; + int ret, i, j = 0; + struct fw_port_cmd c; + struct fw_rss_vi_config_cmd rvc; + + memset(&c, 0, sizeof(c)); + memset(&rvc, 0, sizeof(rvc)); + + for_each_port(adap, i) { + unsigned int rss_size; + struct port_info *p = adap2pinfo(adap, i); + + while ((adap->params.portvec & (1 << j)) == 0) + j++; + + c.op_to_portid = htonl(FW_CMD_OP(FW_PORT_CMD) | + FW_CMD_REQUEST | FW_CMD_READ | + FW_PORT_CMD_PORTID(j)); + c.action_to_len16 = htonl( + FW_PORT_CMD_ACTION(FW_PORT_ACTION_GET_PORT_INFO) | + FW_LEN16(c)); + ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c); + if (ret) + return ret; + + ret = t4_alloc_vi(adap, mbox, j, pf, vf, 1, addr, &rss_size); + if (ret < 0) + return ret; + + p->viid = ret; + p->tx_chan = j; + p->lport = j; + p->rss_size = rss_size; + memcpy(adap->port[i]->dev_addr, addr, ETH_ALEN); + memcpy(adap->port[i]->perm_addr, addr, ETH_ALEN); + adap->port[i]->dev_id = j; + + ret = ntohl(c.u.info.lstatus_to_modtype); + p->mdio_addr = (ret & FW_PORT_CMD_MDIOCAP) ? + FW_PORT_CMD_MDIOADDR_GET(ret) : -1; + p->port_type = FW_PORT_CMD_PTYPE_GET(ret); + p->mod_type = FW_PORT_MOD_TYPE_NA; + + rvc.op_to_viid = htonl(FW_CMD_OP(FW_RSS_VI_CONFIG_CMD) | + FW_CMD_REQUEST | FW_CMD_READ | + FW_RSS_VI_CONFIG_CMD_VIID(p->viid)); + rvc.retval_len16 = htonl(FW_LEN16(rvc)); + ret = t4_wr_mbox(adap, mbox, &rvc, sizeof(rvc), &rvc); + if (ret) + return ret; + p->rss_mode = ntohl(rvc.u.basicvirtual.defaultq_to_udpen); + + init_link_config(&p->link_cfg, ntohs(c.u.info.pcap)); + j++; + } + return 0; +} diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h new file mode 100644 index 000000000000..c26b455f37de --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h @@ -0,0 +1,140 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __T4_HW_H +#define __T4_HW_H + +#include + +enum { + NCHAN = 4, /* # of HW channels */ + MAX_MTU = 9600, /* max MAC MTU, excluding header + FCS */ + EEPROMSIZE = 17408, /* Serial EEPROM physical size */ + EEPROMVSIZE = 32768, /* Serial EEPROM virtual address space size */ + EEPROMPFSIZE = 1024, /* EEPROM writable area size for PFn, n>0 */ + RSS_NENTRIES = 2048, /* # of entries in RSS mapping table */ + TCB_SIZE = 128, /* TCB size */ + NMTUS = 16, /* size of MTU table */ + NCCTRL_WIN = 32, /* # of congestion control windows */ + NEXACT_MAC = 336, /* # of exact MAC address filters */ + L2T_SIZE = 4096, /* # of L2T entries */ + MBOX_LEN = 64, /* mailbox size in bytes */ + TRACE_LEN = 112, /* length of trace data and mask */ + FILTER_OPT_LEN = 36, /* filter tuple width for optional components */ + NWOL_PAT = 8, /* # of WoL patterns */ + WOL_PAT_LEN = 128, /* length of WoL patterns */ +}; + +enum { + SF_PAGE_SIZE = 256, /* serial flash page size */ +}; + +enum { RSP_TYPE_FLBUF, RSP_TYPE_CPL, RSP_TYPE_INTR }; /* response entry types */ + +enum { MBOX_OWNER_NONE, MBOX_OWNER_FW, MBOX_OWNER_DRV }; /* mailbox owners */ + +enum { + SGE_MAX_WR_LEN = 512, /* max WR size in bytes */ + SGE_NTIMERS = 6, /* # of interrupt holdoff timer values */ + SGE_NCOUNTERS = 4, /* # of interrupt packet counter values */ + + SGE_TIMER_RSTRT_CNTR = 6, /* restart RX packet threshold counter */ + SGE_TIMER_UPD_CIDX = 7, /* update cidx only */ + + SGE_EQ_IDXSIZE = 64, /* egress queue pidx/cidx unit size */ + + SGE_INTRDST_PCI = 0, /* interrupt destination is PCI-E */ + SGE_INTRDST_IQ = 1, /* destination is an ingress queue */ + + SGE_UPDATEDEL_NONE = 0, /* ingress queue pidx update delivery */ + SGE_UPDATEDEL_INTR = 1, /* interrupt */ + SGE_UPDATEDEL_STPG = 2, /* status page */ + SGE_UPDATEDEL_BOTH = 3, /* interrupt and status page */ + + SGE_HOSTFCMODE_NONE = 0, /* egress queue cidx updates */ + SGE_HOSTFCMODE_IQ = 1, /* sent to ingress queue */ + SGE_HOSTFCMODE_STPG = 2, /* sent to status page */ + SGE_HOSTFCMODE_BOTH = 3, /* ingress queue and status page */ + + SGE_FETCHBURSTMIN_16B = 0,/* egress queue descriptor fetch minimum */ + SGE_FETCHBURSTMIN_32B = 1, + SGE_FETCHBURSTMIN_64B = 2, + SGE_FETCHBURSTMIN_128B = 3, + + SGE_FETCHBURSTMAX_64B = 0,/* egress queue descriptor fetch maximum */ + SGE_FETCHBURSTMAX_128B = 1, + SGE_FETCHBURSTMAX_256B = 2, + SGE_FETCHBURSTMAX_512B = 3, + + SGE_CIDXFLUSHTHRESH_1 = 0,/* egress queue cidx flush threshold */ + SGE_CIDXFLUSHTHRESH_2 = 1, + SGE_CIDXFLUSHTHRESH_4 = 2, + SGE_CIDXFLUSHTHRESH_8 = 3, + SGE_CIDXFLUSHTHRESH_16 = 4, + SGE_CIDXFLUSHTHRESH_32 = 5, + SGE_CIDXFLUSHTHRESH_64 = 6, + SGE_CIDXFLUSHTHRESH_128 = 7, + + SGE_INGPADBOUNDARY_SHIFT = 5,/* ingress queue pad boundary */ +}; + +struct sge_qstat { /* data written to SGE queue status entries */ + __be32 qid; + __be16 cidx; + __be16 pidx; +}; + +/* + * Structure for last 128 bits of response descriptors + */ +struct rsp_ctrl { + __be32 hdrbuflen_pidx; + __be32 pldbuflen_qid; + union { + u8 type_gen; + __be64 last_flit; + }; +}; + +#define RSPD_NEWBUF 0x80000000U +#define RSPD_LEN(x) (((x) >> 0) & 0x7fffffffU) +#define RSPD_QID(x) RSPD_LEN(x) + +#define RSPD_GEN(x) ((x) >> 7) +#define RSPD_TYPE(x) (((x) >> 4) & 3) + +#define QINTR_CNT_EN 0x1 +#define QINTR_TIMER_IDX(x) ((x) << 1) +#define QINTR_TIMER_IDX_GET(x) (((x) >> 1) & 0x7) +#endif /* __T4_HW_H */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h new file mode 100644 index 000000000000..eb71b8250b91 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h @@ -0,0 +1,678 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __T4_MSG_H +#define __T4_MSG_H + +#include + +enum { + CPL_PASS_OPEN_REQ = 0x1, + CPL_PASS_ACCEPT_RPL = 0x2, + CPL_ACT_OPEN_REQ = 0x3, + CPL_SET_TCB_FIELD = 0x5, + CPL_GET_TCB = 0x6, + CPL_CLOSE_CON_REQ = 0x8, + CPL_CLOSE_LISTSRV_REQ = 0x9, + CPL_ABORT_REQ = 0xA, + CPL_ABORT_RPL = 0xB, + CPL_RX_DATA_ACK = 0xD, + CPL_TX_PKT = 0xE, + CPL_L2T_WRITE_REQ = 0x12, + CPL_TID_RELEASE = 0x1A, + + CPL_CLOSE_LISTSRV_RPL = 0x20, + CPL_L2T_WRITE_RPL = 0x23, + CPL_PASS_OPEN_RPL = 0x24, + CPL_ACT_OPEN_RPL = 0x25, + CPL_PEER_CLOSE = 0x26, + CPL_ABORT_REQ_RSS = 0x2B, + CPL_ABORT_RPL_RSS = 0x2D, + + CPL_CLOSE_CON_RPL = 0x32, + CPL_ISCSI_HDR = 0x33, + CPL_RDMA_CQE = 0x35, + CPL_RDMA_CQE_READ_RSP = 0x36, + CPL_RDMA_CQE_ERR = 0x37, + CPL_RX_DATA = 0x39, + CPL_SET_TCB_RPL = 0x3A, + CPL_RX_PKT = 0x3B, + CPL_RX_DDP_COMPLETE = 0x3F, + + CPL_ACT_ESTABLISH = 0x40, + CPL_PASS_ESTABLISH = 0x41, + CPL_RX_DATA_DDP = 0x42, + CPL_PASS_ACCEPT_REQ = 0x44, + + CPL_RDMA_READ_REQ = 0x60, + + CPL_PASS_OPEN_REQ6 = 0x81, + CPL_ACT_OPEN_REQ6 = 0x83, + + CPL_RDMA_TERMINATE = 0xA2, + CPL_RDMA_WRITE = 0xA4, + CPL_SGE_EGR_UPDATE = 0xA5, + + CPL_TRACE_PKT = 0xB0, + + CPL_FW4_MSG = 0xC0, + CPL_FW4_PLD = 0xC1, + CPL_FW4_ACK = 0xC3, + + CPL_FW6_MSG = 0xE0, + CPL_FW6_PLD = 0xE1, + CPL_TX_PKT_LSO = 0xED, + CPL_TX_PKT_XT = 0xEE, + + NUM_CPL_CMDS +}; + +enum CPL_error { + CPL_ERR_NONE = 0, + CPL_ERR_TCAM_FULL = 3, + CPL_ERR_BAD_LENGTH = 15, + CPL_ERR_BAD_ROUTE = 18, + CPL_ERR_CONN_RESET = 20, + CPL_ERR_CONN_EXIST_SYNRECV = 21, + CPL_ERR_CONN_EXIST = 22, + CPL_ERR_ARP_MISS = 23, + CPL_ERR_BAD_SYN = 24, + CPL_ERR_CONN_TIMEDOUT = 30, + CPL_ERR_XMIT_TIMEDOUT = 31, + CPL_ERR_PERSIST_TIMEDOUT = 32, + CPL_ERR_FINWAIT2_TIMEDOUT = 33, + CPL_ERR_KEEPALIVE_TIMEDOUT = 34, + CPL_ERR_RTX_NEG_ADVICE = 35, + CPL_ERR_PERSIST_NEG_ADVICE = 36, + CPL_ERR_ABORT_FAILED = 42, + CPL_ERR_IWARP_FLM = 50, +}; + +enum { + ULP_MODE_NONE = 0, + ULP_MODE_ISCSI = 2, + ULP_MODE_RDMA = 4, + ULP_MODE_TCPDDP = 5, + ULP_MODE_FCOE = 6, +}; + +enum { + ULP_CRC_HEADER = 1 << 0, + ULP_CRC_DATA = 1 << 1 +}; + +enum { + CPL_ABORT_SEND_RST = 0, + CPL_ABORT_NO_RST, +}; + +enum { /* TX_PKT_XT checksum types */ + TX_CSUM_TCP = 0, + TX_CSUM_UDP = 1, + TX_CSUM_CRC16 = 4, + TX_CSUM_CRC32 = 5, + TX_CSUM_CRC32C = 6, + TX_CSUM_FCOE = 7, + TX_CSUM_TCPIP = 8, + TX_CSUM_UDPIP = 9, + TX_CSUM_TCPIP6 = 10, + TX_CSUM_UDPIP6 = 11, + TX_CSUM_IP = 12, +}; + +union opcode_tid { + __be32 opcode_tid; + u8 opcode; +}; + +#define CPL_OPCODE(x) ((x) << 24) +#define MK_OPCODE_TID(opcode, tid) (CPL_OPCODE(opcode) | (tid)) +#define OPCODE_TID(cmd) ((cmd)->ot.opcode_tid) +#define GET_TID(cmd) (ntohl(OPCODE_TID(cmd)) & 0xFFFFFF) + +/* partitioning of TID fields that also carry a queue id */ +#define GET_TID_TID(x) ((x) & 0x3fff) +#define GET_TID_QID(x) (((x) >> 14) & 0x3ff) +#define TID_QID(x) ((x) << 14) + +struct rss_header { + u8 opcode; +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 channel:2; + u8 filter_hit:1; + u8 filter_tid:1; + u8 hash_type:2; + u8 ipv6:1; + u8 send2fw:1; +#else + u8 send2fw:1; + u8 ipv6:1; + u8 hash_type:2; + u8 filter_tid:1; + u8 filter_hit:1; + u8 channel:2; +#endif + __be16 qid; + __be32 hash_val; +}; + +struct work_request_hdr { + __be32 wr_hi; + __be32 wr_mid; + __be64 wr_lo; +}; + +#define WR_HDR struct work_request_hdr wr + +struct cpl_pass_open_req { + WR_HDR; + union opcode_tid ot; + __be16 local_port; + __be16 peer_port; + __be32 local_ip; + __be32 peer_ip; + __be64 opt0; +#define TX_CHAN(x) ((x) << 2) +#define DELACK(x) ((x) << 5) +#define ULP_MODE(x) ((x) << 8) +#define RCV_BUFSIZ(x) ((x) << 12) +#define DSCP(x) ((x) << 22) +#define SMAC_SEL(x) ((u64)(x) << 28) +#define L2T_IDX(x) ((u64)(x) << 36) +#define NAGLE(x) ((u64)(x) << 49) +#define WND_SCALE(x) ((u64)(x) << 50) +#define KEEP_ALIVE(x) ((u64)(x) << 54) +#define MSS_IDX(x) ((u64)(x) << 60) + __be64 opt1; +#define SYN_RSS_ENABLE (1 << 0) +#define SYN_RSS_QUEUE(x) ((x) << 2) +#define CONN_POLICY_ASK (1 << 22) +}; + +struct cpl_pass_open_req6 { + WR_HDR; + union opcode_tid ot; + __be16 local_port; + __be16 peer_port; + __be64 local_ip_hi; + __be64 local_ip_lo; + __be64 peer_ip_hi; + __be64 peer_ip_lo; + __be64 opt0; + __be64 opt1; +}; + +struct cpl_pass_open_rpl { + union opcode_tid ot; + u8 rsvd[3]; + u8 status; +}; + +struct cpl_pass_accept_rpl { + WR_HDR; + union opcode_tid ot; + __be32 opt2; +#define RSS_QUEUE(x) ((x) << 0) +#define RSS_QUEUE_VALID (1 << 10) +#define RX_COALESCE_VALID(x) ((x) << 11) +#define RX_COALESCE(x) ((x) << 12) +#define TX_QUEUE(x) ((x) << 23) +#define RX_CHANNEL(x) ((x) << 26) +#define WND_SCALE_EN(x) ((x) << 28) +#define TSTAMPS_EN(x) ((x) << 29) +#define SACK_EN(x) ((x) << 30) + __be64 opt0; +}; + +struct cpl_act_open_req { + WR_HDR; + union opcode_tid ot; + __be16 local_port; + __be16 peer_port; + __be32 local_ip; + __be32 peer_ip; + __be64 opt0; + __be32 params; + __be32 opt2; +}; + +struct cpl_act_open_req6 { + WR_HDR; + union opcode_tid ot; + __be16 local_port; + __be16 peer_port; + __be64 local_ip_hi; + __be64 local_ip_lo; + __be64 peer_ip_hi; + __be64 peer_ip_lo; + __be64 opt0; + __be32 params; + __be32 opt2; +}; + +struct cpl_act_open_rpl { + union opcode_tid ot; + __be32 atid_status; +#define GET_AOPEN_STATUS(x) ((x) & 0xff) +#define GET_AOPEN_ATID(x) (((x) >> 8) & 0xffffff) +}; + +struct cpl_pass_establish { + union opcode_tid ot; + __be32 rsvd; + __be32 tos_stid; +#define GET_POPEN_TID(x) ((x) & 0xffffff) +#define GET_POPEN_TOS(x) (((x) >> 24) & 0xff) + __be16 mac_idx; + __be16 tcp_opt; +#define GET_TCPOPT_WSCALE_OK(x) (((x) >> 5) & 1) +#define GET_TCPOPT_SACK(x) (((x) >> 6) & 1) +#define GET_TCPOPT_TSTAMP(x) (((x) >> 7) & 1) +#define GET_TCPOPT_SND_WSCALE(x) (((x) >> 8) & 0xf) +#define GET_TCPOPT_MSS(x) (((x) >> 12) & 0xf) + __be32 snd_isn; + __be32 rcv_isn; +}; + +struct cpl_act_establish { + union opcode_tid ot; + __be32 rsvd; + __be32 tos_atid; + __be16 mac_idx; + __be16 tcp_opt; + __be32 snd_isn; + __be32 rcv_isn; +}; + +struct cpl_get_tcb { + WR_HDR; + union opcode_tid ot; + __be16 reply_ctrl; +#define QUEUENO(x) ((x) << 0) +#define REPLY_CHAN(x) ((x) << 14) +#define NO_REPLY(x) ((x) << 15) + __be16 cookie; +}; + +struct cpl_set_tcb_field { + WR_HDR; + union opcode_tid ot; + __be16 reply_ctrl; + __be16 word_cookie; +#define TCB_WORD(x) ((x) << 0) +#define TCB_COOKIE(x) ((x) << 5) + __be64 mask; + __be64 val; +}; + +struct cpl_set_tcb_rpl { + union opcode_tid ot; + __be16 rsvd; + u8 cookie; + u8 status; + __be64 oldval; +}; + +struct cpl_close_con_req { + WR_HDR; + union opcode_tid ot; + __be32 rsvd; +}; + +struct cpl_close_con_rpl { + union opcode_tid ot; + u8 rsvd[3]; + u8 status; + __be32 snd_nxt; + __be32 rcv_nxt; +}; + +struct cpl_close_listsvr_req { + WR_HDR; + union opcode_tid ot; + __be16 reply_ctrl; +#define LISTSVR_IPV6 (1 << 14) + __be16 rsvd; +}; + +struct cpl_close_listsvr_rpl { + union opcode_tid ot; + u8 rsvd[3]; + u8 status; +}; + +struct cpl_abort_req_rss { + union opcode_tid ot; + u8 rsvd[3]; + u8 status; +}; + +struct cpl_abort_req { + WR_HDR; + union opcode_tid ot; + __be32 rsvd0; + u8 rsvd1; + u8 cmd; + u8 rsvd2[6]; +}; + +struct cpl_abort_rpl_rss { + union opcode_tid ot; + u8 rsvd[3]; + u8 status; +}; + +struct cpl_abort_rpl { + WR_HDR; + union opcode_tid ot; + __be32 rsvd0; + u8 rsvd1; + u8 cmd; + u8 rsvd2[6]; +}; + +struct cpl_peer_close { + union opcode_tid ot; + __be32 rcv_nxt; +}; + +struct cpl_tid_release { + WR_HDR; + union opcode_tid ot; + __be32 rsvd; +}; + +struct cpl_tx_pkt_core { + __be32 ctrl0; +#define TXPKT_VF(x) ((x) << 0) +#define TXPKT_PF(x) ((x) << 8) +#define TXPKT_VF_VLD (1 << 11) +#define TXPKT_OVLAN_IDX(x) ((x) << 12) +#define TXPKT_INTF(x) ((x) << 16) +#define TXPKT_INS_OVLAN (1 << 21) +#define TXPKT_OPCODE(x) ((x) << 24) + __be16 pack; + __be16 len; + __be64 ctrl1; +#define TXPKT_CSUM_END(x) ((x) << 12) +#define TXPKT_CSUM_START(x) ((x) << 20) +#define TXPKT_IPHDR_LEN(x) ((u64)(x) << 20) +#define TXPKT_CSUM_LOC(x) ((u64)(x) << 30) +#define TXPKT_ETHHDR_LEN(x) ((u64)(x) << 34) +#define TXPKT_CSUM_TYPE(x) ((u64)(x) << 40) +#define TXPKT_VLAN(x) ((u64)(x) << 44) +#define TXPKT_VLAN_VLD (1ULL << 60) +#define TXPKT_IPCSUM_DIS (1ULL << 62) +#define TXPKT_L4CSUM_DIS (1ULL << 63) +}; + +struct cpl_tx_pkt { + WR_HDR; + struct cpl_tx_pkt_core c; +}; + +#define cpl_tx_pkt_xt cpl_tx_pkt + +struct cpl_tx_pkt_lso_core { + __be32 lso_ctrl; +#define LSO_TCPHDR_LEN(x) ((x) << 0) +#define LSO_IPHDR_LEN(x) ((x) << 4) +#define LSO_ETHHDR_LEN(x) ((x) << 16) +#define LSO_IPV6(x) ((x) << 20) +#define LSO_LAST_SLICE (1 << 22) +#define LSO_FIRST_SLICE (1 << 23) +#define LSO_OPCODE(x) ((x) << 24) + __be16 ipid_ofst; + __be16 mss; + __be32 seqno_offset; + __be32 len; + /* encapsulated CPL (TX_PKT, TX_PKT_XT or TX_DATA) follows here */ +}; + +struct cpl_tx_pkt_lso { + WR_HDR; + struct cpl_tx_pkt_lso_core c; + /* encapsulated CPL (TX_PKT, TX_PKT_XT or TX_DATA) follows here */ +}; + +struct cpl_iscsi_hdr { + union opcode_tid ot; + __be16 pdu_len_ddp; +#define ISCSI_PDU_LEN(x) ((x) & 0x7FFF) +#define ISCSI_DDP (1 << 15) + __be16 len; + __be32 seq; + __be16 urg; + u8 rsvd; + u8 status; +}; + +struct cpl_rx_data { + union opcode_tid ot; + __be16 rsvd; + __be16 len; + __be32 seq; + __be16 urg; +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 dack_mode:2; + u8 psh:1; + u8 heartbeat:1; + u8 ddp_off:1; + u8 :3; +#else + u8 :3; + u8 ddp_off:1; + u8 heartbeat:1; + u8 psh:1; + u8 dack_mode:2; +#endif + u8 status; +}; + +struct cpl_rx_data_ack { + WR_HDR; + union opcode_tid ot; + __be32 credit_dack; +#define RX_CREDITS(x) ((x) << 0) +#define RX_FORCE_ACK(x) ((x) << 28) +}; + +struct cpl_rx_pkt { + struct rss_header rsshdr; + u8 opcode; +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 iff:4; + u8 csum_calc:1; + u8 ipmi_pkt:1; + u8 vlan_ex:1; + u8 ip_frag:1; +#else + u8 ip_frag:1; + u8 vlan_ex:1; + u8 ipmi_pkt:1; + u8 csum_calc:1; + u8 iff:4; +#endif + __be16 csum; + __be16 vlan; + __be16 len; + __be32 l2info; +#define RXF_UDP (1 << 22) +#define RXF_TCP (1 << 23) +#define RXF_IP (1 << 24) +#define RXF_IP6 (1 << 25) + __be16 hdr_len; + __be16 err_vec; +}; + +struct cpl_trace_pkt { + u8 opcode; + u8 intf; +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 runt:4; + u8 filter_hit:4; + u8 :6; + u8 err:1; + u8 trunc:1; +#else + u8 filter_hit:4; + u8 runt:4; + u8 trunc:1; + u8 err:1; + u8 :6; +#endif + __be16 rsvd; + __be16 len; + __be64 tstamp; +}; + +struct cpl_l2t_write_req { + WR_HDR; + union opcode_tid ot; + __be16 params; +#define L2T_W_INFO(x) ((x) << 2) +#define L2T_W_PORT(x) ((x) << 8) +#define L2T_W_NOREPLY(x) ((x) << 15) + __be16 l2t_idx; + __be16 vlan; + u8 dst_mac[6]; +}; + +struct cpl_l2t_write_rpl { + union opcode_tid ot; + u8 status; + u8 rsvd[3]; +}; + +struct cpl_rdma_terminate { + union opcode_tid ot; + __be16 rsvd; + __be16 len; +}; + +struct cpl_sge_egr_update { + __be32 opcode_qid; +#define EGR_QID(x) ((x) & 0x1FFFF) + __be16 cidx; + __be16 pidx; +}; + +struct cpl_fw4_pld { + u8 opcode; + u8 rsvd0[3]; + u8 type; + u8 rsvd1; + __be16 len; + __be64 data; + __be64 rsvd2; +}; + +struct cpl_fw6_pld { + u8 opcode; + u8 rsvd[5]; + __be16 len; + __be64 data[4]; +}; + +struct cpl_fw4_msg { + u8 opcode; + u8 type; + __be16 rsvd0; + __be32 rsvd1; + __be64 data[2]; +}; + +struct cpl_fw4_ack { + union opcode_tid ot; + u8 credits; + u8 rsvd0[2]; + u8 seq_vld; + __be32 snd_nxt; + __be32 snd_una; + __be64 rsvd1; +}; + +struct cpl_fw6_msg { + u8 opcode; + u8 type; + __be16 rsvd0; + __be32 rsvd1; + __be64 data[4]; +}; + +/* cpl_fw6_msg.type values */ +enum { + FW6_TYPE_CMD_RPL = 0, +}; + +enum { + ULP_TX_MEM_READ = 2, + ULP_TX_MEM_WRITE = 3, + ULP_TX_PKT = 4 +}; + +enum { + ULP_TX_SC_NOOP = 0x80, + ULP_TX_SC_IMM = 0x81, + ULP_TX_SC_DSGL = 0x82, + ULP_TX_SC_ISGL = 0x83 +}; + +struct ulptx_sge_pair { + __be32 len[2]; + __be64 addr[2]; +}; + +struct ulptx_sgl { + __be32 cmd_nsge; +#define ULPTX_CMD(x) ((x) << 24) +#define ULPTX_NSGE(x) ((x) << 0) + __be32 len0; + __be64 addr0; + struct ulptx_sge_pair sge[0]; +}; + +struct ulp_mem_io { + WR_HDR; + __be32 cmd; +#define ULP_MEMIO_ORDER(x) ((x) << 23) + __be32 len16; /* command length */ + __be32 dlen; /* data length in 32-byte units */ +#define ULP_MEMIO_DATA_LEN(x) ((x) << 0) + __be32 lock_addr; +#define ULP_MEMIO_ADDR(x) ((x) << 0) +#define ULP_MEMIO_LOCK(x) ((x) << 31) +}; + +#endif /* __T4_MSG_H */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h new file mode 100644 index 000000000000..0adc5bcec7c4 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -0,0 +1,885 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __T4_REGS_H +#define __T4_REGS_H + +#define MYPF_BASE 0x1b000 +#define MYPF_REG(reg_addr) (MYPF_BASE + (reg_addr)) + +#define PF0_BASE 0x1e000 +#define PF0_REG(reg_addr) (PF0_BASE + (reg_addr)) + +#define PF_STRIDE 0x400 +#define PF_BASE(idx) (PF0_BASE + (idx) * PF_STRIDE) +#define PF_REG(idx, reg) (PF_BASE(idx) + (reg)) + +#define MYPORT_BASE 0x1c000 +#define MYPORT_REG(reg_addr) (MYPORT_BASE + (reg_addr)) + +#define PORT0_BASE 0x20000 +#define PORT0_REG(reg_addr) (PORT0_BASE + (reg_addr)) + +#define PORT_STRIDE 0x2000 +#define PORT_BASE(idx) (PORT0_BASE + (idx) * PORT_STRIDE) +#define PORT_REG(idx, reg) (PORT_BASE(idx) + (reg)) + +#define EDC_STRIDE (EDC_1_BASE_ADDR - EDC_0_BASE_ADDR) +#define EDC_REG(reg, idx) (reg + EDC_STRIDE * idx) + +#define PCIE_MEM_ACCESS_REG(reg_addr, idx) ((reg_addr) + (idx) * 8) +#define PCIE_MAILBOX_REG(reg_addr, idx) ((reg_addr) + (idx) * 8) +#define MC_BIST_STATUS_REG(reg_addr, idx) ((reg_addr) + (idx) * 4) +#define EDC_BIST_STATUS_REG(reg_addr, idx) ((reg_addr) + (idx) * 4) + +#define SGE_PF_KDOORBELL 0x0 +#define QID_MASK 0xffff8000U +#define QID_SHIFT 15 +#define QID(x) ((x) << QID_SHIFT) +#define DBPRIO 0x00004000U +#define PIDX_MASK 0x00003fffU +#define PIDX_SHIFT 0 +#define PIDX(x) ((x) << PIDX_SHIFT) + +#define SGE_PF_GTS 0x4 +#define INGRESSQID_MASK 0xffff0000U +#define INGRESSQID_SHIFT 16 +#define INGRESSQID(x) ((x) << INGRESSQID_SHIFT) +#define TIMERREG_MASK 0x0000e000U +#define TIMERREG_SHIFT 13 +#define TIMERREG(x) ((x) << TIMERREG_SHIFT) +#define SEINTARM_MASK 0x00001000U +#define SEINTARM_SHIFT 12 +#define SEINTARM(x) ((x) << SEINTARM_SHIFT) +#define CIDXINC_MASK 0x00000fffU +#define CIDXINC_SHIFT 0 +#define CIDXINC(x) ((x) << CIDXINC_SHIFT) + +#define SGE_CONTROL 0x1008 +#define DCASYSTYPE 0x00080000U +#define RXPKTCPLMODE 0x00040000U +#define EGRSTATUSPAGESIZE 0x00020000U +#define PKTSHIFT_MASK 0x00001c00U +#define PKTSHIFT_SHIFT 10 +#define PKTSHIFT(x) ((x) << PKTSHIFT_SHIFT) +#define PKTSHIFT_GET(x) (((x) & PKTSHIFT_MASK) >> PKTSHIFT_SHIFT) +#define INGPCIEBOUNDARY_MASK 0x00000380U +#define INGPCIEBOUNDARY_SHIFT 7 +#define INGPCIEBOUNDARY(x) ((x) << INGPCIEBOUNDARY_SHIFT) +#define INGPADBOUNDARY_MASK 0x00000070U +#define INGPADBOUNDARY_SHIFT 4 +#define INGPADBOUNDARY(x) ((x) << INGPADBOUNDARY_SHIFT) +#define INGPADBOUNDARY_GET(x) (((x) & INGPADBOUNDARY_MASK) \ + >> INGPADBOUNDARY_SHIFT) +#define EGRPCIEBOUNDARY_MASK 0x0000000eU +#define EGRPCIEBOUNDARY_SHIFT 1 +#define EGRPCIEBOUNDARY(x) ((x) << EGRPCIEBOUNDARY_SHIFT) +#define GLOBALENABLE 0x00000001U + +#define SGE_HOST_PAGE_SIZE 0x100c +#define HOSTPAGESIZEPF0_MASK 0x0000000fU +#define HOSTPAGESIZEPF0_SHIFT 0 +#define HOSTPAGESIZEPF0(x) ((x) << HOSTPAGESIZEPF0_SHIFT) + +#define SGE_EGRESS_QUEUES_PER_PAGE_PF 0x1010 +#define QUEUESPERPAGEPF0_MASK 0x0000000fU +#define QUEUESPERPAGEPF0_GET(x) ((x) & QUEUESPERPAGEPF0_MASK) + +#define SGE_INT_CAUSE1 0x1024 +#define SGE_INT_CAUSE2 0x1030 +#define SGE_INT_CAUSE3 0x103c +#define ERR_FLM_DBP 0x80000000U +#define ERR_FLM_IDMA1 0x40000000U +#define ERR_FLM_IDMA0 0x20000000U +#define ERR_FLM_HINT 0x10000000U +#define ERR_PCIE_ERROR3 0x08000000U +#define ERR_PCIE_ERROR2 0x04000000U +#define ERR_PCIE_ERROR1 0x02000000U +#define ERR_PCIE_ERROR0 0x01000000U +#define ERR_TIMER_ABOVE_MAX_QID 0x00800000U +#define ERR_CPL_EXCEED_IQE_SIZE 0x00400000U +#define ERR_INVALID_CIDX_INC 0x00200000U +#define ERR_ITP_TIME_PAUSED 0x00100000U +#define ERR_CPL_OPCODE_0 0x00080000U +#define ERR_DROPPED_DB 0x00040000U +#define ERR_DATA_CPL_ON_HIGH_QID1 0x00020000U +#define ERR_DATA_CPL_ON_HIGH_QID0 0x00010000U +#define ERR_BAD_DB_PIDX3 0x00008000U +#define ERR_BAD_DB_PIDX2 0x00004000U +#define ERR_BAD_DB_PIDX1 0x00002000U +#define ERR_BAD_DB_PIDX0 0x00001000U +#define ERR_ING_PCIE_CHAN 0x00000800U +#define ERR_ING_CTXT_PRIO 0x00000400U +#define ERR_EGR_CTXT_PRIO 0x00000200U +#define DBFIFO_HP_INT 0x00000100U +#define DBFIFO_LP_INT 0x00000080U +#define REG_ADDRESS_ERR 0x00000040U +#define INGRESS_SIZE_ERR 0x00000020U +#define EGRESS_SIZE_ERR 0x00000010U +#define ERR_INV_CTXT3 0x00000008U +#define ERR_INV_CTXT2 0x00000004U +#define ERR_INV_CTXT1 0x00000002U +#define ERR_INV_CTXT0 0x00000001U + +#define SGE_INT_ENABLE3 0x1040 +#define SGE_FL_BUFFER_SIZE0 0x1044 +#define SGE_FL_BUFFER_SIZE1 0x1048 +#define SGE_INGRESS_RX_THRESHOLD 0x10a0 +#define THRESHOLD_0_MASK 0x3f000000U +#define THRESHOLD_0_SHIFT 24 +#define THRESHOLD_0(x) ((x) << THRESHOLD_0_SHIFT) +#define THRESHOLD_0_GET(x) (((x) & THRESHOLD_0_MASK) >> THRESHOLD_0_SHIFT) +#define THRESHOLD_1_MASK 0x003f0000U +#define THRESHOLD_1_SHIFT 16 +#define THRESHOLD_1(x) ((x) << THRESHOLD_1_SHIFT) +#define THRESHOLD_1_GET(x) (((x) & THRESHOLD_1_MASK) >> THRESHOLD_1_SHIFT) +#define THRESHOLD_2_MASK 0x00003f00U +#define THRESHOLD_2_SHIFT 8 +#define THRESHOLD_2(x) ((x) << THRESHOLD_2_SHIFT) +#define THRESHOLD_2_GET(x) (((x) & THRESHOLD_2_MASK) >> THRESHOLD_2_SHIFT) +#define THRESHOLD_3_MASK 0x0000003fU +#define THRESHOLD_3_SHIFT 0 +#define THRESHOLD_3(x) ((x) << THRESHOLD_3_SHIFT) +#define THRESHOLD_3_GET(x) (((x) & THRESHOLD_3_MASK) >> THRESHOLD_3_SHIFT) + +#define SGE_TIMER_VALUE_0_AND_1 0x10b8 +#define TIMERVALUE0_MASK 0xffff0000U +#define TIMERVALUE0_SHIFT 16 +#define TIMERVALUE0(x) ((x) << TIMERVALUE0_SHIFT) +#define TIMERVALUE0_GET(x) (((x) & TIMERVALUE0_MASK) >> TIMERVALUE0_SHIFT) +#define TIMERVALUE1_MASK 0x0000ffffU +#define TIMERVALUE1_SHIFT 0 +#define TIMERVALUE1(x) ((x) << TIMERVALUE1_SHIFT) +#define TIMERVALUE1_GET(x) (((x) & TIMERVALUE1_MASK) >> TIMERVALUE1_SHIFT) + +#define SGE_TIMER_VALUE_2_AND_3 0x10bc +#define SGE_TIMER_VALUE_4_AND_5 0x10c0 +#define SGE_DEBUG_INDEX 0x10cc +#define SGE_DEBUG_DATA_HIGH 0x10d0 +#define SGE_DEBUG_DATA_LOW 0x10d4 +#define SGE_INGRESS_QUEUES_PER_PAGE_PF 0x10f4 + +#define PCIE_PF_CLI 0x44 +#define PCIE_INT_CAUSE 0x3004 +#define UNXSPLCPLERR 0x20000000U +#define PCIEPINT 0x10000000U +#define PCIESINT 0x08000000U +#define RPLPERR 0x04000000U +#define RXWRPERR 0x02000000U +#define RXCPLPERR 0x01000000U +#define PIOTAGPERR 0x00800000U +#define MATAGPERR 0x00400000U +#define INTXCLRPERR 0x00200000U +#define FIDPERR 0x00100000U +#define CFGSNPPERR 0x00080000U +#define HRSPPERR 0x00040000U +#define HREQPERR 0x00020000U +#define HCNTPERR 0x00010000U +#define DRSPPERR 0x00008000U +#define DREQPERR 0x00004000U +#define DCNTPERR 0x00002000U +#define CRSPPERR 0x00001000U +#define CREQPERR 0x00000800U +#define CCNTPERR 0x00000400U +#define TARTAGPERR 0x00000200U +#define PIOREQPERR 0x00000100U +#define PIOCPLPERR 0x00000080U +#define MSIXDIPERR 0x00000040U +#define MSIXDATAPERR 0x00000020U +#define MSIXADDRHPERR 0x00000010U +#define MSIXADDRLPERR 0x00000008U +#define MSIDATAPERR 0x00000004U +#define MSIADDRHPERR 0x00000002U +#define MSIADDRLPERR 0x00000001U + +#define PCIE_NONFAT_ERR 0x3010 +#define PCIE_MEM_ACCESS_BASE_WIN 0x3068 +#define PCIEOFST_MASK 0xfffffc00U +#define BIR_MASK 0x00000300U +#define BIR_SHIFT 8 +#define BIR(x) ((x) << BIR_SHIFT) +#define WINDOW_MASK 0x000000ffU +#define WINDOW_SHIFT 0 +#define WINDOW(x) ((x) << WINDOW_SHIFT) +#define PCIE_MEM_ACCESS_OFFSET 0x306c + +#define PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS 0x5908 +#define RNPP 0x80000000U +#define RPCP 0x20000000U +#define RCIP 0x08000000U +#define RCCP 0x04000000U +#define RFTP 0x00800000U +#define PTRP 0x00100000U + +#define PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS 0x59a4 +#define TPCP 0x40000000U +#define TNPP 0x20000000U +#define TFTP 0x10000000U +#define TCAP 0x08000000U +#define TCIP 0x04000000U +#define RCAP 0x02000000U +#define PLUP 0x00800000U +#define PLDN 0x00400000U +#define OTDD 0x00200000U +#define GTRP 0x00100000U +#define RDPE 0x00040000U +#define TDCE 0x00020000U +#define TDUE 0x00010000U + +#define MC_INT_CAUSE 0x7518 +#define ECC_UE_INT_CAUSE 0x00000004U +#define ECC_CE_INT_CAUSE 0x00000002U +#define PERR_INT_CAUSE 0x00000001U + +#define MC_ECC_STATUS 0x751c +#define ECC_CECNT_MASK 0xffff0000U +#define ECC_CECNT_SHIFT 16 +#define ECC_CECNT(x) ((x) << ECC_CECNT_SHIFT) +#define ECC_CECNT_GET(x) (((x) & ECC_CECNT_MASK) >> ECC_CECNT_SHIFT) +#define ECC_UECNT_MASK 0x0000ffffU +#define ECC_UECNT_SHIFT 0 +#define ECC_UECNT(x) ((x) << ECC_UECNT_SHIFT) +#define ECC_UECNT_GET(x) (((x) & ECC_UECNT_MASK) >> ECC_UECNT_SHIFT) + +#define MC_BIST_CMD 0x7600 +#define START_BIST 0x80000000U +#define BIST_CMD_GAP_MASK 0x0000ff00U +#define BIST_CMD_GAP_SHIFT 8 +#define BIST_CMD_GAP(x) ((x) << BIST_CMD_GAP_SHIFT) +#define BIST_OPCODE_MASK 0x00000003U +#define BIST_OPCODE_SHIFT 0 +#define BIST_OPCODE(x) ((x) << BIST_OPCODE_SHIFT) + +#define MC_BIST_CMD_ADDR 0x7604 +#define MC_BIST_CMD_LEN 0x7608 +#define MC_BIST_DATA_PATTERN 0x760c +#define BIST_DATA_TYPE_MASK 0x0000000fU +#define BIST_DATA_TYPE_SHIFT 0 +#define BIST_DATA_TYPE(x) ((x) << BIST_DATA_TYPE_SHIFT) + +#define MC_BIST_STATUS_RDATA 0x7688 + +#define MA_EXT_MEMORY_BAR 0x77c8 +#define EXT_MEM_SIZE_MASK 0x00000fffU +#define EXT_MEM_SIZE_SHIFT 0 +#define EXT_MEM_SIZE_GET(x) (((x) & EXT_MEM_SIZE_MASK) >> EXT_MEM_SIZE_SHIFT) + +#define MA_TARGET_MEM_ENABLE 0x77d8 +#define EXT_MEM_ENABLE 0x00000004U +#define EDRAM1_ENABLE 0x00000002U +#define EDRAM0_ENABLE 0x00000001U + +#define MA_INT_CAUSE 0x77e0 +#define MEM_PERR_INT_CAUSE 0x00000002U +#define MEM_WRAP_INT_CAUSE 0x00000001U + +#define MA_INT_WRAP_STATUS 0x77e4 +#define MEM_WRAP_ADDRESS_MASK 0xfffffff0U +#define MEM_WRAP_ADDRESS_SHIFT 4 +#define MEM_WRAP_ADDRESS_GET(x) (((x) & MEM_WRAP_ADDRESS_MASK) >> MEM_WRAP_ADDRESS_SHIFT) +#define MEM_WRAP_CLIENT_NUM_MASK 0x0000000fU +#define MEM_WRAP_CLIENT_NUM_SHIFT 0 +#define MEM_WRAP_CLIENT_NUM_GET(x) (((x) & MEM_WRAP_CLIENT_NUM_MASK) >> MEM_WRAP_CLIENT_NUM_SHIFT) + +#define MA_PARITY_ERROR_STATUS 0x77f4 + +#define EDC_0_BASE_ADDR 0x7900 + +#define EDC_BIST_CMD 0x7904 +#define EDC_BIST_CMD_ADDR 0x7908 +#define EDC_BIST_CMD_LEN 0x790c +#define EDC_BIST_DATA_PATTERN 0x7910 +#define EDC_BIST_STATUS_RDATA 0x7928 +#define EDC_INT_CAUSE 0x7978 +#define ECC_UE_PAR 0x00000020U +#define ECC_CE_PAR 0x00000010U +#define PERR_PAR_CAUSE 0x00000008U + +#define EDC_ECC_STATUS 0x797c + +#define EDC_1_BASE_ADDR 0x7980 + +#define CIM_BOOT_CFG 0x7b00 +#define BOOTADDR_MASK 0xffffff00U + +#define CIM_PF_MAILBOX_DATA 0x240 +#define CIM_PF_MAILBOX_CTRL 0x280 +#define MBMSGVALID 0x00000008U +#define MBINTREQ 0x00000004U +#define MBOWNER_MASK 0x00000003U +#define MBOWNER_SHIFT 0 +#define MBOWNER(x) ((x) << MBOWNER_SHIFT) +#define MBOWNER_GET(x) (((x) & MBOWNER_MASK) >> MBOWNER_SHIFT) + +#define CIM_PF_HOST_INT_CAUSE 0x28c +#define MBMSGRDYINT 0x00080000U + +#define CIM_HOST_INT_CAUSE 0x7b2c +#define TIEQOUTPARERRINT 0x00100000U +#define TIEQINPARERRINT 0x00080000U +#define MBHOSTPARERR 0x00040000U +#define MBUPPARERR 0x00020000U +#define IBQPARERR 0x0001f800U +#define IBQTP0PARERR 0x00010000U +#define IBQTP1PARERR 0x00008000U +#define IBQULPPARERR 0x00004000U +#define IBQSGELOPARERR 0x00002000U +#define IBQSGEHIPARERR 0x00001000U +#define IBQNCSIPARERR 0x00000800U +#define OBQPARERR 0x000007e0U +#define OBQULP0PARERR 0x00000400U +#define OBQULP1PARERR 0x00000200U +#define OBQULP2PARERR 0x00000100U +#define OBQULP3PARERR 0x00000080U +#define OBQSGEPARERR 0x00000040U +#define OBQNCSIPARERR 0x00000020U +#define PREFDROPINT 0x00000002U +#define UPACCNONZERO 0x00000001U + +#define CIM_HOST_UPACC_INT_CAUSE 0x7b34 +#define EEPROMWRINT 0x40000000U +#define TIMEOUTMAINT 0x20000000U +#define TIMEOUTINT 0x10000000U +#define RSPOVRLOOKUPINT 0x08000000U +#define REQOVRLOOKUPINT 0x04000000U +#define BLKWRPLINT 0x02000000U +#define BLKRDPLINT 0x01000000U +#define SGLWRPLINT 0x00800000U +#define SGLRDPLINT 0x00400000U +#define BLKWRCTLINT 0x00200000U +#define BLKRDCTLINT 0x00100000U +#define SGLWRCTLINT 0x00080000U +#define SGLRDCTLINT 0x00040000U +#define BLKWREEPROMINT 0x00020000U +#define BLKRDEEPROMINT 0x00010000U +#define SGLWREEPROMINT 0x00008000U +#define SGLRDEEPROMINT 0x00004000U +#define BLKWRFLASHINT 0x00002000U +#define BLKRDFLASHINT 0x00001000U +#define SGLWRFLASHINT 0x00000800U +#define SGLRDFLASHINT 0x00000400U +#define BLKWRBOOTINT 0x00000200U +#define BLKRDBOOTINT 0x00000100U +#define SGLWRBOOTINT 0x00000080U +#define SGLRDBOOTINT 0x00000040U +#define ILLWRBEINT 0x00000020U +#define ILLRDBEINT 0x00000010U +#define ILLRDINT 0x00000008U +#define ILLWRINT 0x00000004U +#define ILLTRANSINT 0x00000002U +#define RSVDSPACEINT 0x00000001U + +#define TP_OUT_CONFIG 0x7d04 +#define VLANEXTENABLE_MASK 0x0000f000U +#define VLANEXTENABLE_SHIFT 12 + +#define TP_PARA_REG2 0x7d68 +#define MAXRXDATA_MASK 0xffff0000U +#define MAXRXDATA_SHIFT 16 +#define MAXRXDATA_GET(x) (((x) & MAXRXDATA_MASK) >> MAXRXDATA_SHIFT) + +#define TP_TIMER_RESOLUTION 0x7d90 +#define TIMERRESOLUTION_MASK 0x00ff0000U +#define TIMERRESOLUTION_SHIFT 16 +#define TIMERRESOLUTION_GET(x) (((x) & TIMERRESOLUTION_MASK) >> TIMERRESOLUTION_SHIFT) + +#define TP_SHIFT_CNT 0x7dc0 + +#define TP_CCTRL_TABLE 0x7ddc +#define TP_MTU_TABLE 0x7de4 +#define MTUINDEX_MASK 0xff000000U +#define MTUINDEX_SHIFT 24 +#define MTUINDEX(x) ((x) << MTUINDEX_SHIFT) +#define MTUWIDTH_MASK 0x000f0000U +#define MTUWIDTH_SHIFT 16 +#define MTUWIDTH(x) ((x) << MTUWIDTH_SHIFT) +#define MTUWIDTH_GET(x) (((x) & MTUWIDTH_MASK) >> MTUWIDTH_SHIFT) +#define MTUVALUE_MASK 0x00003fffU +#define MTUVALUE_SHIFT 0 +#define MTUVALUE(x) ((x) << MTUVALUE_SHIFT) +#define MTUVALUE_GET(x) (((x) & MTUVALUE_MASK) >> MTUVALUE_SHIFT) + +#define TP_RSS_LKP_TABLE 0x7dec +#define LKPTBLROWVLD 0x80000000U +#define LKPTBLQUEUE1_MASK 0x000ffc00U +#define LKPTBLQUEUE1_SHIFT 10 +#define LKPTBLQUEUE1(x) ((x) << LKPTBLQUEUE1_SHIFT) +#define LKPTBLQUEUE1_GET(x) (((x) & LKPTBLQUEUE1_MASK) >> LKPTBLQUEUE1_SHIFT) +#define LKPTBLQUEUE0_MASK 0x000003ffU +#define LKPTBLQUEUE0_SHIFT 0 +#define LKPTBLQUEUE0(x) ((x) << LKPTBLQUEUE0_SHIFT) +#define LKPTBLQUEUE0_GET(x) (((x) & LKPTBLQUEUE0_MASK) >> LKPTBLQUEUE0_SHIFT) + +#define TP_PIO_ADDR 0x7e40 +#define TP_PIO_DATA 0x7e44 +#define TP_MIB_INDEX 0x7e50 +#define TP_MIB_DATA 0x7e54 +#define TP_INT_CAUSE 0x7e74 +#define FLMTXFLSTEMPTY 0x40000000U + +#define TP_INGRESS_CONFIG 0x141 +#define VNIC 0x00000800U +#define CSUM_HAS_PSEUDO_HDR 0x00000400U +#define RM_OVLAN 0x00000200U +#define LOOKUPEVERYPKT 0x00000100U + +#define TP_MIB_MAC_IN_ERR_0 0x0 +#define TP_MIB_TCP_OUT_RST 0xc +#define TP_MIB_TCP_IN_SEG_HI 0x10 +#define TP_MIB_TCP_IN_SEG_LO 0x11 +#define TP_MIB_TCP_OUT_SEG_HI 0x12 +#define TP_MIB_TCP_OUT_SEG_LO 0x13 +#define TP_MIB_TCP_RXT_SEG_HI 0x14 +#define TP_MIB_TCP_RXT_SEG_LO 0x15 +#define TP_MIB_TNL_CNG_DROP_0 0x18 +#define TP_MIB_TCP_V6IN_ERR_0 0x28 +#define TP_MIB_TCP_V6OUT_RST 0x2c +#define TP_MIB_OFD_ARP_DROP 0x36 +#define TP_MIB_TNL_DROP_0 0x44 +#define TP_MIB_OFD_VLN_DROP_0 0x58 + +#define ULP_TX_INT_CAUSE 0x8dcc +#define PBL_BOUND_ERR_CH3 0x80000000U +#define PBL_BOUND_ERR_CH2 0x40000000U +#define PBL_BOUND_ERR_CH1 0x20000000U +#define PBL_BOUND_ERR_CH0 0x10000000U + +#define PM_RX_INT_CAUSE 0x8fdc +#define ZERO_E_CMD_ERROR 0x00400000U +#define PMRX_FRAMING_ERROR 0x003ffff0U +#define OCSPI_PAR_ERROR 0x00000008U +#define DB_OPTIONS_PAR_ERROR 0x00000004U +#define IESPI_PAR_ERROR 0x00000002U +#define E_PCMD_PAR_ERROR 0x00000001U + +#define PM_TX_INT_CAUSE 0x8ffc +#define PCMD_LEN_OVFL0 0x80000000U +#define PCMD_LEN_OVFL1 0x40000000U +#define PCMD_LEN_OVFL2 0x20000000U +#define ZERO_C_CMD_ERROR 0x10000000U +#define PMTX_FRAMING_ERROR 0x0ffffff0U +#define OESPI_PAR_ERROR 0x00000008U +#define ICSPI_PAR_ERROR 0x00000002U +#define C_PCMD_PAR_ERROR 0x00000001U + +#define MPS_PORT_STAT_TX_PORT_BYTES_L 0x400 +#define MPS_PORT_STAT_TX_PORT_BYTES_H 0x404 +#define MPS_PORT_STAT_TX_PORT_FRAMES_L 0x408 +#define MPS_PORT_STAT_TX_PORT_FRAMES_H 0x40c +#define MPS_PORT_STAT_TX_PORT_BCAST_L 0x410 +#define MPS_PORT_STAT_TX_PORT_BCAST_H 0x414 +#define MPS_PORT_STAT_TX_PORT_MCAST_L 0x418 +#define MPS_PORT_STAT_TX_PORT_MCAST_H 0x41c +#define MPS_PORT_STAT_TX_PORT_UCAST_L 0x420 +#define MPS_PORT_STAT_TX_PORT_UCAST_H 0x424 +#define MPS_PORT_STAT_TX_PORT_ERROR_L 0x428 +#define MPS_PORT_STAT_TX_PORT_ERROR_H 0x42c +#define MPS_PORT_STAT_TX_PORT_64B_L 0x430 +#define MPS_PORT_STAT_TX_PORT_64B_H 0x434 +#define MPS_PORT_STAT_TX_PORT_65B_127B_L 0x438 +#define MPS_PORT_STAT_TX_PORT_65B_127B_H 0x43c +#define MPS_PORT_STAT_TX_PORT_128B_255B_L 0x440 +#define MPS_PORT_STAT_TX_PORT_128B_255B_H 0x444 +#define MPS_PORT_STAT_TX_PORT_256B_511B_L 0x448 +#define MPS_PORT_STAT_TX_PORT_256B_511B_H 0x44c +#define MPS_PORT_STAT_TX_PORT_512B_1023B_L 0x450 +#define MPS_PORT_STAT_TX_PORT_512B_1023B_H 0x454 +#define MPS_PORT_STAT_TX_PORT_1024B_1518B_L 0x458 +#define MPS_PORT_STAT_TX_PORT_1024B_1518B_H 0x45c +#define MPS_PORT_STAT_TX_PORT_1519B_MAX_L 0x460 +#define MPS_PORT_STAT_TX_PORT_1519B_MAX_H 0x464 +#define MPS_PORT_STAT_TX_PORT_DROP_L 0x468 +#define MPS_PORT_STAT_TX_PORT_DROP_H 0x46c +#define MPS_PORT_STAT_TX_PORT_PAUSE_L 0x470 +#define MPS_PORT_STAT_TX_PORT_PAUSE_H 0x474 +#define MPS_PORT_STAT_TX_PORT_PPP0_L 0x478 +#define MPS_PORT_STAT_TX_PORT_PPP0_H 0x47c +#define MPS_PORT_STAT_TX_PORT_PPP1_L 0x480 +#define MPS_PORT_STAT_TX_PORT_PPP1_H 0x484 +#define MPS_PORT_STAT_TX_PORT_PPP2_L 0x488 +#define MPS_PORT_STAT_TX_PORT_PPP2_H 0x48c +#define MPS_PORT_STAT_TX_PORT_PPP3_L 0x490 +#define MPS_PORT_STAT_TX_PORT_PPP3_H 0x494 +#define MPS_PORT_STAT_TX_PORT_PPP4_L 0x498 +#define MPS_PORT_STAT_TX_PORT_PPP4_H 0x49c +#define MPS_PORT_STAT_TX_PORT_PPP5_L 0x4a0 +#define MPS_PORT_STAT_TX_PORT_PPP5_H 0x4a4 +#define MPS_PORT_STAT_TX_PORT_PPP6_L 0x4a8 +#define MPS_PORT_STAT_TX_PORT_PPP6_H 0x4ac +#define MPS_PORT_STAT_TX_PORT_PPP7_L 0x4b0 +#define MPS_PORT_STAT_TX_PORT_PPP7_H 0x4b4 +#define MPS_PORT_STAT_LB_PORT_BYTES_L 0x4c0 +#define MPS_PORT_STAT_LB_PORT_BYTES_H 0x4c4 +#define MPS_PORT_STAT_LB_PORT_FRAMES_L 0x4c8 +#define MPS_PORT_STAT_LB_PORT_FRAMES_H 0x4cc +#define MPS_PORT_STAT_LB_PORT_BCAST_L 0x4d0 +#define MPS_PORT_STAT_LB_PORT_BCAST_H 0x4d4 +#define MPS_PORT_STAT_LB_PORT_MCAST_L 0x4d8 +#define MPS_PORT_STAT_LB_PORT_MCAST_H 0x4dc +#define MPS_PORT_STAT_LB_PORT_UCAST_L 0x4e0 +#define MPS_PORT_STAT_LB_PORT_UCAST_H 0x4e4 +#define MPS_PORT_STAT_LB_PORT_ERROR_L 0x4e8 +#define MPS_PORT_STAT_LB_PORT_ERROR_H 0x4ec +#define MPS_PORT_STAT_LB_PORT_64B_L 0x4f0 +#define MPS_PORT_STAT_LB_PORT_64B_H 0x4f4 +#define MPS_PORT_STAT_LB_PORT_65B_127B_L 0x4f8 +#define MPS_PORT_STAT_LB_PORT_65B_127B_H 0x4fc +#define MPS_PORT_STAT_LB_PORT_128B_255B_L 0x500 +#define MPS_PORT_STAT_LB_PORT_128B_255B_H 0x504 +#define MPS_PORT_STAT_LB_PORT_256B_511B_L 0x508 +#define MPS_PORT_STAT_LB_PORT_256B_511B_H 0x50c +#define MPS_PORT_STAT_LB_PORT_512B_1023B_L 0x510 +#define MPS_PORT_STAT_LB_PORT_512B_1023B_H 0x514 +#define MPS_PORT_STAT_LB_PORT_1024B_1518B_L 0x518 +#define MPS_PORT_STAT_LB_PORT_1024B_1518B_H 0x51c +#define MPS_PORT_STAT_LB_PORT_1519B_MAX_L 0x520 +#define MPS_PORT_STAT_LB_PORT_1519B_MAX_H 0x524 +#define MPS_PORT_STAT_LB_PORT_DROP_FRAMES 0x528 +#define MPS_PORT_STAT_RX_PORT_BYTES_L 0x540 +#define MPS_PORT_STAT_RX_PORT_BYTES_H 0x544 +#define MPS_PORT_STAT_RX_PORT_FRAMES_L 0x548 +#define MPS_PORT_STAT_RX_PORT_FRAMES_H 0x54c +#define MPS_PORT_STAT_RX_PORT_BCAST_L 0x550 +#define MPS_PORT_STAT_RX_PORT_BCAST_H 0x554 +#define MPS_PORT_STAT_RX_PORT_MCAST_L 0x558 +#define MPS_PORT_STAT_RX_PORT_MCAST_H 0x55c +#define MPS_PORT_STAT_RX_PORT_UCAST_L 0x560 +#define MPS_PORT_STAT_RX_PORT_UCAST_H 0x564 +#define MPS_PORT_STAT_RX_PORT_MTU_ERROR_L 0x568 +#define MPS_PORT_STAT_RX_PORT_MTU_ERROR_H 0x56c +#define MPS_PORT_STAT_RX_PORT_MTU_CRC_ERROR_L 0x570 +#define MPS_PORT_STAT_RX_PORT_MTU_CRC_ERROR_H 0x574 +#define MPS_PORT_STAT_RX_PORT_CRC_ERROR_L 0x578 +#define MPS_PORT_STAT_RX_PORT_CRC_ERROR_H 0x57c +#define MPS_PORT_STAT_RX_PORT_LEN_ERROR_L 0x580 +#define MPS_PORT_STAT_RX_PORT_LEN_ERROR_H 0x584 +#define MPS_PORT_STAT_RX_PORT_SYM_ERROR_L 0x588 +#define MPS_PORT_STAT_RX_PORT_SYM_ERROR_H 0x58c +#define MPS_PORT_STAT_RX_PORT_64B_L 0x590 +#define MPS_PORT_STAT_RX_PORT_64B_H 0x594 +#define MPS_PORT_STAT_RX_PORT_65B_127B_L 0x598 +#define MPS_PORT_STAT_RX_PORT_65B_127B_H 0x59c +#define MPS_PORT_STAT_RX_PORT_128B_255B_L 0x5a0 +#define MPS_PORT_STAT_RX_PORT_128B_255B_H 0x5a4 +#define MPS_PORT_STAT_RX_PORT_256B_511B_L 0x5a8 +#define MPS_PORT_STAT_RX_PORT_256B_511B_H 0x5ac +#define MPS_PORT_STAT_RX_PORT_512B_1023B_L 0x5b0 +#define MPS_PORT_STAT_RX_PORT_512B_1023B_H 0x5b4 +#define MPS_PORT_STAT_RX_PORT_1024B_1518B_L 0x5b8 +#define MPS_PORT_STAT_RX_PORT_1024B_1518B_H 0x5bc +#define MPS_PORT_STAT_RX_PORT_1519B_MAX_L 0x5c0 +#define MPS_PORT_STAT_RX_PORT_1519B_MAX_H 0x5c4 +#define MPS_PORT_STAT_RX_PORT_PAUSE_L 0x5c8 +#define MPS_PORT_STAT_RX_PORT_PAUSE_H 0x5cc +#define MPS_PORT_STAT_RX_PORT_PPP0_L 0x5d0 +#define MPS_PORT_STAT_RX_PORT_PPP0_H 0x5d4 +#define MPS_PORT_STAT_RX_PORT_PPP1_L 0x5d8 +#define MPS_PORT_STAT_RX_PORT_PPP1_H 0x5dc +#define MPS_PORT_STAT_RX_PORT_PPP2_L 0x5e0 +#define MPS_PORT_STAT_RX_PORT_PPP2_H 0x5e4 +#define MPS_PORT_STAT_RX_PORT_PPP3_L 0x5e8 +#define MPS_PORT_STAT_RX_PORT_PPP3_H 0x5ec +#define MPS_PORT_STAT_RX_PORT_PPP4_L 0x5f0 +#define MPS_PORT_STAT_RX_PORT_PPP4_H 0x5f4 +#define MPS_PORT_STAT_RX_PORT_PPP5_L 0x5f8 +#define MPS_PORT_STAT_RX_PORT_PPP5_H 0x5fc +#define MPS_PORT_STAT_RX_PORT_PPP6_L 0x600 +#define MPS_PORT_STAT_RX_PORT_PPP6_H 0x604 +#define MPS_PORT_STAT_RX_PORT_PPP7_L 0x608 +#define MPS_PORT_STAT_RX_PORT_PPP7_H 0x60c +#define MPS_PORT_STAT_RX_PORT_LESS_64B_L 0x610 +#define MPS_PORT_STAT_RX_PORT_LESS_64B_H 0x614 +#define MPS_CMN_CTL 0x9000 +#define NUMPORTS_MASK 0x00000003U +#define NUMPORTS_SHIFT 0 +#define NUMPORTS_GET(x) (((x) & NUMPORTS_MASK) >> NUMPORTS_SHIFT) + +#define MPS_INT_CAUSE 0x9008 +#define STATINT 0x00000020U +#define TXINT 0x00000010U +#define RXINT 0x00000008U +#define TRCINT 0x00000004U +#define CLSINT 0x00000002U +#define PLINT 0x00000001U + +#define MPS_TX_INT_CAUSE 0x9408 +#define PORTERR 0x00010000U +#define FRMERR 0x00008000U +#define SECNTERR 0x00004000U +#define BUBBLE 0x00002000U +#define TXDESCFIFO 0x00001e00U +#define TXDATAFIFO 0x000001e0U +#define NCSIFIFO 0x00000010U +#define TPFIFO 0x0000000fU + +#define MPS_STAT_PERR_INT_CAUSE_SRAM 0x9614 +#define MPS_STAT_PERR_INT_CAUSE_TX_FIFO 0x9620 +#define MPS_STAT_PERR_INT_CAUSE_RX_FIFO 0x962c + +#define MPS_STAT_RX_BG_0_MAC_DROP_FRAME_L 0x9640 +#define MPS_STAT_RX_BG_0_MAC_DROP_FRAME_H 0x9644 +#define MPS_STAT_RX_BG_1_MAC_DROP_FRAME_L 0x9648 +#define MPS_STAT_RX_BG_1_MAC_DROP_FRAME_H 0x964c +#define MPS_STAT_RX_BG_2_MAC_DROP_FRAME_L 0x9650 +#define MPS_STAT_RX_BG_2_MAC_DROP_FRAME_H 0x9654 +#define MPS_STAT_RX_BG_3_MAC_DROP_FRAME_L 0x9658 +#define MPS_STAT_RX_BG_3_MAC_DROP_FRAME_H 0x965c +#define MPS_STAT_RX_BG_0_LB_DROP_FRAME_L 0x9660 +#define MPS_STAT_RX_BG_0_LB_DROP_FRAME_H 0x9664 +#define MPS_STAT_RX_BG_1_LB_DROP_FRAME_L 0x9668 +#define MPS_STAT_RX_BG_1_LB_DROP_FRAME_H 0x966c +#define MPS_STAT_RX_BG_2_LB_DROP_FRAME_L 0x9670 +#define MPS_STAT_RX_BG_2_LB_DROP_FRAME_H 0x9674 +#define MPS_STAT_RX_BG_3_LB_DROP_FRAME_L 0x9678 +#define MPS_STAT_RX_BG_3_LB_DROP_FRAME_H 0x967c +#define MPS_STAT_RX_BG_0_MAC_TRUNC_FRAME_L 0x9680 +#define MPS_STAT_RX_BG_0_MAC_TRUNC_FRAME_H 0x9684 +#define MPS_STAT_RX_BG_1_MAC_TRUNC_FRAME_L 0x9688 +#define MPS_STAT_RX_BG_1_MAC_TRUNC_FRAME_H 0x968c +#define MPS_STAT_RX_BG_2_MAC_TRUNC_FRAME_L 0x9690 +#define MPS_STAT_RX_BG_2_MAC_TRUNC_FRAME_H 0x9694 +#define MPS_STAT_RX_BG_3_MAC_TRUNC_FRAME_L 0x9698 +#define MPS_STAT_RX_BG_3_MAC_TRUNC_FRAME_H 0x969c +#define MPS_STAT_RX_BG_0_LB_TRUNC_FRAME_L 0x96a0 +#define MPS_STAT_RX_BG_0_LB_TRUNC_FRAME_H 0x96a4 +#define MPS_STAT_RX_BG_1_LB_TRUNC_FRAME_L 0x96a8 +#define MPS_STAT_RX_BG_1_LB_TRUNC_FRAME_H 0x96ac +#define MPS_STAT_RX_BG_2_LB_TRUNC_FRAME_L 0x96b0 +#define MPS_STAT_RX_BG_2_LB_TRUNC_FRAME_H 0x96b4 +#define MPS_STAT_RX_BG_3_LB_TRUNC_FRAME_L 0x96b8 +#define MPS_STAT_RX_BG_3_LB_TRUNC_FRAME_H 0x96bc +#define MPS_TRC_CFG 0x9800 +#define TRCFIFOEMPTY 0x00000010U +#define TRCIGNOREDROPINPUT 0x00000008U +#define TRCKEEPDUPLICATES 0x00000004U +#define TRCEN 0x00000002U +#define TRCMULTIFILTER 0x00000001U + +#define MPS_TRC_RSS_CONTROL 0x9808 +#define RSSCONTROL_MASK 0x00ff0000U +#define RSSCONTROL_SHIFT 16 +#define RSSCONTROL(x) ((x) << RSSCONTROL_SHIFT) +#define QUEUENUMBER_MASK 0x0000ffffU +#define QUEUENUMBER_SHIFT 0 +#define QUEUENUMBER(x) ((x) << QUEUENUMBER_SHIFT) + +#define MPS_TRC_FILTER_MATCH_CTL_A 0x9810 +#define TFINVERTMATCH 0x01000000U +#define TFPKTTOOLARGE 0x00800000U +#define TFEN 0x00400000U +#define TFPORT_MASK 0x003c0000U +#define TFPORT_SHIFT 18 +#define TFPORT(x) ((x) << TFPORT_SHIFT) +#define TFPORT_GET(x) (((x) & TFPORT_MASK) >> TFPORT_SHIFT) +#define TFDROP 0x00020000U +#define TFSOPEOPERR 0x00010000U +#define TFLENGTH_MASK 0x00001f00U +#define TFLENGTH_SHIFT 8 +#define TFLENGTH(x) ((x) << TFLENGTH_SHIFT) +#define TFLENGTH_GET(x) (((x) & TFLENGTH_MASK) >> TFLENGTH_SHIFT) +#define TFOFFSET_MASK 0x0000001fU +#define TFOFFSET_SHIFT 0 +#define TFOFFSET(x) ((x) << TFOFFSET_SHIFT) +#define TFOFFSET_GET(x) (((x) & TFOFFSET_MASK) >> TFOFFSET_SHIFT) + +#define MPS_TRC_FILTER_MATCH_CTL_B 0x9820 +#define TFMINPKTSIZE_MASK 0x01ff0000U +#define TFMINPKTSIZE_SHIFT 16 +#define TFMINPKTSIZE(x) ((x) << TFMINPKTSIZE_SHIFT) +#define TFMINPKTSIZE_GET(x) (((x) & TFMINPKTSIZE_MASK) >> TFMINPKTSIZE_SHIFT) +#define TFCAPTUREMAX_MASK 0x00003fffU +#define TFCAPTUREMAX_SHIFT 0 +#define TFCAPTUREMAX(x) ((x) << TFCAPTUREMAX_SHIFT) +#define TFCAPTUREMAX_GET(x) (((x) & TFCAPTUREMAX_MASK) >> TFCAPTUREMAX_SHIFT) + +#define MPS_TRC_INT_CAUSE 0x985c +#define MISCPERR 0x00000100U +#define PKTFIFO 0x000000f0U +#define FILTMEM 0x0000000fU + +#define MPS_TRC_FILTER0_MATCH 0x9c00 +#define MPS_TRC_FILTER0_DONT_CARE 0x9c80 +#define MPS_TRC_FILTER1_MATCH 0x9d00 +#define MPS_CLS_INT_CAUSE 0xd028 +#define PLERRENB 0x00000008U +#define HASHSRAM 0x00000004U +#define MATCHTCAM 0x00000002U +#define MATCHSRAM 0x00000001U + +#define MPS_RX_PERR_INT_CAUSE 0x11074 + +#define CPL_INTR_CAUSE 0x19054 +#define CIM_OP_MAP_PERR 0x00000020U +#define CIM_OVFL_ERROR 0x00000010U +#define TP_FRAMING_ERROR 0x00000008U +#define SGE_FRAMING_ERROR 0x00000004U +#define CIM_FRAMING_ERROR 0x00000002U +#define ZERO_SWITCH_ERROR 0x00000001U + +#define SMB_INT_CAUSE 0x19090 +#define MSTTXFIFOPARINT 0x00200000U +#define MSTRXFIFOPARINT 0x00100000U +#define SLVFIFOPARINT 0x00080000U + +#define ULP_RX_INT_CAUSE 0x19158 +#define ULP_RX_ISCSI_TAGMASK 0x19164 +#define ULP_RX_ISCSI_PSZ 0x19168 +#define HPZ3_MASK 0x0f000000U +#define HPZ3_SHIFT 24 +#define HPZ3(x) ((x) << HPZ3_SHIFT) +#define HPZ2_MASK 0x000f0000U +#define HPZ2_SHIFT 16 +#define HPZ2(x) ((x) << HPZ2_SHIFT) +#define HPZ1_MASK 0x00000f00U +#define HPZ1_SHIFT 8 +#define HPZ1(x) ((x) << HPZ1_SHIFT) +#define HPZ0_MASK 0x0000000fU +#define HPZ0_SHIFT 0 +#define HPZ0(x) ((x) << HPZ0_SHIFT) + +#define ULP_RX_TDDP_PSZ 0x19178 + +#define SF_DATA 0x193f8 +#define SF_OP 0x193fc +#define BUSY 0x80000000U +#define SF_LOCK 0x00000010U +#define SF_CONT 0x00000008U +#define BYTECNT_MASK 0x00000006U +#define BYTECNT_SHIFT 1 +#define BYTECNT(x) ((x) << BYTECNT_SHIFT) +#define OP_WR 0x00000001U + +#define PL_PF_INT_CAUSE 0x3c0 +#define PFSW 0x00000008U +#define PFSGE 0x00000004U +#define PFCIM 0x00000002U +#define PFMPS 0x00000001U + +#define PL_PF_INT_ENABLE 0x3c4 +#define PL_PF_CTL 0x3c8 +#define SWINT 0x00000001U + +#define PL_WHOAMI 0x19400 +#define SOURCEPF_MASK 0x00000700U +#define SOURCEPF_SHIFT 8 +#define SOURCEPF(x) ((x) << SOURCEPF_SHIFT) +#define SOURCEPF_GET(x) (((x) & SOURCEPF_MASK) >> SOURCEPF_SHIFT) +#define ISVF 0x00000080U +#define VFID_MASK 0x0000007fU +#define VFID_SHIFT 0 +#define VFID(x) ((x) << VFID_SHIFT) +#define VFID_GET(x) (((x) & VFID_MASK) >> VFID_SHIFT) + +#define PL_INT_CAUSE 0x1940c +#define ULP_TX 0x08000000U +#define SGE 0x04000000U +#define HMA 0x02000000U +#define CPL_SWITCH 0x01000000U +#define ULP_RX 0x00800000U +#define PM_RX 0x00400000U +#define PM_TX 0x00200000U +#define MA 0x00100000U +#define TP 0x00080000U +#define LE 0x00040000U +#define EDC1 0x00020000U +#define EDC0 0x00010000U +#define MC 0x00008000U +#define PCIE 0x00004000U +#define PMU 0x00002000U +#define XGMAC_KR1 0x00001000U +#define XGMAC_KR0 0x00000800U +#define XGMAC1 0x00000400U +#define XGMAC0 0x00000200U +#define SMB 0x00000100U +#define SF 0x00000080U +#define PL 0x00000040U +#define NCSI 0x00000020U +#define MPS 0x00000010U +#define MI 0x00000008U +#define DBG 0x00000004U +#define I2CM 0x00000002U +#define CIM 0x00000001U + +#define PL_INT_MAP0 0x19414 +#define PL_RST 0x19428 +#define PIORST 0x00000002U +#define PIORSTMODE 0x00000001U + +#define PL_PL_INT_CAUSE 0x19430 +#define FATALPERR 0x00000010U +#define PERRVFID 0x00000001U + +#define PL_REV 0x1943c + +#define LE_DB_CONFIG 0x19c04 +#define HASHEN 0x00100000U + +#define LE_DB_SERVER_INDEX 0x19c18 +#define LE_DB_ACT_CNT_IPV4 0x19c20 +#define LE_DB_ACT_CNT_IPV6 0x19c24 + +#define LE_DB_INT_CAUSE 0x19c3c +#define REQQPARERR 0x00010000U +#define UNKNOWNCMD 0x00008000U +#define PARITYERR 0x00000040U +#define LIPMISS 0x00000020U +#define LIP0 0x00000010U + +#define LE_DB_TID_HASHBASE 0x19df8 + +#define NCSI_INT_CAUSE 0x1a0d8 +#define CIM_DM_PRTY_ERR 0x00000100U +#define MPS_DM_PRTY_ERR 0x00000080U +#define TXFIFO_PRTY_ERR 0x00000002U +#define RXFIFO_PRTY_ERR 0x00000001U + +#define XGMAC_PORT_CFG2 0x1018 +#define PATEN 0x00040000U +#define MAGICEN 0x00020000U + +#define XGMAC_PORT_MAGIC_MACID_LO 0x1024 +#define XGMAC_PORT_MAGIC_MACID_HI 0x1028 + +#define XGMAC_PORT_EPIO_DATA0 0x10c0 +#define XGMAC_PORT_EPIO_DATA1 0x10c4 +#define XGMAC_PORT_EPIO_DATA2 0x10c8 +#define XGMAC_PORT_EPIO_DATA3 0x10cc +#define XGMAC_PORT_EPIO_OP 0x10d0 +#define EPIOWR 0x00000100U +#define ADDRESS_MASK 0x000000ffU +#define ADDRESS_SHIFT 0 +#define ADDRESS(x) ((x) << ADDRESS_SHIFT) + +#define XGMAC_PORT_INT_CAUSE 0x10dc +#endif /* __T4_REGS_H */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h new file mode 100644 index 000000000000..edcfd7ec7802 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -0,0 +1,1623 @@ +/* + * This file is part of the Chelsio T4 Ethernet driver for Linux. + * + * Copyright (c) 2009-2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _T4FW_INTERFACE_H_ +#define _T4FW_INTERFACE_H_ + +#define FW_T4VF_SGE_BASE_ADDR 0x0000 +#define FW_T4VF_MPS_BASE_ADDR 0x0100 +#define FW_T4VF_PL_BASE_ADDR 0x0200 +#define FW_T4VF_MBDATA_BASE_ADDR 0x0240 +#define FW_T4VF_CIM_BASE_ADDR 0x0300 + +enum fw_wr_opcodes { + FW_FILTER_WR = 0x02, + FW_ULPTX_WR = 0x04, + FW_TP_WR = 0x05, + FW_ETH_TX_PKT_WR = 0x08, + FW_FLOWC_WR = 0x0a, + FW_OFLD_TX_DATA_WR = 0x0b, + FW_CMD_WR = 0x10, + FW_ETH_TX_PKT_VM_WR = 0x11, + FW_RI_RES_WR = 0x0c, + FW_RI_INIT_WR = 0x0d, + FW_RI_RDMA_WRITE_WR = 0x14, + FW_RI_SEND_WR = 0x15, + FW_RI_RDMA_READ_WR = 0x16, + FW_RI_RECV_WR = 0x17, + FW_RI_BIND_MW_WR = 0x18, + FW_RI_FR_NSMR_WR = 0x19, + FW_RI_INV_LSTAG_WR = 0x1a, + FW_LASTC2E_WR = 0x40 +}; + +struct fw_wr_hdr { + __be32 hi; + __be32 lo; +}; + +#define FW_WR_OP(x) ((x) << 24) +#define FW_WR_ATOMIC(x) ((x) << 23) +#define FW_WR_FLUSH(x) ((x) << 22) +#define FW_WR_COMPL(x) ((x) << 21) +#define FW_WR_IMMDLEN_MASK 0xff +#define FW_WR_IMMDLEN(x) ((x) << 0) + +#define FW_WR_EQUIQ (1U << 31) +#define FW_WR_EQUEQ (1U << 30) +#define FW_WR_FLOWID(x) ((x) << 8) +#define FW_WR_LEN16(x) ((x) << 0) + +struct fw_ulptx_wr { + __be32 op_to_compl; + __be32 flowid_len16; + u64 cookie; +}; + +struct fw_tp_wr { + __be32 op_to_immdlen; + __be32 flowid_len16; + u64 cookie; +}; + +struct fw_eth_tx_pkt_wr { + __be32 op_immdlen; + __be32 equiq_to_len16; + __be64 r3; +}; + +enum fw_flowc_mnem { + FW_FLOWC_MNEM_PFNVFN, /* PFN [15:8] VFN [7:0] */ + FW_FLOWC_MNEM_CH, + FW_FLOWC_MNEM_PORT, + FW_FLOWC_MNEM_IQID, + FW_FLOWC_MNEM_SNDNXT, + FW_FLOWC_MNEM_RCVNXT, + FW_FLOWC_MNEM_SNDBUF, + FW_FLOWC_MNEM_MSS, +}; + +struct fw_flowc_mnemval { + u8 mnemonic; + u8 r4[3]; + __be32 val; +}; + +struct fw_flowc_wr { + __be32 op_to_nparams; +#define FW_FLOWC_WR_NPARAMS(x) ((x) << 0) + __be32 flowid_len16; + struct fw_flowc_mnemval mnemval[0]; +}; + +struct fw_ofld_tx_data_wr { + __be32 op_to_immdlen; + __be32 flowid_len16; + __be32 plen; + __be32 tunnel_to_proxy; +#define FW_OFLD_TX_DATA_WR_TUNNEL(x) ((x) << 19) +#define FW_OFLD_TX_DATA_WR_SAVE(x) ((x) << 18) +#define FW_OFLD_TX_DATA_WR_FLUSH(x) ((x) << 17) +#define FW_OFLD_TX_DATA_WR_URGENT(x) ((x) << 16) +#define FW_OFLD_TX_DATA_WR_MORE(x) ((x) << 15) +#define FW_OFLD_TX_DATA_WR_SHOVE(x) ((x) << 14) +#define FW_OFLD_TX_DATA_WR_ULPMODE(x) ((x) << 10) +#define FW_OFLD_TX_DATA_WR_ULPSUBMODE(x) ((x) << 6) +}; + +struct fw_cmd_wr { + __be32 op_dma; +#define FW_CMD_WR_DMA (1U << 17) + __be32 len16_pkd; + __be64 cookie_daddr; +}; + +struct fw_eth_tx_pkt_vm_wr { + __be32 op_immdlen; + __be32 equiq_to_len16; + __be32 r3[2]; + u8 ethmacdst[6]; + u8 ethmacsrc[6]; + __be16 ethtype; + __be16 vlantci; +}; + +#define FW_CMD_MAX_TIMEOUT 3000 + +enum fw_cmd_opcodes { + FW_LDST_CMD = 0x01, + FW_RESET_CMD = 0x03, + FW_HELLO_CMD = 0x04, + FW_BYE_CMD = 0x05, + FW_INITIALIZE_CMD = 0x06, + FW_CAPS_CONFIG_CMD = 0x07, + FW_PARAMS_CMD = 0x08, + FW_PFVF_CMD = 0x09, + FW_IQ_CMD = 0x10, + FW_EQ_MNGT_CMD = 0x11, + FW_EQ_ETH_CMD = 0x12, + FW_EQ_CTRL_CMD = 0x13, + FW_EQ_OFLD_CMD = 0x21, + FW_VI_CMD = 0x14, + FW_VI_MAC_CMD = 0x15, + FW_VI_RXMODE_CMD = 0x16, + FW_VI_ENABLE_CMD = 0x17, + FW_ACL_MAC_CMD = 0x18, + FW_ACL_VLAN_CMD = 0x19, + FW_VI_STATS_CMD = 0x1a, + FW_PORT_CMD = 0x1b, + FW_PORT_STATS_CMD = 0x1c, + FW_PORT_LB_STATS_CMD = 0x1d, + FW_PORT_TRACE_CMD = 0x1e, + FW_PORT_TRACE_MMAP_CMD = 0x1f, + FW_RSS_IND_TBL_CMD = 0x20, + FW_RSS_GLB_CONFIG_CMD = 0x22, + FW_RSS_VI_CONFIG_CMD = 0x23, + FW_LASTC2E_CMD = 0x40, + FW_ERROR_CMD = 0x80, + FW_DEBUG_CMD = 0x81, +}; + +enum fw_cmd_cap { + FW_CMD_CAP_PF = 0x01, + FW_CMD_CAP_DMAQ = 0x02, + FW_CMD_CAP_PORT = 0x04, + FW_CMD_CAP_PORTPROMISC = 0x08, + FW_CMD_CAP_PORTSTATS = 0x10, + FW_CMD_CAP_VF = 0x80, +}; + +/* + * Generic command header flit0 + */ +struct fw_cmd_hdr { + __be32 hi; + __be32 lo; +}; + +#define FW_CMD_OP(x) ((x) << 24) +#define FW_CMD_OP_GET(x) (((x) >> 24) & 0xff) +#define FW_CMD_REQUEST (1U << 23) +#define FW_CMD_READ (1U << 22) +#define FW_CMD_WRITE (1U << 21) +#define FW_CMD_EXEC (1U << 20) +#define FW_CMD_RAMASK(x) ((x) << 20) +#define FW_CMD_RETVAL(x) ((x) << 8) +#define FW_CMD_RETVAL_GET(x) (((x) >> 8) & 0xff) +#define FW_CMD_LEN16(x) ((x) << 0) + +enum fw_ldst_addrspc { + FW_LDST_ADDRSPC_FIRMWARE = 0x0001, + FW_LDST_ADDRSPC_SGE_EGRC = 0x0008, + FW_LDST_ADDRSPC_SGE_INGC = 0x0009, + FW_LDST_ADDRSPC_SGE_FLMC = 0x000a, + FW_LDST_ADDRSPC_SGE_CONMC = 0x000b, + FW_LDST_ADDRSPC_TP_PIO = 0x0010, + FW_LDST_ADDRSPC_TP_TM_PIO = 0x0011, + FW_LDST_ADDRSPC_TP_MIB = 0x0012, + FW_LDST_ADDRSPC_MDIO = 0x0018, + FW_LDST_ADDRSPC_MPS = 0x0020, + FW_LDST_ADDRSPC_FUNC = 0x0028 +}; + +enum fw_ldst_mps_fid { + FW_LDST_MPS_ATRB, + FW_LDST_MPS_RPLC +}; + +enum fw_ldst_func_access_ctl { + FW_LDST_FUNC_ACC_CTL_VIID, + FW_LDST_FUNC_ACC_CTL_FID +}; + +enum fw_ldst_func_mod_index { + FW_LDST_FUNC_MPS +}; + +struct fw_ldst_cmd { + __be32 op_to_addrspace; +#define FW_LDST_CMD_ADDRSPACE(x) ((x) << 0) + __be32 cycles_to_len16; + union fw_ldst { + struct fw_ldst_addrval { + __be32 addr; + __be32 val; + } addrval; + struct fw_ldst_idctxt { + __be32 physid; + __be32 msg_pkd; + __be32 ctxt_data7; + __be32 ctxt_data6; + __be32 ctxt_data5; + __be32 ctxt_data4; + __be32 ctxt_data3; + __be32 ctxt_data2; + __be32 ctxt_data1; + __be32 ctxt_data0; + } idctxt; + struct fw_ldst_mdio { + __be16 paddr_mmd; + __be16 raddr; + __be16 vctl; + __be16 rval; + } mdio; + struct fw_ldst_mps { + __be16 fid_ctl; + __be16 rplcpf_pkd; + __be32 rplc127_96; + __be32 rplc95_64; + __be32 rplc63_32; + __be32 rplc31_0; + __be32 atrb; + __be16 vlan[16]; + } mps; + struct fw_ldst_func { + u8 access_ctl; + u8 mod_index; + __be16 ctl_id; + __be32 offset; + __be64 data0; + __be64 data1; + } func; + } u; +}; + +#define FW_LDST_CMD_MSG(x) ((x) << 31) +#define FW_LDST_CMD_PADDR(x) ((x) << 8) +#define FW_LDST_CMD_MMD(x) ((x) << 0) +#define FW_LDST_CMD_FID(x) ((x) << 15) +#define FW_LDST_CMD_CTL(x) ((x) << 0) +#define FW_LDST_CMD_RPLCPF(x) ((x) << 0) + +struct fw_reset_cmd { + __be32 op_to_write; + __be32 retval_len16; + __be32 val; + __be32 r3; +}; + +struct fw_hello_cmd { + __be32 op_to_write; + __be32 retval_len16; + __be32 err_to_mbasyncnot; +#define FW_HELLO_CMD_ERR (1U << 31) +#define FW_HELLO_CMD_INIT (1U << 30) +#define FW_HELLO_CMD_MASTERDIS(x) ((x) << 29) +#define FW_HELLO_CMD_MASTERFORCE(x) ((x) << 28) +#define FW_HELLO_CMD_MBMASTER(x) ((x) << 24) +#define FW_HELLO_CMD_MBASYNCNOT(x) ((x) << 20) + __be32 fwrev; +}; + +struct fw_bye_cmd { + __be32 op_to_write; + __be32 retval_len16; + __be64 r3; +}; + +struct fw_initialize_cmd { + __be32 op_to_write; + __be32 retval_len16; + __be64 r3; +}; + +enum fw_caps_config_hm { + FW_CAPS_CONFIG_HM_PCIE = 0x00000001, + FW_CAPS_CONFIG_HM_PL = 0x00000002, + FW_CAPS_CONFIG_HM_SGE = 0x00000004, + FW_CAPS_CONFIG_HM_CIM = 0x00000008, + FW_CAPS_CONFIG_HM_ULPTX = 0x00000010, + FW_CAPS_CONFIG_HM_TP = 0x00000020, + FW_CAPS_CONFIG_HM_ULPRX = 0x00000040, + FW_CAPS_CONFIG_HM_PMRX = 0x00000080, + FW_CAPS_CONFIG_HM_PMTX = 0x00000100, + FW_CAPS_CONFIG_HM_MC = 0x00000200, + FW_CAPS_CONFIG_HM_LE = 0x00000400, + FW_CAPS_CONFIG_HM_MPS = 0x00000800, + FW_CAPS_CONFIG_HM_XGMAC = 0x00001000, + FW_CAPS_CONFIG_HM_CPLSWITCH = 0x00002000, + FW_CAPS_CONFIG_HM_T4DBG = 0x00004000, + FW_CAPS_CONFIG_HM_MI = 0x00008000, + FW_CAPS_CONFIG_HM_I2CM = 0x00010000, + FW_CAPS_CONFIG_HM_NCSI = 0x00020000, + FW_CAPS_CONFIG_HM_SMB = 0x00040000, + FW_CAPS_CONFIG_HM_MA = 0x00080000, + FW_CAPS_CONFIG_HM_EDRAM = 0x00100000, + FW_CAPS_CONFIG_HM_PMU = 0x00200000, + FW_CAPS_CONFIG_HM_UART = 0x00400000, + FW_CAPS_CONFIG_HM_SF = 0x00800000, +}; + +enum fw_caps_config_nbm { + FW_CAPS_CONFIG_NBM_IPMI = 0x00000001, + FW_CAPS_CONFIG_NBM_NCSI = 0x00000002, +}; + +enum fw_caps_config_link { + FW_CAPS_CONFIG_LINK_PPP = 0x00000001, + FW_CAPS_CONFIG_LINK_QFC = 0x00000002, + FW_CAPS_CONFIG_LINK_DCBX = 0x00000004, +}; + +enum fw_caps_config_switch { + FW_CAPS_CONFIG_SWITCH_INGRESS = 0x00000001, + FW_CAPS_CONFIG_SWITCH_EGRESS = 0x00000002, +}; + +enum fw_caps_config_nic { + FW_CAPS_CONFIG_NIC = 0x00000001, + FW_CAPS_CONFIG_NIC_VM = 0x00000002, +}; + +enum fw_caps_config_ofld { + FW_CAPS_CONFIG_OFLD = 0x00000001, +}; + +enum fw_caps_config_rdma { + FW_CAPS_CONFIG_RDMA_RDDP = 0x00000001, + FW_CAPS_CONFIG_RDMA_RDMAC = 0x00000002, +}; + +enum fw_caps_config_iscsi { + FW_CAPS_CONFIG_ISCSI_INITIATOR_PDU = 0x00000001, + FW_CAPS_CONFIG_ISCSI_TARGET_PDU = 0x00000002, + FW_CAPS_CONFIG_ISCSI_INITIATOR_CNXOFLD = 0x00000004, + FW_CAPS_CONFIG_ISCSI_TARGET_CNXOFLD = 0x00000008, +}; + +enum fw_caps_config_fcoe { + FW_CAPS_CONFIG_FCOE_INITIATOR = 0x00000001, + FW_CAPS_CONFIG_FCOE_TARGET = 0x00000002, +}; + +struct fw_caps_config_cmd { + __be32 op_to_write; + __be32 retval_len16; + __be32 r2; + __be32 hwmbitmap; + __be16 nbmcaps; + __be16 linkcaps; + __be16 switchcaps; + __be16 r3; + __be16 niccaps; + __be16 ofldcaps; + __be16 rdmacaps; + __be16 r4; + __be16 iscsicaps; + __be16 fcoecaps; + __be32 r5; + __be64 r6; +}; + +/* + * params command mnemonics + */ +enum fw_params_mnem { + FW_PARAMS_MNEM_DEV = 1, /* device params */ + FW_PARAMS_MNEM_PFVF = 2, /* function params */ + FW_PARAMS_MNEM_REG = 3, /* limited register access */ + FW_PARAMS_MNEM_DMAQ = 4, /* dma queue params */ + FW_PARAMS_MNEM_LAST +}; + +/* + * device parameters + */ +enum fw_params_param_dev { + FW_PARAMS_PARAM_DEV_CCLK = 0x00, /* chip core clock in khz */ + FW_PARAMS_PARAM_DEV_PORTVEC = 0x01, /* the port vector */ + FW_PARAMS_PARAM_DEV_NTID = 0x02, /* reads the number of TIDs + * allocated by the device's + * Lookup Engine + */ + FW_PARAMS_PARAM_DEV_FLOWC_BUFFIFO_SZ = 0x03, + FW_PARAMS_PARAM_DEV_INTVER_NIC = 0x04, + FW_PARAMS_PARAM_DEV_INTVER_VNIC = 0x05, + FW_PARAMS_PARAM_DEV_INTVER_OFLD = 0x06, + FW_PARAMS_PARAM_DEV_INTVER_RI = 0x07, + FW_PARAMS_PARAM_DEV_INTVER_ISCSIPDU = 0x08, + FW_PARAMS_PARAM_DEV_INTVER_ISCSI = 0x09, + FW_PARAMS_PARAM_DEV_INTVER_FCOE = 0x0A, + FW_PARAMS_PARAM_DEV_FWREV = 0x0B, + FW_PARAMS_PARAM_DEV_TPREV = 0x0C, +}; + +/* + * physical and virtual function parameters + */ +enum fw_params_param_pfvf { + FW_PARAMS_PARAM_PFVF_RWXCAPS = 0x00, + FW_PARAMS_PARAM_PFVF_ROUTE_START = 0x01, + FW_PARAMS_PARAM_PFVF_ROUTE_END = 0x02, + FW_PARAMS_PARAM_PFVF_CLIP_START = 0x03, + FW_PARAMS_PARAM_PFVF_CLIP_END = 0x04, + FW_PARAMS_PARAM_PFVF_FILTER_START = 0x05, + FW_PARAMS_PARAM_PFVF_FILTER_END = 0x06, + FW_PARAMS_PARAM_PFVF_SERVER_START = 0x07, + FW_PARAMS_PARAM_PFVF_SERVER_END = 0x08, + FW_PARAMS_PARAM_PFVF_TDDP_START = 0x09, + FW_PARAMS_PARAM_PFVF_TDDP_END = 0x0A, + FW_PARAMS_PARAM_PFVF_ISCSI_START = 0x0B, + FW_PARAMS_PARAM_PFVF_ISCSI_END = 0x0C, + FW_PARAMS_PARAM_PFVF_STAG_START = 0x0D, + FW_PARAMS_PARAM_PFVF_STAG_END = 0x0E, + FW_PARAMS_PARAM_PFVF_RQ_START = 0x1F, + FW_PARAMS_PARAM_PFVF_RQ_END = 0x10, + FW_PARAMS_PARAM_PFVF_PBL_START = 0x11, + FW_PARAMS_PARAM_PFVF_PBL_END = 0x12, + FW_PARAMS_PARAM_PFVF_L2T_START = 0x13, + FW_PARAMS_PARAM_PFVF_L2T_END = 0x14, + FW_PARAMS_PARAM_PFVF_SQRQ_START = 0x15, + FW_PARAMS_PARAM_PFVF_SQRQ_END = 0x16, + FW_PARAMS_PARAM_PFVF_CQ_START = 0x17, + FW_PARAMS_PARAM_PFVF_CQ_END = 0x18, + FW_PARAMS_PARAM_PFVF_SCHEDCLASS_ETH = 0x20, + FW_PARAMS_PARAM_PFVF_VIID = 0x24, + FW_PARAMS_PARAM_PFVF_CPMASK = 0x25, + FW_PARAMS_PARAM_PFVF_OCQ_START = 0x26, + FW_PARAMS_PARAM_PFVF_OCQ_END = 0x27, + FW_PARAMS_PARAM_PFVF_CONM_MAP = 0x28, + FW_PARAMS_PARAM_PFVF_IQFLINT_START = 0x29, + FW_PARAMS_PARAM_PFVF_IQFLINT_END = 0x2A, + FW_PARAMS_PARAM_PFVF_EQ_START = 0x2B, + FW_PARAMS_PARAM_PFVF_EQ_END = 0x2C, +}; + +/* + * dma queue parameters + */ +enum fw_params_param_dmaq { + FW_PARAMS_PARAM_DMAQ_IQ_DCAEN_DCACPU = 0x00, + FW_PARAMS_PARAM_DMAQ_IQ_INTCNTTHRESH = 0x01, + FW_PARAMS_PARAM_DMAQ_EQ_CMPLIQID_MNGT = 0x10, + FW_PARAMS_PARAM_DMAQ_EQ_CMPLIQID_CTRL = 0x11, + FW_PARAMS_PARAM_DMAQ_EQ_SCHEDCLASS_ETH = 0x12, +}; + +#define FW_PARAMS_MNEM(x) ((x) << 24) +#define FW_PARAMS_PARAM_X(x) ((x) << 16) +#define FW_PARAMS_PARAM_Y(x) ((x) << 8) +#define FW_PARAMS_PARAM_Z(x) ((x) << 0) +#define FW_PARAMS_PARAM_XYZ(x) ((x) << 0) +#define FW_PARAMS_PARAM_YZ(x) ((x) << 0) + +struct fw_params_cmd { + __be32 op_to_vfn; + __be32 retval_len16; + struct fw_params_param { + __be32 mnem; + __be32 val; + } param[7]; +}; + +#define FW_PARAMS_CMD_PFN(x) ((x) << 8) +#define FW_PARAMS_CMD_VFN(x) ((x) << 0) + +struct fw_pfvf_cmd { + __be32 op_to_vfn; + __be32 retval_len16; + __be32 niqflint_niq; + __be32 type_to_neq; + __be32 tc_to_nexactf; + __be32 r_caps_to_nethctrl; + __be16 nricq; + __be16 nriqp; + __be32 r4; +}; + +#define FW_PFVF_CMD_PFN(x) ((x) << 8) +#define FW_PFVF_CMD_VFN(x) ((x) << 0) + +#define FW_PFVF_CMD_NIQFLINT(x) ((x) << 20) +#define FW_PFVF_CMD_NIQFLINT_GET(x) (((x) >> 20) & 0xfff) + +#define FW_PFVF_CMD_NIQ(x) ((x) << 0) +#define FW_PFVF_CMD_NIQ_GET(x) (((x) >> 0) & 0xfffff) + +#define FW_PFVF_CMD_TYPE (1 << 31) +#define FW_PFVF_CMD_TYPE_GET(x) (((x) >> 31) & 0x1) + +#define FW_PFVF_CMD_CMASK(x) ((x) << 24) +#define FW_PFVF_CMD_CMASK_MASK 0xf +#define FW_PFVF_CMD_CMASK_GET(x) (((x) >> 24) & FW_PFVF_CMD_CMASK_MASK) + +#define FW_PFVF_CMD_PMASK(x) ((x) << 20) +#define FW_PFVF_CMD_PMASK_MASK 0xf +#define FW_PFVF_CMD_PMASK_GET(x) (((x) >> 20) & FW_PFVF_CMD_PMASK_MASK) + +#define FW_PFVF_CMD_NEQ(x) ((x) << 0) +#define FW_PFVF_CMD_NEQ_GET(x) (((x) >> 0) & 0xfffff) + +#define FW_PFVF_CMD_TC(x) ((x) << 24) +#define FW_PFVF_CMD_TC_GET(x) (((x) >> 24) & 0xff) + +#define FW_PFVF_CMD_NVI(x) ((x) << 16) +#define FW_PFVF_CMD_NVI_GET(x) (((x) >> 16) & 0xff) + +#define FW_PFVF_CMD_NEXACTF(x) ((x) << 0) +#define FW_PFVF_CMD_NEXACTF_GET(x) (((x) >> 0) & 0xffff) + +#define FW_PFVF_CMD_R_CAPS(x) ((x) << 24) +#define FW_PFVF_CMD_R_CAPS_GET(x) (((x) >> 24) & 0xff) + +#define FW_PFVF_CMD_WX_CAPS(x) ((x) << 16) +#define FW_PFVF_CMD_WX_CAPS_GET(x) (((x) >> 16) & 0xff) + +#define FW_PFVF_CMD_NETHCTRL(x) ((x) << 0) +#define FW_PFVF_CMD_NETHCTRL_GET(x) (((x) >> 0) & 0xffff) + +enum fw_iq_type { + FW_IQ_TYPE_FL_INT_CAP, + FW_IQ_TYPE_NO_FL_INT_CAP +}; + +struct fw_iq_cmd { + __be32 op_to_vfn; + __be32 alloc_to_len16; + __be16 physiqid; + __be16 iqid; + __be16 fl0id; + __be16 fl1id; + __be32 type_to_iqandstindex; + __be16 iqdroprss_to_iqesize; + __be16 iqsize; + __be64 iqaddr; + __be32 iqns_to_fl0congen; + __be16 fl0dcaen_to_fl0cidxfthresh; + __be16 fl0size; + __be64 fl0addr; + __be32 fl1cngchmap_to_fl1congen; + __be16 fl1dcaen_to_fl1cidxfthresh; + __be16 fl1size; + __be64 fl1addr; +}; + +#define FW_IQ_CMD_PFN(x) ((x) << 8) +#define FW_IQ_CMD_VFN(x) ((x) << 0) + +#define FW_IQ_CMD_ALLOC (1U << 31) +#define FW_IQ_CMD_FREE (1U << 30) +#define FW_IQ_CMD_MODIFY (1U << 29) +#define FW_IQ_CMD_IQSTART(x) ((x) << 28) +#define FW_IQ_CMD_IQSTOP(x) ((x) << 27) + +#define FW_IQ_CMD_TYPE(x) ((x) << 29) +#define FW_IQ_CMD_IQASYNCH(x) ((x) << 28) +#define FW_IQ_CMD_VIID(x) ((x) << 16) +#define FW_IQ_CMD_IQANDST(x) ((x) << 15) +#define FW_IQ_CMD_IQANUS(x) ((x) << 14) +#define FW_IQ_CMD_IQANUD(x) ((x) << 12) +#define FW_IQ_CMD_IQANDSTINDEX(x) ((x) << 0) + +#define FW_IQ_CMD_IQDROPRSS (1U << 15) +#define FW_IQ_CMD_IQGTSMODE (1U << 14) +#define FW_IQ_CMD_IQPCIECH(x) ((x) << 12) +#define FW_IQ_CMD_IQDCAEN(x) ((x) << 11) +#define FW_IQ_CMD_IQDCACPU(x) ((x) << 6) +#define FW_IQ_CMD_IQINTCNTTHRESH(x) ((x) << 4) +#define FW_IQ_CMD_IQO (1U << 3) +#define FW_IQ_CMD_IQCPRIO(x) ((x) << 2) +#define FW_IQ_CMD_IQESIZE(x) ((x) << 0) + +#define FW_IQ_CMD_IQNS(x) ((x) << 31) +#define FW_IQ_CMD_IQRO(x) ((x) << 30) +#define FW_IQ_CMD_IQFLINTIQHSEN(x) ((x) << 28) +#define FW_IQ_CMD_IQFLINTCONGEN(x) ((x) << 27) +#define FW_IQ_CMD_IQFLINTISCSIC(x) ((x) << 26) +#define FW_IQ_CMD_FL0CNGCHMAP(x) ((x) << 20) +#define FW_IQ_CMD_FL0CACHELOCK(x) ((x) << 15) +#define FW_IQ_CMD_FL0DBP(x) ((x) << 14) +#define FW_IQ_CMD_FL0DATANS(x) ((x) << 13) +#define FW_IQ_CMD_FL0DATARO(x) ((x) << 12) +#define FW_IQ_CMD_FL0CONGCIF(x) ((x) << 11) +#define FW_IQ_CMD_FL0ONCHIP(x) ((x) << 10) +#define FW_IQ_CMD_FL0STATUSPGNS(x) ((x) << 9) +#define FW_IQ_CMD_FL0STATUSPGRO(x) ((x) << 8) +#define FW_IQ_CMD_FL0FETCHNS(x) ((x) << 7) +#define FW_IQ_CMD_FL0FETCHRO(x) ((x) << 6) +#define FW_IQ_CMD_FL0HOSTFCMODE(x) ((x) << 4) +#define FW_IQ_CMD_FL0CPRIO(x) ((x) << 3) +#define FW_IQ_CMD_FL0PADEN (1U << 2) +#define FW_IQ_CMD_FL0PACKEN (1U << 1) +#define FW_IQ_CMD_FL0CONGEN (1U << 0) + +#define FW_IQ_CMD_FL0DCAEN(x) ((x) << 15) +#define FW_IQ_CMD_FL0DCACPU(x) ((x) << 10) +#define FW_IQ_CMD_FL0FBMIN(x) ((x) << 7) +#define FW_IQ_CMD_FL0FBMAX(x) ((x) << 4) +#define FW_IQ_CMD_FL0CIDXFTHRESHO (1U << 3) +#define FW_IQ_CMD_FL0CIDXFTHRESH(x) ((x) << 0) + +#define FW_IQ_CMD_FL1CNGCHMAP(x) ((x) << 20) +#define FW_IQ_CMD_FL1CACHELOCK(x) ((x) << 15) +#define FW_IQ_CMD_FL1DBP(x) ((x) << 14) +#define FW_IQ_CMD_FL1DATANS(x) ((x) << 13) +#define FW_IQ_CMD_FL1DATARO(x) ((x) << 12) +#define FW_IQ_CMD_FL1CONGCIF(x) ((x) << 11) +#define FW_IQ_CMD_FL1ONCHIP(x) ((x) << 10) +#define FW_IQ_CMD_FL1STATUSPGNS(x) ((x) << 9) +#define FW_IQ_CMD_FL1STATUSPGRO(x) ((x) << 8) +#define FW_IQ_CMD_FL1FETCHNS(x) ((x) << 7) +#define FW_IQ_CMD_FL1FETCHRO(x) ((x) << 6) +#define FW_IQ_CMD_FL1HOSTFCMODE(x) ((x) << 4) +#define FW_IQ_CMD_FL1CPRIO(x) ((x) << 3) +#define FW_IQ_CMD_FL1PADEN (1U << 2) +#define FW_IQ_CMD_FL1PACKEN (1U << 1) +#define FW_IQ_CMD_FL1CONGEN (1U << 0) + +#define FW_IQ_CMD_FL1DCAEN(x) ((x) << 15) +#define FW_IQ_CMD_FL1DCACPU(x) ((x) << 10) +#define FW_IQ_CMD_FL1FBMIN(x) ((x) << 7) +#define FW_IQ_CMD_FL1FBMAX(x) ((x) << 4) +#define FW_IQ_CMD_FL1CIDXFTHRESHO (1U << 3) +#define FW_IQ_CMD_FL1CIDXFTHRESH(x) ((x) << 0) + +struct fw_eq_eth_cmd { + __be32 op_to_vfn; + __be32 alloc_to_len16; + __be32 eqid_pkd; + __be32 physeqid_pkd; + __be32 fetchszm_to_iqid; + __be32 dcaen_to_eqsize; + __be64 eqaddr; + __be32 viid_pkd; + __be32 r8_lo; + __be64 r9; +}; + +#define FW_EQ_ETH_CMD_PFN(x) ((x) << 8) +#define FW_EQ_ETH_CMD_VFN(x) ((x) << 0) +#define FW_EQ_ETH_CMD_ALLOC (1U << 31) +#define FW_EQ_ETH_CMD_FREE (1U << 30) +#define FW_EQ_ETH_CMD_MODIFY (1U << 29) +#define FW_EQ_ETH_CMD_EQSTART (1U << 28) +#define FW_EQ_ETH_CMD_EQSTOP (1U << 27) + +#define FW_EQ_ETH_CMD_EQID(x) ((x) << 0) +#define FW_EQ_ETH_CMD_EQID_GET(x) (((x) >> 0) & 0xfffff) +#define FW_EQ_ETH_CMD_PHYSEQID(x) ((x) << 0) +#define FW_EQ_ETH_CMD_PHYSEQID_GET(x) (((x) >> 0) & 0xfffff) + +#define FW_EQ_ETH_CMD_FETCHSZM(x) ((x) << 26) +#define FW_EQ_ETH_CMD_STATUSPGNS(x) ((x) << 25) +#define FW_EQ_ETH_CMD_STATUSPGRO(x) ((x) << 24) +#define FW_EQ_ETH_CMD_FETCHNS(x) ((x) << 23) +#define FW_EQ_ETH_CMD_FETCHRO(x) ((x) << 22) +#define FW_EQ_ETH_CMD_HOSTFCMODE(x) ((x) << 20) +#define FW_EQ_ETH_CMD_CPRIO(x) ((x) << 19) +#define FW_EQ_ETH_CMD_ONCHIP(x) ((x) << 18) +#define FW_EQ_ETH_CMD_PCIECHN(x) ((x) << 16) +#define FW_EQ_ETH_CMD_IQID(x) ((x) << 0) + +#define FW_EQ_ETH_CMD_DCAEN(x) ((x) << 31) +#define FW_EQ_ETH_CMD_DCACPU(x) ((x) << 26) +#define FW_EQ_ETH_CMD_FBMIN(x) ((x) << 23) +#define FW_EQ_ETH_CMD_FBMAX(x) ((x) << 20) +#define FW_EQ_ETH_CMD_CIDXFTHRESHO(x) ((x) << 19) +#define FW_EQ_ETH_CMD_CIDXFTHRESH(x) ((x) << 16) +#define FW_EQ_ETH_CMD_EQSIZE(x) ((x) << 0) + +#define FW_EQ_ETH_CMD_VIID(x) ((x) << 16) + +struct fw_eq_ctrl_cmd { + __be32 op_to_vfn; + __be32 alloc_to_len16; + __be32 cmpliqid_eqid; + __be32 physeqid_pkd; + __be32 fetchszm_to_iqid; + __be32 dcaen_to_eqsize; + __be64 eqaddr; +}; + +#define FW_EQ_CTRL_CMD_PFN(x) ((x) << 8) +#define FW_EQ_CTRL_CMD_VFN(x) ((x) << 0) + +#define FW_EQ_CTRL_CMD_ALLOC (1U << 31) +#define FW_EQ_CTRL_CMD_FREE (1U << 30) +#define FW_EQ_CTRL_CMD_MODIFY (1U << 29) +#define FW_EQ_CTRL_CMD_EQSTART (1U << 28) +#define FW_EQ_CTRL_CMD_EQSTOP (1U << 27) + +#define FW_EQ_CTRL_CMD_CMPLIQID(x) ((x) << 20) +#define FW_EQ_CTRL_CMD_EQID(x) ((x) << 0) +#define FW_EQ_CTRL_CMD_EQID_GET(x) (((x) >> 0) & 0xfffff) +#define FW_EQ_CTRL_CMD_PHYSEQID_GET(x) (((x) >> 0) & 0xfffff) + +#define FW_EQ_CTRL_CMD_FETCHSZM (1U << 26) +#define FW_EQ_CTRL_CMD_STATUSPGNS (1U << 25) +#define FW_EQ_CTRL_CMD_STATUSPGRO (1U << 24) +#define FW_EQ_CTRL_CMD_FETCHNS (1U << 23) +#define FW_EQ_CTRL_CMD_FETCHRO (1U << 22) +#define FW_EQ_CTRL_CMD_HOSTFCMODE(x) ((x) << 20) +#define FW_EQ_CTRL_CMD_CPRIO(x) ((x) << 19) +#define FW_EQ_CTRL_CMD_ONCHIP(x) ((x) << 18) +#define FW_EQ_CTRL_CMD_PCIECHN(x) ((x) << 16) +#define FW_EQ_CTRL_CMD_IQID(x) ((x) << 0) + +#define FW_EQ_CTRL_CMD_DCAEN(x) ((x) << 31) +#define FW_EQ_CTRL_CMD_DCACPU(x) ((x) << 26) +#define FW_EQ_CTRL_CMD_FBMIN(x) ((x) << 23) +#define FW_EQ_CTRL_CMD_FBMAX(x) ((x) << 20) +#define FW_EQ_CTRL_CMD_CIDXFTHRESHO(x) ((x) << 19) +#define FW_EQ_CTRL_CMD_CIDXFTHRESH(x) ((x) << 16) +#define FW_EQ_CTRL_CMD_EQSIZE(x) ((x) << 0) + +struct fw_eq_ofld_cmd { + __be32 op_to_vfn; + __be32 alloc_to_len16; + __be32 eqid_pkd; + __be32 physeqid_pkd; + __be32 fetchszm_to_iqid; + __be32 dcaen_to_eqsize; + __be64 eqaddr; +}; + +#define FW_EQ_OFLD_CMD_PFN(x) ((x) << 8) +#define FW_EQ_OFLD_CMD_VFN(x) ((x) << 0) + +#define FW_EQ_OFLD_CMD_ALLOC (1U << 31) +#define FW_EQ_OFLD_CMD_FREE (1U << 30) +#define FW_EQ_OFLD_CMD_MODIFY (1U << 29) +#define FW_EQ_OFLD_CMD_EQSTART (1U << 28) +#define FW_EQ_OFLD_CMD_EQSTOP (1U << 27) + +#define FW_EQ_OFLD_CMD_EQID(x) ((x) << 0) +#define FW_EQ_OFLD_CMD_EQID_GET(x) (((x) >> 0) & 0xfffff) +#define FW_EQ_OFLD_CMD_PHYSEQID_GET(x) (((x) >> 0) & 0xfffff) + +#define FW_EQ_OFLD_CMD_FETCHSZM(x) ((x) << 26) +#define FW_EQ_OFLD_CMD_STATUSPGNS(x) ((x) << 25) +#define FW_EQ_OFLD_CMD_STATUSPGRO(x) ((x) << 24) +#define FW_EQ_OFLD_CMD_FETCHNS(x) ((x) << 23) +#define FW_EQ_OFLD_CMD_FETCHRO(x) ((x) << 22) +#define FW_EQ_OFLD_CMD_HOSTFCMODE(x) ((x) << 20) +#define FW_EQ_OFLD_CMD_CPRIO(x) ((x) << 19) +#define FW_EQ_OFLD_CMD_ONCHIP(x) ((x) << 18) +#define FW_EQ_OFLD_CMD_PCIECHN(x) ((x) << 16) +#define FW_EQ_OFLD_CMD_IQID(x) ((x) << 0) + +#define FW_EQ_OFLD_CMD_DCAEN(x) ((x) << 31) +#define FW_EQ_OFLD_CMD_DCACPU(x) ((x) << 26) +#define FW_EQ_OFLD_CMD_FBMIN(x) ((x) << 23) +#define FW_EQ_OFLD_CMD_FBMAX(x) ((x) << 20) +#define FW_EQ_OFLD_CMD_CIDXFTHRESHO(x) ((x) << 19) +#define FW_EQ_OFLD_CMD_CIDXFTHRESH(x) ((x) << 16) +#define FW_EQ_OFLD_CMD_EQSIZE(x) ((x) << 0) + +/* + * Macros for VIID parsing: + * VIID - [10:8] PFN, [7] VI Valid, [6:0] VI number + */ +#define FW_VIID_PFN_GET(x) (((x) >> 8) & 0x7) +#define FW_VIID_VIVLD_GET(x) (((x) >> 7) & 0x1) +#define FW_VIID_VIN_GET(x) (((x) >> 0) & 0x7F) + +struct fw_vi_cmd { + __be32 op_to_vfn; + __be32 alloc_to_len16; + __be16 type_viid; + u8 mac[6]; + u8 portid_pkd; + u8 nmac; + u8 nmac0[6]; + __be16 rsssize_pkd; + u8 nmac1[6]; + __be16 idsiiq_pkd; + u8 nmac2[6]; + __be16 idseiq_pkd; + u8 nmac3[6]; + __be64 r9; + __be64 r10; +}; + +#define FW_VI_CMD_PFN(x) ((x) << 8) +#define FW_VI_CMD_VFN(x) ((x) << 0) +#define FW_VI_CMD_ALLOC (1U << 31) +#define FW_VI_CMD_FREE (1U << 30) +#define FW_VI_CMD_VIID(x) ((x) << 0) +#define FW_VI_CMD_VIID_GET(x) ((x) & 0xfff) +#define FW_VI_CMD_PORTID(x) ((x) << 4) +#define FW_VI_CMD_PORTID_GET(x) (((x) >> 4) & 0xf) +#define FW_VI_CMD_RSSSIZE_GET(x) (((x) >> 0) & 0x7ff) + +/* Special VI_MAC command index ids */ +#define FW_VI_MAC_ADD_MAC 0x3FF +#define FW_VI_MAC_ADD_PERSIST_MAC 0x3FE +#define FW_VI_MAC_MAC_BASED_FREE 0x3FD +#define FW_CLS_TCAM_NUM_ENTRIES 336 + +enum fw_vi_mac_smac { + FW_VI_MAC_MPS_TCAM_ENTRY, + FW_VI_MAC_MPS_TCAM_ONLY, + FW_VI_MAC_SMT_ONLY, + FW_VI_MAC_SMT_AND_MPSTCAM +}; + +enum fw_vi_mac_result { + FW_VI_MAC_R_SUCCESS, + FW_VI_MAC_R_F_NONEXISTENT_NOMEM, + FW_VI_MAC_R_SMAC_FAIL, + FW_VI_MAC_R_F_ACL_CHECK +}; + +struct fw_vi_mac_cmd { + __be32 op_to_viid; + __be32 freemacs_to_len16; + union fw_vi_mac { + struct fw_vi_mac_exact { + __be16 valid_to_idx; + u8 macaddr[6]; + } exact[7]; + struct fw_vi_mac_hash { + __be64 hashvec; + } hash; + } u; +}; + +#define FW_VI_MAC_CMD_VIID(x) ((x) << 0) +#define FW_VI_MAC_CMD_FREEMACS(x) ((x) << 31) +#define FW_VI_MAC_CMD_HASHVECEN (1U << 23) +#define FW_VI_MAC_CMD_HASHUNIEN(x) ((x) << 22) +#define FW_VI_MAC_CMD_VALID (1U << 15) +#define FW_VI_MAC_CMD_PRIO(x) ((x) << 12) +#define FW_VI_MAC_CMD_SMAC_RESULT(x) ((x) << 10) +#define FW_VI_MAC_CMD_SMAC_RESULT_GET(x) (((x) >> 10) & 0x3) +#define FW_VI_MAC_CMD_IDX(x) ((x) << 0) +#define FW_VI_MAC_CMD_IDX_GET(x) (((x) >> 0) & 0x3ff) + +#define FW_RXMODE_MTU_NO_CHG 65535 + +struct fw_vi_rxmode_cmd { + __be32 op_to_viid; + __be32 retval_len16; + __be32 mtu_to_vlanexen; + __be32 r4_lo; +}; + +#define FW_VI_RXMODE_CMD_VIID(x) ((x) << 0) +#define FW_VI_RXMODE_CMD_MTU_MASK 0xffff +#define FW_VI_RXMODE_CMD_MTU(x) ((x) << 16) +#define FW_VI_RXMODE_CMD_PROMISCEN_MASK 0x3 +#define FW_VI_RXMODE_CMD_PROMISCEN(x) ((x) << 14) +#define FW_VI_RXMODE_CMD_ALLMULTIEN_MASK 0x3 +#define FW_VI_RXMODE_CMD_ALLMULTIEN(x) ((x) << 12) +#define FW_VI_RXMODE_CMD_BROADCASTEN_MASK 0x3 +#define FW_VI_RXMODE_CMD_BROADCASTEN(x) ((x) << 10) +#define FW_VI_RXMODE_CMD_VLANEXEN_MASK 0x3 +#define FW_VI_RXMODE_CMD_VLANEXEN(x) ((x) << 8) + +struct fw_vi_enable_cmd { + __be32 op_to_viid; + __be32 ien_to_len16; + __be16 blinkdur; + __be16 r3; + __be32 r4; +}; + +#define FW_VI_ENABLE_CMD_VIID(x) ((x) << 0) +#define FW_VI_ENABLE_CMD_IEN(x) ((x) << 31) +#define FW_VI_ENABLE_CMD_EEN(x) ((x) << 30) +#define FW_VI_ENABLE_CMD_LED (1U << 29) + +/* VI VF stats offset definitions */ +#define VI_VF_NUM_STATS 16 +enum fw_vi_stats_vf_index { + FW_VI_VF_STAT_TX_BCAST_BYTES_IX, + FW_VI_VF_STAT_TX_BCAST_FRAMES_IX, + FW_VI_VF_STAT_TX_MCAST_BYTES_IX, + FW_VI_VF_STAT_TX_MCAST_FRAMES_IX, + FW_VI_VF_STAT_TX_UCAST_BYTES_IX, + FW_VI_VF_STAT_TX_UCAST_FRAMES_IX, + FW_VI_VF_STAT_TX_DROP_FRAMES_IX, + FW_VI_VF_STAT_TX_OFLD_BYTES_IX, + FW_VI_VF_STAT_TX_OFLD_FRAMES_IX, + FW_VI_VF_STAT_RX_BCAST_BYTES_IX, + FW_VI_VF_STAT_RX_BCAST_FRAMES_IX, + FW_VI_VF_STAT_RX_MCAST_BYTES_IX, + FW_VI_VF_STAT_RX_MCAST_FRAMES_IX, + FW_VI_VF_STAT_RX_UCAST_BYTES_IX, + FW_VI_VF_STAT_RX_UCAST_FRAMES_IX, + FW_VI_VF_STAT_RX_ERR_FRAMES_IX +}; + +/* VI PF stats offset definitions */ +#define VI_PF_NUM_STATS 17 +enum fw_vi_stats_pf_index { + FW_VI_PF_STAT_TX_BCAST_BYTES_IX, + FW_VI_PF_STAT_TX_BCAST_FRAMES_IX, + FW_VI_PF_STAT_TX_MCAST_BYTES_IX, + FW_VI_PF_STAT_TX_MCAST_FRAMES_IX, + FW_VI_PF_STAT_TX_UCAST_BYTES_IX, + FW_VI_PF_STAT_TX_UCAST_FRAMES_IX, + FW_VI_PF_STAT_TX_OFLD_BYTES_IX, + FW_VI_PF_STAT_TX_OFLD_FRAMES_IX, + FW_VI_PF_STAT_RX_BYTES_IX, + FW_VI_PF_STAT_RX_FRAMES_IX, + FW_VI_PF_STAT_RX_BCAST_BYTES_IX, + FW_VI_PF_STAT_RX_BCAST_FRAMES_IX, + FW_VI_PF_STAT_RX_MCAST_BYTES_IX, + FW_VI_PF_STAT_RX_MCAST_FRAMES_IX, + FW_VI_PF_STAT_RX_UCAST_BYTES_IX, + FW_VI_PF_STAT_RX_UCAST_FRAMES_IX, + FW_VI_PF_STAT_RX_ERR_FRAMES_IX +}; + +struct fw_vi_stats_cmd { + __be32 op_to_viid; + __be32 retval_len16; + union fw_vi_stats { + struct fw_vi_stats_ctl { + __be16 nstats_ix; + __be16 r6; + __be32 r7; + __be64 stat0; + __be64 stat1; + __be64 stat2; + __be64 stat3; + __be64 stat4; + __be64 stat5; + } ctl; + struct fw_vi_stats_pf { + __be64 tx_bcast_bytes; + __be64 tx_bcast_frames; + __be64 tx_mcast_bytes; + __be64 tx_mcast_frames; + __be64 tx_ucast_bytes; + __be64 tx_ucast_frames; + __be64 tx_offload_bytes; + __be64 tx_offload_frames; + __be64 rx_pf_bytes; + __be64 rx_pf_frames; + __be64 rx_bcast_bytes; + __be64 rx_bcast_frames; + __be64 rx_mcast_bytes; + __be64 rx_mcast_frames; + __be64 rx_ucast_bytes; + __be64 rx_ucast_frames; + __be64 rx_err_frames; + } pf; + struct fw_vi_stats_vf { + __be64 tx_bcast_bytes; + __be64 tx_bcast_frames; + __be64 tx_mcast_bytes; + __be64 tx_mcast_frames; + __be64 tx_ucast_bytes; + __be64 tx_ucast_frames; + __be64 tx_drop_frames; + __be64 tx_offload_bytes; + __be64 tx_offload_frames; + __be64 rx_bcast_bytes; + __be64 rx_bcast_frames; + __be64 rx_mcast_bytes; + __be64 rx_mcast_frames; + __be64 rx_ucast_bytes; + __be64 rx_ucast_frames; + __be64 rx_err_frames; + } vf; + } u; +}; + +#define FW_VI_STATS_CMD_VIID(x) ((x) << 0) +#define FW_VI_STATS_CMD_NSTATS(x) ((x) << 12) +#define FW_VI_STATS_CMD_IX(x) ((x) << 0) + +struct fw_acl_mac_cmd { + __be32 op_to_vfn; + __be32 en_to_len16; + u8 nmac; + u8 r3[7]; + __be16 r4; + u8 macaddr0[6]; + __be16 r5; + u8 macaddr1[6]; + __be16 r6; + u8 macaddr2[6]; + __be16 r7; + u8 macaddr3[6]; +}; + +#define FW_ACL_MAC_CMD_PFN(x) ((x) << 8) +#define FW_ACL_MAC_CMD_VFN(x) ((x) << 0) +#define FW_ACL_MAC_CMD_EN(x) ((x) << 31) + +struct fw_acl_vlan_cmd { + __be32 op_to_vfn; + __be32 en_to_len16; + u8 nvlan; + u8 dropnovlan_fm; + u8 r3_lo[6]; + __be16 vlanid[16]; +}; + +#define FW_ACL_VLAN_CMD_PFN(x) ((x) << 8) +#define FW_ACL_VLAN_CMD_VFN(x) ((x) << 0) +#define FW_ACL_VLAN_CMD_EN(x) ((x) << 31) +#define FW_ACL_VLAN_CMD_DROPNOVLAN(x) ((x) << 7) +#define FW_ACL_VLAN_CMD_FM(x) ((x) << 6) + +enum fw_port_cap { + FW_PORT_CAP_SPEED_100M = 0x0001, + FW_PORT_CAP_SPEED_1G = 0x0002, + FW_PORT_CAP_SPEED_2_5G = 0x0004, + FW_PORT_CAP_SPEED_10G = 0x0008, + FW_PORT_CAP_SPEED_40G = 0x0010, + FW_PORT_CAP_SPEED_100G = 0x0020, + FW_PORT_CAP_FC_RX = 0x0040, + FW_PORT_CAP_FC_TX = 0x0080, + FW_PORT_CAP_ANEG = 0x0100, + FW_PORT_CAP_MDI_0 = 0x0200, + FW_PORT_CAP_MDI_1 = 0x0400, + FW_PORT_CAP_BEAN = 0x0800, + FW_PORT_CAP_PMA_LPBK = 0x1000, + FW_PORT_CAP_PCS_LPBK = 0x2000, + FW_PORT_CAP_PHYXS_LPBK = 0x4000, + FW_PORT_CAP_FAR_END_LPBK = 0x8000, +}; + +enum fw_port_mdi { + FW_PORT_MDI_UNCHANGED, + FW_PORT_MDI_AUTO, + FW_PORT_MDI_F_STRAIGHT, + FW_PORT_MDI_F_CROSSOVER +}; + +#define FW_PORT_MDI(x) ((x) << 9) + +enum fw_port_action { + FW_PORT_ACTION_L1_CFG = 0x0001, + FW_PORT_ACTION_L2_CFG = 0x0002, + FW_PORT_ACTION_GET_PORT_INFO = 0x0003, + FW_PORT_ACTION_L2_PPP_CFG = 0x0004, + FW_PORT_ACTION_L2_DCB_CFG = 0x0005, + FW_PORT_ACTION_LOW_PWR_TO_NORMAL = 0x0010, + FW_PORT_ACTION_L1_LOW_PWR_EN = 0x0011, + FW_PORT_ACTION_L2_WOL_MODE_EN = 0x0012, + FW_PORT_ACTION_LPBK_TO_NORMAL = 0x0020, + FW_PORT_ACTION_L1_LPBK = 0x0021, + FW_PORT_ACTION_L1_PMA_LPBK = 0x0022, + FW_PORT_ACTION_L1_PCS_LPBK = 0x0023, + FW_PORT_ACTION_L1_PHYXS_CSIDE_LPBK = 0x0024, + FW_PORT_ACTION_L1_PHYXS_ESIDE_LPBK = 0x0025, + FW_PORT_ACTION_PHY_RESET = 0x0040, + FW_PORT_ACTION_PMA_RESET = 0x0041, + FW_PORT_ACTION_PCS_RESET = 0x0042, + FW_PORT_ACTION_PHYXS_RESET = 0x0043, + FW_PORT_ACTION_DTEXS_REEST = 0x0044, + FW_PORT_ACTION_AN_RESET = 0x0045 +}; + +enum fw_port_l2cfg_ctlbf { + FW_PORT_L2_CTLBF_OVLAN0 = 0x01, + FW_PORT_L2_CTLBF_OVLAN1 = 0x02, + FW_PORT_L2_CTLBF_OVLAN2 = 0x04, + FW_PORT_L2_CTLBF_OVLAN3 = 0x08, + FW_PORT_L2_CTLBF_IVLAN = 0x10, + FW_PORT_L2_CTLBF_TXIPG = 0x20 +}; + +enum fw_port_dcb_cfg { + FW_PORT_DCB_CFG_PG = 0x01, + FW_PORT_DCB_CFG_PFC = 0x02, + FW_PORT_DCB_CFG_APPL = 0x04 +}; + +enum fw_port_dcb_cfg_rc { + FW_PORT_DCB_CFG_SUCCESS = 0x0, + FW_PORT_DCB_CFG_ERROR = 0x1 +}; + +struct fw_port_cmd { + __be32 op_to_portid; + __be32 action_to_len16; + union fw_port { + struct fw_port_l1cfg { + __be32 rcap; + __be32 r; + } l1cfg; + struct fw_port_l2cfg { + __be16 ctlbf_to_ivlan0; + __be16 ivlantype; + __be32 txipg_pkd; + __be16 ovlan0mask; + __be16 ovlan0type; + __be16 ovlan1mask; + __be16 ovlan1type; + __be16 ovlan2mask; + __be16 ovlan2type; + __be16 ovlan3mask; + __be16 ovlan3type; + } l2cfg; + struct fw_port_info { + __be32 lstatus_to_modtype; + __be16 pcap; + __be16 acap; + __be16 mtu; + __u8 cbllen; + __u8 r9; + __be32 r10; + __be64 r11; + } info; + struct fw_port_ppp { + __be32 pppen_to_ncsich; + __be32 r11; + } ppp; + struct fw_port_dcb { + __be16 cfg; + u8 up_map; + u8 sf_cfgrc; + __be16 prot_ix; + u8 pe7_to_pe0; + u8 numTCPFCs; + __be32 pgid0_to_pgid7; + __be32 numTCs_oui; + u8 pgpc[8]; + } dcb; + } u; +}; + +#define FW_PORT_CMD_READ (1U << 22) + +#define FW_PORT_CMD_PORTID(x) ((x) << 0) +#define FW_PORT_CMD_PORTID_GET(x) (((x) >> 0) & 0xf) + +#define FW_PORT_CMD_ACTION(x) ((x) << 16) +#define FW_PORT_CMD_ACTION_GET(x) (((x) >> 16) & 0xffff) + +#define FW_PORT_CMD_CTLBF(x) ((x) << 10) +#define FW_PORT_CMD_OVLAN3(x) ((x) << 7) +#define FW_PORT_CMD_OVLAN2(x) ((x) << 6) +#define FW_PORT_CMD_OVLAN1(x) ((x) << 5) +#define FW_PORT_CMD_OVLAN0(x) ((x) << 4) +#define FW_PORT_CMD_IVLAN0(x) ((x) << 3) + +#define FW_PORT_CMD_TXIPG(x) ((x) << 19) + +#define FW_PORT_CMD_LSTATUS (1U << 31) +#define FW_PORT_CMD_LSPEED(x) ((x) << 24) +#define FW_PORT_CMD_LSPEED_GET(x) (((x) >> 24) & 0x3f) +#define FW_PORT_CMD_TXPAUSE (1U << 23) +#define FW_PORT_CMD_RXPAUSE (1U << 22) +#define FW_PORT_CMD_MDIOCAP (1U << 21) +#define FW_PORT_CMD_MDIOADDR_GET(x) (((x) >> 16) & 0x1f) +#define FW_PORT_CMD_LPTXPAUSE (1U << 15) +#define FW_PORT_CMD_LPRXPAUSE (1U << 14) +#define FW_PORT_CMD_PTYPE_MASK 0x1f +#define FW_PORT_CMD_PTYPE_GET(x) (((x) >> 8) & FW_PORT_CMD_PTYPE_MASK) +#define FW_PORT_CMD_MODTYPE_MASK 0x1f +#define FW_PORT_CMD_MODTYPE_GET(x) (((x) >> 0) & FW_PORT_CMD_MODTYPE_MASK) + +#define FW_PORT_CMD_PPPEN(x) ((x) << 31) +#define FW_PORT_CMD_TPSRC(x) ((x) << 28) +#define FW_PORT_CMD_NCSISRC(x) ((x) << 24) + +#define FW_PORT_CMD_CH0(x) ((x) << 20) +#define FW_PORT_CMD_CH1(x) ((x) << 16) +#define FW_PORT_CMD_CH2(x) ((x) << 12) +#define FW_PORT_CMD_CH3(x) ((x) << 8) +#define FW_PORT_CMD_NCSICH(x) ((x) << 4) + +enum fw_port_type { + FW_PORT_TYPE_FIBER_XFI, + FW_PORT_TYPE_FIBER_XAUI, + FW_PORT_TYPE_BT_SGMII, + FW_PORT_TYPE_BT_XFI, + FW_PORT_TYPE_BT_XAUI, + FW_PORT_TYPE_KX4, + FW_PORT_TYPE_CX4, + FW_PORT_TYPE_KX, + FW_PORT_TYPE_KR, + FW_PORT_TYPE_SFP, + FW_PORT_TYPE_BP_AP, + FW_PORT_TYPE_BP4_AP, + + FW_PORT_TYPE_NONE = FW_PORT_CMD_PTYPE_MASK +}; + +enum fw_port_module_type { + FW_PORT_MOD_TYPE_NA, + FW_PORT_MOD_TYPE_LR, + FW_PORT_MOD_TYPE_SR, + FW_PORT_MOD_TYPE_ER, + FW_PORT_MOD_TYPE_TWINAX_PASSIVE, + FW_PORT_MOD_TYPE_TWINAX_ACTIVE, + FW_PORT_MOD_TYPE_LRM, + + FW_PORT_MOD_TYPE_NONE = FW_PORT_CMD_MODTYPE_MASK +}; + +/* port stats */ +#define FW_NUM_PORT_STATS 50 +#define FW_NUM_PORT_TX_STATS 23 +#define FW_NUM_PORT_RX_STATS 27 + +enum fw_port_stats_tx_index { + FW_STAT_TX_PORT_BYTES_IX, + FW_STAT_TX_PORT_FRAMES_IX, + FW_STAT_TX_PORT_BCAST_IX, + FW_STAT_TX_PORT_MCAST_IX, + FW_STAT_TX_PORT_UCAST_IX, + FW_STAT_TX_PORT_ERROR_IX, + FW_STAT_TX_PORT_64B_IX, + FW_STAT_TX_PORT_65B_127B_IX, + FW_STAT_TX_PORT_128B_255B_IX, + FW_STAT_TX_PORT_256B_511B_IX, + FW_STAT_TX_PORT_512B_1023B_IX, + FW_STAT_TX_PORT_1024B_1518B_IX, + FW_STAT_TX_PORT_1519B_MAX_IX, + FW_STAT_TX_PORT_DROP_IX, + FW_STAT_TX_PORT_PAUSE_IX, + FW_STAT_TX_PORT_PPP0_IX, + FW_STAT_TX_PORT_PPP1_IX, + FW_STAT_TX_PORT_PPP2_IX, + FW_STAT_TX_PORT_PPP3_IX, + FW_STAT_TX_PORT_PPP4_IX, + FW_STAT_TX_PORT_PPP5_IX, + FW_STAT_TX_PORT_PPP6_IX, + FW_STAT_TX_PORT_PPP7_IX +}; + +enum fw_port_stat_rx_index { + FW_STAT_RX_PORT_BYTES_IX, + FW_STAT_RX_PORT_FRAMES_IX, + FW_STAT_RX_PORT_BCAST_IX, + FW_STAT_RX_PORT_MCAST_IX, + FW_STAT_RX_PORT_UCAST_IX, + FW_STAT_RX_PORT_MTU_ERROR_IX, + FW_STAT_RX_PORT_MTU_CRC_ERROR_IX, + FW_STAT_RX_PORT_CRC_ERROR_IX, + FW_STAT_RX_PORT_LEN_ERROR_IX, + FW_STAT_RX_PORT_SYM_ERROR_IX, + FW_STAT_RX_PORT_64B_IX, + FW_STAT_RX_PORT_65B_127B_IX, + FW_STAT_RX_PORT_128B_255B_IX, + FW_STAT_RX_PORT_256B_511B_IX, + FW_STAT_RX_PORT_512B_1023B_IX, + FW_STAT_RX_PORT_1024B_1518B_IX, + FW_STAT_RX_PORT_1519B_MAX_IX, + FW_STAT_RX_PORT_PAUSE_IX, + FW_STAT_RX_PORT_PPP0_IX, + FW_STAT_RX_PORT_PPP1_IX, + FW_STAT_RX_PORT_PPP2_IX, + FW_STAT_RX_PORT_PPP3_IX, + FW_STAT_RX_PORT_PPP4_IX, + FW_STAT_RX_PORT_PPP5_IX, + FW_STAT_RX_PORT_PPP6_IX, + FW_STAT_RX_PORT_PPP7_IX, + FW_STAT_RX_PORT_LESS_64B_IX +}; + +struct fw_port_stats_cmd { + __be32 op_to_portid; + __be32 retval_len16; + union fw_port_stats { + struct fw_port_stats_ctl { + u8 nstats_bg_bm; + u8 tx_ix; + __be16 r6; + __be32 r7; + __be64 stat0; + __be64 stat1; + __be64 stat2; + __be64 stat3; + __be64 stat4; + __be64 stat5; + } ctl; + struct fw_port_stats_all { + __be64 tx_bytes; + __be64 tx_frames; + __be64 tx_bcast; + __be64 tx_mcast; + __be64 tx_ucast; + __be64 tx_error; + __be64 tx_64b; + __be64 tx_65b_127b; + __be64 tx_128b_255b; + __be64 tx_256b_511b; + __be64 tx_512b_1023b; + __be64 tx_1024b_1518b; + __be64 tx_1519b_max; + __be64 tx_drop; + __be64 tx_pause; + __be64 tx_ppp0; + __be64 tx_ppp1; + __be64 tx_ppp2; + __be64 tx_ppp3; + __be64 tx_ppp4; + __be64 tx_ppp5; + __be64 tx_ppp6; + __be64 tx_ppp7; + __be64 rx_bytes; + __be64 rx_frames; + __be64 rx_bcast; + __be64 rx_mcast; + __be64 rx_ucast; + __be64 rx_mtu_error; + __be64 rx_mtu_crc_error; + __be64 rx_crc_error; + __be64 rx_len_error; + __be64 rx_sym_error; + __be64 rx_64b; + __be64 rx_65b_127b; + __be64 rx_128b_255b; + __be64 rx_256b_511b; + __be64 rx_512b_1023b; + __be64 rx_1024b_1518b; + __be64 rx_1519b_max; + __be64 rx_pause; + __be64 rx_ppp0; + __be64 rx_ppp1; + __be64 rx_ppp2; + __be64 rx_ppp3; + __be64 rx_ppp4; + __be64 rx_ppp5; + __be64 rx_ppp6; + __be64 rx_ppp7; + __be64 rx_less_64b; + __be64 rx_bg_drop; + __be64 rx_bg_trunc; + } all; + } u; +}; + +#define FW_PORT_STATS_CMD_NSTATS(x) ((x) << 4) +#define FW_PORT_STATS_CMD_BG_BM(x) ((x) << 0) +#define FW_PORT_STATS_CMD_TX(x) ((x) << 7) +#define FW_PORT_STATS_CMD_IX(x) ((x) << 0) + +/* port loopback stats */ +#define FW_NUM_LB_STATS 16 +enum fw_port_lb_stats_index { + FW_STAT_LB_PORT_BYTES_IX, + FW_STAT_LB_PORT_FRAMES_IX, + FW_STAT_LB_PORT_BCAST_IX, + FW_STAT_LB_PORT_MCAST_IX, + FW_STAT_LB_PORT_UCAST_IX, + FW_STAT_LB_PORT_ERROR_IX, + FW_STAT_LB_PORT_64B_IX, + FW_STAT_LB_PORT_65B_127B_IX, + FW_STAT_LB_PORT_128B_255B_IX, + FW_STAT_LB_PORT_256B_511B_IX, + FW_STAT_LB_PORT_512B_1023B_IX, + FW_STAT_LB_PORT_1024B_1518B_IX, + FW_STAT_LB_PORT_1519B_MAX_IX, + FW_STAT_LB_PORT_DROP_FRAMES_IX +}; + +struct fw_port_lb_stats_cmd { + __be32 op_to_lbport; + __be32 retval_len16; + union fw_port_lb_stats { + struct fw_port_lb_stats_ctl { + u8 nstats_bg_bm; + u8 ix_pkd; + __be16 r6; + __be32 r7; + __be64 stat0; + __be64 stat1; + __be64 stat2; + __be64 stat3; + __be64 stat4; + __be64 stat5; + } ctl; + struct fw_port_lb_stats_all { + __be64 tx_bytes; + __be64 tx_frames; + __be64 tx_bcast; + __be64 tx_mcast; + __be64 tx_ucast; + __be64 tx_error; + __be64 tx_64b; + __be64 tx_65b_127b; + __be64 tx_128b_255b; + __be64 tx_256b_511b; + __be64 tx_512b_1023b; + __be64 tx_1024b_1518b; + __be64 tx_1519b_max; + __be64 rx_lb_drop; + __be64 rx_lb_trunc; + } all; + } u; +}; + +#define FW_PORT_LB_STATS_CMD_LBPORT(x) ((x) << 0) +#define FW_PORT_LB_STATS_CMD_NSTATS(x) ((x) << 4) +#define FW_PORT_LB_STATS_CMD_BG_BM(x) ((x) << 0) +#define FW_PORT_LB_STATS_CMD_IX(x) ((x) << 0) + +struct fw_rss_ind_tbl_cmd { + __be32 op_to_viid; +#define FW_RSS_IND_TBL_CMD_VIID(x) ((x) << 0) + __be32 retval_len16; + __be16 niqid; + __be16 startidx; + __be32 r3; + __be32 iq0_to_iq2; +#define FW_RSS_IND_TBL_CMD_IQ0(x) ((x) << 20) +#define FW_RSS_IND_TBL_CMD_IQ1(x) ((x) << 10) +#define FW_RSS_IND_TBL_CMD_IQ2(x) ((x) << 0) + __be32 iq3_to_iq5; + __be32 iq6_to_iq8; + __be32 iq9_to_iq11; + __be32 iq12_to_iq14; + __be32 iq15_to_iq17; + __be32 iq18_to_iq20; + __be32 iq21_to_iq23; + __be32 iq24_to_iq26; + __be32 iq27_to_iq29; + __be32 iq30_iq31; + __be32 r15_lo; +}; + +struct fw_rss_glb_config_cmd { + __be32 op_to_write; + __be32 retval_len16; + union fw_rss_glb_config { + struct fw_rss_glb_config_manual { + __be32 mode_pkd; + __be32 r3; + __be64 r4; + __be64 r5; + } manual; + struct fw_rss_glb_config_basicvirtual { + __be32 mode_pkd; + __be32 synmapen_to_hashtoeplitz; +#define FW_RSS_GLB_CONFIG_CMD_SYNMAPEN (1U << 8) +#define FW_RSS_GLB_CONFIG_CMD_SYN4TUPENIPV6 (1U << 7) +#define FW_RSS_GLB_CONFIG_CMD_SYN2TUPENIPV6 (1U << 6) +#define FW_RSS_GLB_CONFIG_CMD_SYN4TUPENIPV4 (1U << 5) +#define FW_RSS_GLB_CONFIG_CMD_SYN2TUPENIPV4 (1U << 4) +#define FW_RSS_GLB_CONFIG_CMD_OFDMAPEN (1U << 3) +#define FW_RSS_GLB_CONFIG_CMD_TNLMAPEN (1U << 2) +#define FW_RSS_GLB_CONFIG_CMD_TNLALLLKP (1U << 1) +#define FW_RSS_GLB_CONFIG_CMD_HASHTOEPLITZ (1U << 0) + __be64 r8; + __be64 r9; + } basicvirtual; + } u; +}; + +#define FW_RSS_GLB_CONFIG_CMD_MODE(x) ((x) << 28) +#define FW_RSS_GLB_CONFIG_CMD_MODE_GET(x) (((x) >> 28) & 0xf) + +#define FW_RSS_GLB_CONFIG_CMD_MODE_MANUAL 0 +#define FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL 1 + +struct fw_rss_vi_config_cmd { + __be32 op_to_viid; +#define FW_RSS_VI_CONFIG_CMD_VIID(x) ((x) << 0) + __be32 retval_len16; + union fw_rss_vi_config { + struct fw_rss_vi_config_manual { + __be64 r3; + __be64 r4; + __be64 r5; + } manual; + struct fw_rss_vi_config_basicvirtual { + __be32 r6; + __be32 defaultq_to_udpen; +#define FW_RSS_VI_CONFIG_CMD_DEFAULTQ(x) ((x) << 16) +#define FW_RSS_VI_CONFIG_CMD_DEFAULTQ_GET(x) (((x) >> 16) & 0x3ff) +#define FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN (1U << 4) +#define FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN (1U << 3) +#define FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN (1U << 2) +#define FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN (1U << 1) +#define FW_RSS_VI_CONFIG_CMD_UDPEN (1U << 0) + __be64 r9; + __be64 r10; + } basicvirtual; + } u; +}; + +enum fw_error_type { + FW_ERROR_TYPE_EXCEPTION = 0x0, + FW_ERROR_TYPE_HWMODULE = 0x1, + FW_ERROR_TYPE_WR = 0x2, + FW_ERROR_TYPE_ACL = 0x3, +}; + +struct fw_error_cmd { + __be32 op_to_type; + __be32 len16_pkd; + union fw_error { + struct fw_error_exception { + __be32 info[6]; + } exception; + struct fw_error_hwmodule { + __be32 regaddr; + __be32 regval; + } hwmodule; + struct fw_error_wr { + __be16 cidx; + __be16 pfn_vfn; + __be32 eqid; + u8 wrhdr[16]; + } wr; + struct fw_error_acl { + __be16 cidx; + __be16 pfn_vfn; + __be32 eqid; + __be16 mv_pkd; + u8 val[6]; + __be64 r4; + } acl; + } u; +}; + +struct fw_debug_cmd { + __be32 op_type; +#define FW_DEBUG_CMD_TYPE_GET(x) ((x) & 0xff) + __be32 len16_pkd; + union fw_debug { + struct fw_debug_assert { + __be32 fcid; + __be32 line; + __be32 x; + __be32 y; + u8 filename_0_7[8]; + u8 filename_8_15[8]; + __be64 r3; + } assert; + struct fw_debug_prt { + __be16 dprtstridx; + __be16 r3[3]; + __be32 dprtstrparam0; + __be32 dprtstrparam1; + __be32 dprtstrparam2; + __be32 dprtstrparam3; + } prt; + } u; +}; + +struct fw_hdr { + u8 ver; + u8 reserved1; + __be16 len512; /* bin length in units of 512-bytes */ + __be32 fw_ver; /* firmware version */ + __be32 tp_microcode_ver; + u8 intfver_nic; + u8 intfver_vnic; + u8 intfver_ofld; + u8 intfver_ri; + u8 intfver_iscsipdu; + u8 intfver_iscsi; + u8 intfver_fcoe; + u8 reserved2; + __be32 reserved3[27]; +}; + +#define FW_HDR_FW_VER_MAJOR_GET(x) (((x) >> 24) & 0xff) +#define FW_HDR_FW_VER_MINOR_GET(x) (((x) >> 16) & 0xff) +#define FW_HDR_FW_VER_MICRO_GET(x) (((x) >> 8) & 0xff) +#define FW_HDR_FW_VER_BUILD_GET(x) (((x) >> 0) & 0xff) +#endif /* _T4FW_INTERFACE_H_ */ diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/Makefile b/drivers/net/ethernet/chelsio/cxgb4vf/Makefile new file mode 100644 index 000000000000..d72ee26cb4c7 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4vf/Makefile @@ -0,0 +1,7 @@ +# +# Chelsio T4 SR-IOV Virtual Function Driver +# + +obj-$(CONFIG_CHELSIO_T4VF) += cxgb4vf.o + +cxgb4vf-objs := cxgb4vf_main.o t4vf_hw.o sge.o diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h b/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h new file mode 100644 index 000000000000..594334d5c711 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h @@ -0,0 +1,534 @@ +/* + * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet + * driver for Linux. + * + * Copyright (c) 2009-2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * This file should not be included directly. Include t4vf_common.h instead. + */ + +#ifndef __CXGB4VF_ADAPTER_H__ +#define __CXGB4VF_ADAPTER_H__ + +#include +#include +#include +#include +#include +#include + +#include "../cxgb4/t4_hw.h" + +/* + * Constants of the implementation. + */ +enum { + MAX_NPORTS = 1, /* max # of "ports" */ + MAX_PORT_QSETS = 8, /* max # of Queue Sets / "port" */ + MAX_ETH_QSETS = MAX_NPORTS*MAX_PORT_QSETS, + + /* + * MSI-X interrupt index usage. + */ + MSIX_FW = 0, /* MSI-X index for firmware Q */ + MSIX_IQFLINT = 1, /* MSI-X index base for Ingress Qs */ + MSIX_EXTRAS = 1, + MSIX_ENTRIES = MAX_ETH_QSETS + MSIX_EXTRAS, + + /* + * The maximum number of Ingress and Egress Queues is determined by + * the maximum number of "Queue Sets" which we support plus any + * ancillary queues. Each "Queue Set" requires one Ingress Queue + * for RX Packet Ingress Event notifications and two Egress Queues for + * a Free List and an Ethernet TX list. + */ + INGQ_EXTRAS = 2, /* firmware event queue and */ + /* forwarded interrupts */ + MAX_INGQ = MAX_ETH_QSETS+INGQ_EXTRAS, + MAX_EGRQ = MAX_ETH_QSETS*2, +}; + +/* + * Forward structure definition references. + */ +struct adapter; +struct sge_eth_rxq; +struct sge_rspq; + +/* + * Per-"port" information. This is really per-Virtual Interface information + * but the use of the "port" nomanclature makes it easier to go back and forth + * between the PF and VF drivers ... + */ +struct port_info { + struct adapter *adapter; /* our adapter */ + u16 viid; /* virtual interface ID */ + s16 xact_addr_filt; /* index of our MAC address filter */ + u16 rss_size; /* size of VI's RSS table slice */ + u8 pidx; /* index into adapter port[] */ + u8 port_id; /* physical port ID */ + u8 nqsets; /* # of "Queue Sets" */ + u8 first_qset; /* index of first "Queue Set" */ + struct link_config link_cfg; /* physical port configuration */ +}; + +/* + * Scatter Gather Engine resources for the "adapter". Our ingress and egress + * queues are organized into "Queue Sets" with one ingress and one egress + * queue per Queue Set. These Queue Sets are aportionable between the "ports" + * (Virtual Interfaces). One extra ingress queue is used to receive + * asynchronous messages from the firmware. Note that the "Queue IDs" that we + * use here are really "Relative Queue IDs" which are returned as part of the + * firmware command to allocate queues. These queue IDs are relative to the + * absolute Queue ID base of the section of the Queue ID space allocated to + * the PF/VF. + */ + +/* + * SGE free-list queue state. + */ +struct rx_sw_desc; +struct sge_fl { + unsigned int avail; /* # of available RX buffers */ + unsigned int pend_cred; /* new buffers since last FL DB ring */ + unsigned int cidx; /* consumer index */ + unsigned int pidx; /* producer index */ + unsigned long alloc_failed; /* # of buffer allocation failures */ + unsigned long large_alloc_failed; + unsigned long starving; /* # of times FL was found starving */ + + /* + * Write-once/infrequently fields. + * ------------------------------- + */ + + unsigned int cntxt_id; /* SGE relative QID for the free list */ + unsigned int abs_id; /* SGE absolute QID for the free list */ + unsigned int size; /* capacity of free list */ + struct rx_sw_desc *sdesc; /* address of SW RX descriptor ring */ + __be64 *desc; /* address of HW RX descriptor ring */ + dma_addr_t addr; /* PCI bus address of hardware ring */ +}; + +/* + * An ingress packet gather list. + */ +struct pkt_gl { + skb_frag_t frags[MAX_SKB_FRAGS]; + void *va; /* virtual address of first byte */ + unsigned int nfrags; /* # of fragments */ + unsigned int tot_len; /* total length of fragments */ +}; + +typedef int (*rspq_handler_t)(struct sge_rspq *, const __be64 *, + const struct pkt_gl *); + +/* + * State for an SGE Response Queue. + */ +struct sge_rspq { + struct napi_struct napi; /* NAPI scheduling control */ + const __be64 *cur_desc; /* current descriptor in queue */ + unsigned int cidx; /* consumer index */ + u8 gen; /* current generation bit */ + u8 next_intr_params; /* holdoff params for next interrupt */ + int offset; /* offset into current FL buffer */ + + unsigned int unhandled_irqs; /* bogus interrupts */ + + /* + * Write-once/infrequently fields. + * ------------------------------- + */ + + u8 intr_params; /* interrupt holdoff parameters */ + u8 pktcnt_idx; /* interrupt packet threshold */ + u8 idx; /* queue index within its group */ + u16 cntxt_id; /* SGE rel QID for the response Q */ + u16 abs_id; /* SGE abs QID for the response Q */ + __be64 *desc; /* address of hardware response ring */ + dma_addr_t phys_addr; /* PCI bus address of ring */ + unsigned int iqe_len; /* entry size */ + unsigned int size; /* capcity of response Q */ + struct adapter *adapter; /* our adapter */ + struct net_device *netdev; /* associated net device */ + rspq_handler_t handler; /* the handler for this response Q */ +}; + +/* + * Ethernet queue statistics + */ +struct sge_eth_stats { + unsigned long pkts; /* # of ethernet packets */ + unsigned long lro_pkts; /* # of LRO super packets */ + unsigned long lro_merged; /* # of wire packets merged by LRO */ + unsigned long rx_cso; /* # of Rx checksum offloads */ + unsigned long vlan_ex; /* # of Rx VLAN extractions */ + unsigned long rx_drops; /* # of packets dropped due to no mem */ +}; + +/* + * State for an Ethernet Receive Queue. + */ +struct sge_eth_rxq { + struct sge_rspq rspq; /* Response Queue */ + struct sge_fl fl; /* Free List */ + struct sge_eth_stats stats; /* receive statistics */ +}; + +/* + * SGE Transmit Queue state. This contains all of the resources associated + * with the hardware status of a TX Queue which is a circular ring of hardware + * TX Descriptors. For convenience, it also contains a pointer to a parallel + * "Software Descriptor" array but we don't know anything about it here other + * than its type name. + */ +struct tx_desc { + /* + * Egress Queues are measured in units of SGE_EQ_IDXSIZE by the + * hardware: Sizes, Producer and Consumer indices, etc. + */ + __be64 flit[SGE_EQ_IDXSIZE/sizeof(__be64)]; +}; +struct tx_sw_desc; +struct sge_txq { + unsigned int in_use; /* # of in-use TX descriptors */ + unsigned int size; /* # of descriptors */ + unsigned int cidx; /* SW consumer index */ + unsigned int pidx; /* producer index */ + unsigned long stops; /* # of times queue has been stopped */ + unsigned long restarts; /* # of queue restarts */ + + /* + * Write-once/infrequently fields. + * ------------------------------- + */ + + unsigned int cntxt_id; /* SGE relative QID for the TX Q */ + unsigned int abs_id; /* SGE absolute QID for the TX Q */ + struct tx_desc *desc; /* address of HW TX descriptor ring */ + struct tx_sw_desc *sdesc; /* address of SW TX descriptor ring */ + struct sge_qstat *stat; /* queue status entry */ + dma_addr_t phys_addr; /* PCI bus address of hardware ring */ +}; + +/* + * State for an Ethernet Transmit Queue. + */ +struct sge_eth_txq { + struct sge_txq q; /* SGE TX Queue */ + struct netdev_queue *txq; /* associated netdev TX queue */ + unsigned long tso; /* # of TSO requests */ + unsigned long tx_cso; /* # of TX checksum offloads */ + unsigned long vlan_ins; /* # of TX VLAN insertions */ + unsigned long mapping_err; /* # of I/O MMU packet mapping errors */ +}; + +/* + * The complete set of Scatter/Gather Engine resources. + */ +struct sge { + /* + * Our "Queue Sets" ... + */ + struct sge_eth_txq ethtxq[MAX_ETH_QSETS]; + struct sge_eth_rxq ethrxq[MAX_ETH_QSETS]; + + /* + * Extra ingress queues for asynchronous firmware events and + * forwarded interrupts (when in MSI mode). + */ + struct sge_rspq fw_evtq ____cacheline_aligned_in_smp; + + struct sge_rspq intrq ____cacheline_aligned_in_smp; + spinlock_t intrq_lock; + + /* + * State for managing "starving Free Lists" -- Free Lists which have + * fallen below a certain threshold of buffers available to the + * hardware and attempts to refill them up to that threshold have + * failed. We have a regular "slow tick" timer process which will + * make periodic attempts to refill these starving Free Lists ... + */ + DECLARE_BITMAP(starving_fl, MAX_EGRQ); + struct timer_list rx_timer; + + /* + * State for cleaning up completed TX descriptors. + */ + struct timer_list tx_timer; + + /* + * Write-once/infrequently fields. + * ------------------------------- + */ + + u16 max_ethqsets; /* # of available Ethernet queue sets */ + u16 ethqsets; /* # of active Ethernet queue sets */ + u16 ethtxq_rover; /* Tx queue to clean up next */ + u16 timer_val[SGE_NTIMERS]; /* interrupt holdoff timer array */ + u8 counter_val[SGE_NCOUNTERS]; /* interrupt RX threshold array */ + + /* + * Reverse maps from Absolute Queue IDs to associated queue pointers. + * The absolute Queue IDs are in a compact range which start at a + * [potentially large] Base Queue ID. We perform the reverse map by + * first converting the Absolute Queue ID into a Relative Queue ID by + * subtracting off the Base Queue ID and then use a Relative Queue ID + * indexed table to get the pointer to the corresponding software + * queue structure. + */ + unsigned int egr_base; + unsigned int ingr_base; + void *egr_map[MAX_EGRQ]; + struct sge_rspq *ingr_map[MAX_INGQ]; +}; + +/* + * Utility macros to convert Absolute- to Relative-Queue indices and Egress- + * and Ingress-Queues. The EQ_MAP() and IQ_MAP() macros which provide + * pointers to Ingress- and Egress-Queues can be used as both L- and R-values + */ +#define EQ_IDX(s, abs_id) ((unsigned int)((abs_id) - (s)->egr_base)) +#define IQ_IDX(s, abs_id) ((unsigned int)((abs_id) - (s)->ingr_base)) + +#define EQ_MAP(s, abs_id) ((s)->egr_map[EQ_IDX(s, abs_id)]) +#define IQ_MAP(s, abs_id) ((s)->ingr_map[IQ_IDX(s, abs_id)]) + +/* + * Macro to iterate across Queue Sets ("rxq" is a historic misnomer). + */ +#define for_each_ethrxq(sge, iter) \ + for (iter = 0; iter < (sge)->ethqsets; iter++) + +/* + * Per-"adapter" (Virtual Function) information. + */ +struct adapter { + /* PCI resources */ + void __iomem *regs; + struct pci_dev *pdev; + struct device *pdev_dev; + + /* "adapter" resources */ + unsigned long registered_device_map; + unsigned long open_device_map; + unsigned long flags; + struct adapter_params params; + + /* queue and interrupt resources */ + struct { + unsigned short vec; + char desc[22]; + } msix_info[MSIX_ENTRIES]; + struct sge sge; + + /* Linux network device resources */ + struct net_device *port[MAX_NPORTS]; + const char *name; + unsigned int msg_enable; + + /* debugfs resources */ + struct dentry *debugfs_root; + + /* various locks */ + spinlock_t stats_lock; +}; + +enum { /* adapter flags */ + FULL_INIT_DONE = (1UL << 0), + USING_MSI = (1UL << 1), + USING_MSIX = (1UL << 2), + QUEUES_BOUND = (1UL << 3), +}; + +/* + * The following register read/write routine definitions are required by + * the common code. + */ + +/** + * t4_read_reg - read a HW register + * @adapter: the adapter + * @reg_addr: the register address + * + * Returns the 32-bit value of the given HW register. + */ +static inline u32 t4_read_reg(struct adapter *adapter, u32 reg_addr) +{ + return readl(adapter->regs + reg_addr); +} + +/** + * t4_write_reg - write a HW register + * @adapter: the adapter + * @reg_addr: the register address + * @val: the value to write + * + * Write a 32-bit value into the given HW register. + */ +static inline void t4_write_reg(struct adapter *adapter, u32 reg_addr, u32 val) +{ + writel(val, adapter->regs + reg_addr); +} + +#ifndef readq +static inline u64 readq(const volatile void __iomem *addr) +{ + return readl(addr) + ((u64)readl(addr + 4) << 32); +} + +static inline void writeq(u64 val, volatile void __iomem *addr) +{ + writel(val, addr); + writel(val >> 32, addr + 4); +} +#endif + +/** + * t4_read_reg64 - read a 64-bit HW register + * @adapter: the adapter + * @reg_addr: the register address + * + * Returns the 64-bit value of the given HW register. + */ +static inline u64 t4_read_reg64(struct adapter *adapter, u32 reg_addr) +{ + return readq(adapter->regs + reg_addr); +} + +/** + * t4_write_reg64 - write a 64-bit HW register + * @adapter: the adapter + * @reg_addr: the register address + * @val: the value to write + * + * Write a 64-bit value into the given HW register. + */ +static inline void t4_write_reg64(struct adapter *adapter, u32 reg_addr, + u64 val) +{ + writeq(val, adapter->regs + reg_addr); +} + +/** + * port_name - return the string name of a port + * @adapter: the adapter + * @pidx: the port index + * + * Return the string name of the selected port. + */ +static inline const char *port_name(struct adapter *adapter, int pidx) +{ + return adapter->port[pidx]->name; +} + +/** + * t4_os_set_hw_addr - store a port's MAC address in SW + * @adapter: the adapter + * @pidx: the port index + * @hw_addr: the Ethernet address + * + * Store the Ethernet address of the given port in SW. Called by the common + * code when it retrieves a port's Ethernet address from EEPROM. + */ +static inline void t4_os_set_hw_addr(struct adapter *adapter, int pidx, + u8 hw_addr[]) +{ + memcpy(adapter->port[pidx]->dev_addr, hw_addr, ETH_ALEN); + memcpy(adapter->port[pidx]->perm_addr, hw_addr, ETH_ALEN); +} + +/** + * netdev2pinfo - return the port_info structure associated with a net_device + * @dev: the netdev + * + * Return the struct port_info associated with a net_device + */ +static inline struct port_info *netdev2pinfo(const struct net_device *dev) +{ + return netdev_priv(dev); +} + +/** + * adap2pinfo - return the port_info of a port + * @adap: the adapter + * @pidx: the port index + * + * Return the port_info structure for the adapter. + */ +static inline struct port_info *adap2pinfo(struct adapter *adapter, int pidx) +{ + return netdev_priv(adapter->port[pidx]); +} + +/** + * netdev2adap - return the adapter structure associated with a net_device + * @dev: the netdev + * + * Return the struct adapter associated with a net_device + */ +static inline struct adapter *netdev2adap(const struct net_device *dev) +{ + return netdev2pinfo(dev)->adapter; +} + +/* + * OS "Callback" function declarations. These are functions that the OS code + * is "contracted" to provide for the common code. + */ +void t4vf_os_link_changed(struct adapter *, int, int); + +/* + * SGE function prototype declarations. + */ +int t4vf_sge_alloc_rxq(struct adapter *, struct sge_rspq *, bool, + struct net_device *, int, + struct sge_fl *, rspq_handler_t); +int t4vf_sge_alloc_eth_txq(struct adapter *, struct sge_eth_txq *, + struct net_device *, struct netdev_queue *, + unsigned int); +void t4vf_free_sge_resources(struct adapter *); + +int t4vf_eth_xmit(struct sk_buff *, struct net_device *); +int t4vf_ethrx_handler(struct sge_rspq *, const __be64 *, + const struct pkt_gl *); + +irq_handler_t t4vf_intr_handler(struct adapter *); +irqreturn_t t4vf_sge_intr_msix(int, void *); + +int t4vf_sge_init(struct adapter *); +void t4vf_sge_start(struct adapter *); +void t4vf_sge_stop(struct adapter *); + +#endif /* __CXGB4VF_ADAPTER_H__ */ diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c new file mode 100644 index 000000000000..ec799139dfe2 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c @@ -0,0 +1,2947 @@ +/* + * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet + * driver for Linux. + * + * Copyright (c) 2009-2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "t4vf_common.h" +#include "t4vf_defs.h" + +#include "../cxgb4/t4_regs.h" +#include "../cxgb4/t4_msg.h" + +/* + * Generic information about the driver. + */ +#define DRV_VERSION "1.0.0" +#define DRV_DESC "Chelsio T4 Virtual Function (VF) Network Driver" + +/* + * Module Parameters. + * ================== + */ + +/* + * Default ethtool "message level" for adapters. + */ +#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \ + NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\ + NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) + +static int dflt_msg_enable = DFLT_MSG_ENABLE; + +module_param(dflt_msg_enable, int, 0644); +MODULE_PARM_DESC(dflt_msg_enable, + "default adapter ethtool message level bitmap"); + +/* + * The driver uses the best interrupt scheme available on a platform in the + * order MSI-X then MSI. This parameter determines which of these schemes the + * driver may consider as follows: + * + * msi = 2: choose from among MSI-X and MSI + * msi = 1: only consider MSI interrupts + * + * Note that unlike the Physical Function driver, this Virtual Function driver + * does _not_ support legacy INTx interrupts (this limitation is mandated by + * the PCI-E SR-IOV standard). + */ +#define MSI_MSIX 2 +#define MSI_MSI 1 +#define MSI_DEFAULT MSI_MSIX + +static int msi = MSI_DEFAULT; + +module_param(msi, int, 0644); +MODULE_PARM_DESC(msi, "whether to use MSI-X or MSI"); + +/* + * Fundamental constants. + * ====================== + */ + +enum { + MAX_TXQ_ENTRIES = 16384, + MAX_RSPQ_ENTRIES = 16384, + MAX_RX_BUFFERS = 16384, + + MIN_TXQ_ENTRIES = 32, + MIN_RSPQ_ENTRIES = 128, + MIN_FL_ENTRIES = 16, + + /* + * For purposes of manipulating the Free List size we need to + * recognize that Free Lists are actually Egress Queues (the host + * produces free buffers which the hardware consumes), Egress Queues + * indices are all in units of Egress Context Units bytes, and free + * list entries are 64-bit PCI DMA addresses. And since the state of + * the Producer Index == the Consumer Index implies an EMPTY list, we + * always have at least one Egress Unit's worth of Free List entries + * unused. See sge.c for more details ... + */ + EQ_UNIT = SGE_EQ_IDXSIZE, + FL_PER_EQ_UNIT = EQ_UNIT / sizeof(__be64), + MIN_FL_RESID = FL_PER_EQ_UNIT, +}; + +/* + * Global driver state. + * ==================== + */ + +static struct dentry *cxgb4vf_debugfs_root; + +/* + * OS "Callback" functions. + * ======================== + */ + +/* + * The link status has changed on the indicated "port" (Virtual Interface). + */ +void t4vf_os_link_changed(struct adapter *adapter, int pidx, int link_ok) +{ + struct net_device *dev = adapter->port[pidx]; + + /* + * If the port is disabled or the current recorded "link up" + * status matches the new status, just return. + */ + if (!netif_running(dev) || link_ok == netif_carrier_ok(dev)) + return; + + /* + * Tell the OS that the link status has changed and print a short + * informative message on the console about the event. + */ + if (link_ok) { + const char *s; + const char *fc; + const struct port_info *pi = netdev_priv(dev); + + netif_carrier_on(dev); + + switch (pi->link_cfg.speed) { + case SPEED_10000: + s = "10Gbps"; + break; + + case SPEED_1000: + s = "1000Mbps"; + break; + + case SPEED_100: + s = "100Mbps"; + break; + + default: + s = "unknown"; + break; + } + + switch (pi->link_cfg.fc) { + case PAUSE_RX: + fc = "RX"; + break; + + case PAUSE_TX: + fc = "TX"; + break; + + case PAUSE_RX|PAUSE_TX: + fc = "RX/TX"; + break; + + default: + fc = "no"; + break; + } + + printk(KERN_INFO "%s: link up, %s, full-duplex, %s PAUSE\n", + dev->name, s, fc); + } else { + netif_carrier_off(dev); + printk(KERN_INFO "%s: link down\n", dev->name); + } +} + +/* + * Net device operations. + * ====================== + */ + + + + +/* + * Perform the MAC and PHY actions needed to enable a "port" (Virtual + * Interface). + */ +static int link_start(struct net_device *dev) +{ + int ret; + struct port_info *pi = netdev_priv(dev); + + /* + * We do not set address filters and promiscuity here, the stack does + * that step explicitly. Enable vlan accel. + */ + ret = t4vf_set_rxmode(pi->adapter, pi->viid, dev->mtu, -1, -1, -1, 1, + true); + if (ret == 0) { + ret = t4vf_change_mac(pi->adapter, pi->viid, + pi->xact_addr_filt, dev->dev_addr, true); + if (ret >= 0) { + pi->xact_addr_filt = ret; + ret = 0; + } + } + + /* + * We don't need to actually "start the link" itself since the + * firmware will do that for us when the first Virtual Interface + * is enabled on a port. + */ + if (ret == 0) + ret = t4vf_enable_vi(pi->adapter, pi->viid, true, true); + return ret; +} + +/* + * Name the MSI-X interrupts. + */ +static void name_msix_vecs(struct adapter *adapter) +{ + int namelen = sizeof(adapter->msix_info[0].desc) - 1; + int pidx; + + /* + * Firmware events. + */ + snprintf(adapter->msix_info[MSIX_FW].desc, namelen, + "%s-FWeventq", adapter->name); + adapter->msix_info[MSIX_FW].desc[namelen] = 0; + + /* + * Ethernet queues. + */ + for_each_port(adapter, pidx) { + struct net_device *dev = adapter->port[pidx]; + const struct port_info *pi = netdev_priv(dev); + int qs, msi; + + for (qs = 0, msi = MSIX_IQFLINT; qs < pi->nqsets; qs++, msi++) { + snprintf(adapter->msix_info[msi].desc, namelen, + "%s-%d", dev->name, qs); + adapter->msix_info[msi].desc[namelen] = 0; + } + } +} + +/* + * Request all of our MSI-X resources. + */ +static int request_msix_queue_irqs(struct adapter *adapter) +{ + struct sge *s = &adapter->sge; + int rxq, msi, err; + + /* + * Firmware events. + */ + err = request_irq(adapter->msix_info[MSIX_FW].vec, t4vf_sge_intr_msix, + 0, adapter->msix_info[MSIX_FW].desc, &s->fw_evtq); + if (err) + return err; + + /* + * Ethernet queues. + */ + msi = MSIX_IQFLINT; + for_each_ethrxq(s, rxq) { + err = request_irq(adapter->msix_info[msi].vec, + t4vf_sge_intr_msix, 0, + adapter->msix_info[msi].desc, + &s->ethrxq[rxq].rspq); + if (err) + goto err_free_irqs; + msi++; + } + return 0; + +err_free_irqs: + while (--rxq >= 0) + free_irq(adapter->msix_info[--msi].vec, &s->ethrxq[rxq].rspq); + free_irq(adapter->msix_info[MSIX_FW].vec, &s->fw_evtq); + return err; +} + +/* + * Free our MSI-X resources. + */ +static void free_msix_queue_irqs(struct adapter *adapter) +{ + struct sge *s = &adapter->sge; + int rxq, msi; + + free_irq(adapter->msix_info[MSIX_FW].vec, &s->fw_evtq); + msi = MSIX_IQFLINT; + for_each_ethrxq(s, rxq) + free_irq(adapter->msix_info[msi++].vec, + &s->ethrxq[rxq].rspq); +} + +/* + * Turn on NAPI and start up interrupts on a response queue. + */ +static void qenable(struct sge_rspq *rspq) +{ + napi_enable(&rspq->napi); + + /* + * 0-increment the Going To Sleep register to start the timer and + * enable interrupts. + */ + t4_write_reg(rspq->adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS, + CIDXINC(0) | + SEINTARM(rspq->intr_params) | + INGRESSQID(rspq->cntxt_id)); +} + +/* + * Enable NAPI scheduling and interrupt generation for all Receive Queues. + */ +static void enable_rx(struct adapter *adapter) +{ + int rxq; + struct sge *s = &adapter->sge; + + for_each_ethrxq(s, rxq) + qenable(&s->ethrxq[rxq].rspq); + qenable(&s->fw_evtq); + + /* + * The interrupt queue doesn't use NAPI so we do the 0-increment of + * its Going To Sleep register here to get it started. + */ + if (adapter->flags & USING_MSI) + t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS, + CIDXINC(0) | + SEINTARM(s->intrq.intr_params) | + INGRESSQID(s->intrq.cntxt_id)); + +} + +/* + * Wait until all NAPI handlers are descheduled. + */ +static void quiesce_rx(struct adapter *adapter) +{ + struct sge *s = &adapter->sge; + int rxq; + + for_each_ethrxq(s, rxq) + napi_disable(&s->ethrxq[rxq].rspq.napi); + napi_disable(&s->fw_evtq.napi); +} + +/* + * Response queue handler for the firmware event queue. + */ +static int fwevtq_handler(struct sge_rspq *rspq, const __be64 *rsp, + const struct pkt_gl *gl) +{ + /* + * Extract response opcode and get pointer to CPL message body. + */ + struct adapter *adapter = rspq->adapter; + u8 opcode = ((const struct rss_header *)rsp)->opcode; + void *cpl = (void *)(rsp + 1); + + switch (opcode) { + case CPL_FW6_MSG: { + /* + * We've received an asynchronous message from the firmware. + */ + const struct cpl_fw6_msg *fw_msg = cpl; + if (fw_msg->type == FW6_TYPE_CMD_RPL) + t4vf_handle_fw_rpl(adapter, fw_msg->data); + break; + } + + case CPL_SGE_EGR_UPDATE: { + /* + * We've received an Egress Queue Status Update message. We + * get these, if the SGE is configured to send these when the + * firmware passes certain points in processing our TX + * Ethernet Queue or if we make an explicit request for one. + * We use these updates to determine when we may need to + * restart a TX Ethernet Queue which was stopped for lack of + * free TX Queue Descriptors ... + */ + const struct cpl_sge_egr_update *p = (void *)cpl; + unsigned int qid = EGR_QID(be32_to_cpu(p->opcode_qid)); + struct sge *s = &adapter->sge; + struct sge_txq *tq; + struct sge_eth_txq *txq; + unsigned int eq_idx; + + /* + * Perform sanity checking on the Queue ID to make sure it + * really refers to one of our TX Ethernet Egress Queues which + * is active and matches the queue's ID. None of these error + * conditions should ever happen so we may want to either make + * them fatal and/or conditionalized under DEBUG. + */ + eq_idx = EQ_IDX(s, qid); + if (unlikely(eq_idx >= MAX_EGRQ)) { + dev_err(adapter->pdev_dev, + "Egress Update QID %d out of range\n", qid); + break; + } + tq = s->egr_map[eq_idx]; + if (unlikely(tq == NULL)) { + dev_err(adapter->pdev_dev, + "Egress Update QID %d TXQ=NULL\n", qid); + break; + } + txq = container_of(tq, struct sge_eth_txq, q); + if (unlikely(tq->abs_id != qid)) { + dev_err(adapter->pdev_dev, + "Egress Update QID %d refers to TXQ %d\n", + qid, tq->abs_id); + break; + } + + /* + * Restart a stopped TX Queue which has less than half of its + * TX ring in use ... + */ + txq->q.restarts++; + netif_tx_wake_queue(txq->txq); + break; + } + + default: + dev_err(adapter->pdev_dev, + "unexpected CPL %#x on FW event queue\n", opcode); + } + + return 0; +} + +/* + * Allocate SGE TX/RX response queues. Determine how many sets of SGE queues + * to use and initializes them. We support multiple "Queue Sets" per port if + * we have MSI-X, otherwise just one queue set per port. + */ +static int setup_sge_queues(struct adapter *adapter) +{ + struct sge *s = &adapter->sge; + int err, pidx, msix; + + /* + * Clear "Queue Set" Free List Starving and TX Queue Mapping Error + * state. + */ + bitmap_zero(s->starving_fl, MAX_EGRQ); + + /* + * If we're using MSI interrupt mode we need to set up a "forwarded + * interrupt" queue which we'll set up with our MSI vector. The rest + * of the ingress queues will be set up to forward their interrupts to + * this queue ... This must be first since t4vf_sge_alloc_rxq() uses + * the intrq's queue ID as the interrupt forwarding queue for the + * subsequent calls ... + */ + if (adapter->flags & USING_MSI) { + err = t4vf_sge_alloc_rxq(adapter, &s->intrq, false, + adapter->port[0], 0, NULL, NULL); + if (err) + goto err_free_queues; + } + + /* + * Allocate our ingress queue for asynchronous firmware messages. + */ + err = t4vf_sge_alloc_rxq(adapter, &s->fw_evtq, true, adapter->port[0], + MSIX_FW, NULL, fwevtq_handler); + if (err) + goto err_free_queues; + + /* + * Allocate each "port"'s initial Queue Sets. These can be changed + * later on ... up to the point where any interface on the adapter is + * brought up at which point lots of things get nailed down + * permanently ... + */ + msix = MSIX_IQFLINT; + for_each_port(adapter, pidx) { + struct net_device *dev = adapter->port[pidx]; + struct port_info *pi = netdev_priv(dev); + struct sge_eth_rxq *rxq = &s->ethrxq[pi->first_qset]; + struct sge_eth_txq *txq = &s->ethtxq[pi->first_qset]; + int qs; + + for (qs = 0; qs < pi->nqsets; qs++, rxq++, txq++) { + err = t4vf_sge_alloc_rxq(adapter, &rxq->rspq, false, + dev, msix++, + &rxq->fl, t4vf_ethrx_handler); + if (err) + goto err_free_queues; + + err = t4vf_sge_alloc_eth_txq(adapter, txq, dev, + netdev_get_tx_queue(dev, qs), + s->fw_evtq.cntxt_id); + if (err) + goto err_free_queues; + + rxq->rspq.idx = qs; + memset(&rxq->stats, 0, sizeof(rxq->stats)); + } + } + + /* + * Create the reverse mappings for the queues. + */ + s->egr_base = s->ethtxq[0].q.abs_id - s->ethtxq[0].q.cntxt_id; + s->ingr_base = s->ethrxq[0].rspq.abs_id - s->ethrxq[0].rspq.cntxt_id; + IQ_MAP(s, s->fw_evtq.abs_id) = &s->fw_evtq; + for_each_port(adapter, pidx) { + struct net_device *dev = adapter->port[pidx]; + struct port_info *pi = netdev_priv(dev); + struct sge_eth_rxq *rxq = &s->ethrxq[pi->first_qset]; + struct sge_eth_txq *txq = &s->ethtxq[pi->first_qset]; + int qs; + + for (qs = 0; qs < pi->nqsets; qs++, rxq++, txq++) { + IQ_MAP(s, rxq->rspq.abs_id) = &rxq->rspq; + EQ_MAP(s, txq->q.abs_id) = &txq->q; + + /* + * The FW_IQ_CMD doesn't return the Absolute Queue IDs + * for Free Lists but since all of the Egress Queues + * (including Free Lists) have Relative Queue IDs + * which are computed as Absolute - Base Queue ID, we + * can synthesize the Absolute Queue IDs for the Free + * Lists. This is useful for debugging purposes when + * we want to dump Queue Contexts via the PF Driver. + */ + rxq->fl.abs_id = rxq->fl.cntxt_id + s->egr_base; + EQ_MAP(s, rxq->fl.abs_id) = &rxq->fl; + } + } + return 0; + +err_free_queues: + t4vf_free_sge_resources(adapter); + return err; +} + +/* + * Set up Receive Side Scaling (RSS) to distribute packets to multiple receive + * queues. We configure the RSS CPU lookup table to distribute to the number + * of HW receive queues, and the response queue lookup table to narrow that + * down to the response queues actually configured for each "port" (Virtual + * Interface). We always configure the RSS mapping for all ports since the + * mapping table has plenty of entries. + */ +static int setup_rss(struct adapter *adapter) +{ + int pidx; + + for_each_port(adapter, pidx) { + struct port_info *pi = adap2pinfo(adapter, pidx); + struct sge_eth_rxq *rxq = &adapter->sge.ethrxq[pi->first_qset]; + u16 rss[MAX_PORT_QSETS]; + int qs, err; + + for (qs = 0; qs < pi->nqsets; qs++) + rss[qs] = rxq[qs].rspq.abs_id; + + err = t4vf_config_rss_range(adapter, pi->viid, + 0, pi->rss_size, rss, pi->nqsets); + if (err) + return err; + + /* + * Perform Global RSS Mode-specific initialization. + */ + switch (adapter->params.rss.mode) { + case FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL: + /* + * If Tunnel All Lookup isn't specified in the global + * RSS Configuration, then we need to specify a + * default Ingress Queue for any ingress packets which + * aren't hashed. We'll use our first ingress queue + * ... + */ + if (!adapter->params.rss.u.basicvirtual.tnlalllookup) { + union rss_vi_config config; + err = t4vf_read_rss_vi_config(adapter, + pi->viid, + &config); + if (err) + return err; + config.basicvirtual.defaultq = + rxq[0].rspq.abs_id; + err = t4vf_write_rss_vi_config(adapter, + pi->viid, + &config); + if (err) + return err; + } + break; + } + } + + return 0; +} + +/* + * Bring the adapter up. Called whenever we go from no "ports" open to having + * one open. This function performs the actions necessary to make an adapter + * operational, such as completing the initialization of HW modules, and + * enabling interrupts. Must be called with the rtnl lock held. (Note that + * this is called "cxgb_up" in the PF Driver.) + */ +static int adapter_up(struct adapter *adapter) +{ + int err; + + /* + * If this is the first time we've been called, perform basic + * adapter setup. Once we've done this, many of our adapter + * parameters can no longer be changed ... + */ + if ((adapter->flags & FULL_INIT_DONE) == 0) { + err = setup_sge_queues(adapter); + if (err) + return err; + err = setup_rss(adapter); + if (err) { + t4vf_free_sge_resources(adapter); + return err; + } + + if (adapter->flags & USING_MSIX) + name_msix_vecs(adapter); + adapter->flags |= FULL_INIT_DONE; + } + + /* + * Acquire our interrupt resources. We only support MSI-X and MSI. + */ + BUG_ON((adapter->flags & (USING_MSIX|USING_MSI)) == 0); + if (adapter->flags & USING_MSIX) + err = request_msix_queue_irqs(adapter); + else + err = request_irq(adapter->pdev->irq, + t4vf_intr_handler(adapter), 0, + adapter->name, adapter); + if (err) { + dev_err(adapter->pdev_dev, "request_irq failed, err %d\n", + err); + return err; + } + + /* + * Enable NAPI ingress processing and return success. + */ + enable_rx(adapter); + t4vf_sge_start(adapter); + return 0; +} + +/* + * Bring the adapter down. Called whenever the last "port" (Virtual + * Interface) closed. (Note that this routine is called "cxgb_down" in the PF + * Driver.) + */ +static void adapter_down(struct adapter *adapter) +{ + /* + * Free interrupt resources. + */ + if (adapter->flags & USING_MSIX) + free_msix_queue_irqs(adapter); + else + free_irq(adapter->pdev->irq, adapter); + + /* + * Wait for NAPI handlers to finish. + */ + quiesce_rx(adapter); +} + +/* + * Start up a net device. + */ +static int cxgb4vf_open(struct net_device *dev) +{ + int err; + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + + /* + * If this is the first interface that we're opening on the "adapter", + * bring the "adapter" up now. + */ + if (adapter->open_device_map == 0) { + err = adapter_up(adapter); + if (err) + return err; + } + + /* + * Note that this interface is up and start everything up ... + */ + netif_set_real_num_tx_queues(dev, pi->nqsets); + err = netif_set_real_num_rx_queues(dev, pi->nqsets); + if (err) + goto err_unwind; + err = link_start(dev); + if (err) + goto err_unwind; + + netif_tx_start_all_queues(dev); + set_bit(pi->port_id, &adapter->open_device_map); + return 0; + +err_unwind: + if (adapter->open_device_map == 0) + adapter_down(adapter); + return err; +} + +/* + * Shut down a net device. This routine is called "cxgb_close" in the PF + * Driver ... + */ +static int cxgb4vf_stop(struct net_device *dev) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + + netif_tx_stop_all_queues(dev); + netif_carrier_off(dev); + t4vf_enable_vi(adapter, pi->viid, false, false); + pi->link_cfg.link_ok = 0; + + clear_bit(pi->port_id, &adapter->open_device_map); + if (adapter->open_device_map == 0) + adapter_down(adapter); + return 0; +} + +/* + * Translate our basic statistics into the standard "ifconfig" statistics. + */ +static struct net_device_stats *cxgb4vf_get_stats(struct net_device *dev) +{ + struct t4vf_port_stats stats; + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adapter = pi->adapter; + struct net_device_stats *ns = &dev->stats; + int err; + + spin_lock(&adapter->stats_lock); + err = t4vf_get_port_stats(adapter, pi->pidx, &stats); + spin_unlock(&adapter->stats_lock); + + memset(ns, 0, sizeof(*ns)); + if (err) + return ns; + + ns->tx_bytes = (stats.tx_bcast_bytes + stats.tx_mcast_bytes + + stats.tx_ucast_bytes + stats.tx_offload_bytes); + ns->tx_packets = (stats.tx_bcast_frames + stats.tx_mcast_frames + + stats.tx_ucast_frames + stats.tx_offload_frames); + ns->rx_bytes = (stats.rx_bcast_bytes + stats.rx_mcast_bytes + + stats.rx_ucast_bytes); + ns->rx_packets = (stats.rx_bcast_frames + stats.rx_mcast_frames + + stats.rx_ucast_frames); + ns->multicast = stats.rx_mcast_frames; + ns->tx_errors = stats.tx_drop_frames; + ns->rx_errors = stats.rx_err_frames; + + return ns; +} + +/* + * Collect up to maxaddrs worth of a netdevice's unicast addresses, starting + * at a specified offset within the list, into an array of addrss pointers and + * return the number collected. + */ +static inline unsigned int collect_netdev_uc_list_addrs(const struct net_device *dev, + const u8 **addr, + unsigned int offset, + unsigned int maxaddrs) +{ + unsigned int index = 0; + unsigned int naddr = 0; + const struct netdev_hw_addr *ha; + + for_each_dev_addr(dev, ha) + if (index++ >= offset) { + addr[naddr++] = ha->addr; + if (naddr >= maxaddrs) + break; + } + return naddr; +} + +/* + * Collect up to maxaddrs worth of a netdevice's multicast addresses, starting + * at a specified offset within the list, into an array of addrss pointers and + * return the number collected. + */ +static inline unsigned int collect_netdev_mc_list_addrs(const struct net_device *dev, + const u8 **addr, + unsigned int offset, + unsigned int maxaddrs) +{ + unsigned int index = 0; + unsigned int naddr = 0; + const struct netdev_hw_addr *ha; + + netdev_for_each_mc_addr(ha, dev) + if (index++ >= offset) { + addr[naddr++] = ha->addr; + if (naddr >= maxaddrs) + break; + } + return naddr; +} + +/* + * Configure the exact and hash address filters to handle a port's multicast + * and secondary unicast MAC addresses. + */ +static int set_addr_filters(const struct net_device *dev, bool sleep) +{ + u64 mhash = 0; + u64 uhash = 0; + bool free = true; + unsigned int offset, naddr; + const u8 *addr[7]; + int ret; + const struct port_info *pi = netdev_priv(dev); + + /* first do the secondary unicast addresses */ + for (offset = 0; ; offset += naddr) { + naddr = collect_netdev_uc_list_addrs(dev, addr, offset, + ARRAY_SIZE(addr)); + if (naddr == 0) + break; + + ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free, + naddr, addr, NULL, &uhash, sleep); + if (ret < 0) + return ret; + + free = false; + } + + /* next set up the multicast addresses */ + for (offset = 0; ; offset += naddr) { + naddr = collect_netdev_mc_list_addrs(dev, addr, offset, + ARRAY_SIZE(addr)); + if (naddr == 0) + break; + + ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free, + naddr, addr, NULL, &mhash, sleep); + if (ret < 0) + return ret; + free = false; + } + + return t4vf_set_addr_hash(pi->adapter, pi->viid, uhash != 0, + uhash | mhash, sleep); +} + +/* + * Set RX properties of a port, such as promiscruity, address filters, and MTU. + * If @mtu is -1 it is left unchanged. + */ +static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok) +{ + int ret; + struct port_info *pi = netdev_priv(dev); + + ret = set_addr_filters(dev, sleep_ok); + if (ret == 0) + ret = t4vf_set_rxmode(pi->adapter, pi->viid, -1, + (dev->flags & IFF_PROMISC) != 0, + (dev->flags & IFF_ALLMULTI) != 0, + 1, -1, sleep_ok); + return ret; +} + +/* + * Set the current receive modes on the device. + */ +static void cxgb4vf_set_rxmode(struct net_device *dev) +{ + /* unfortunately we can't return errors to the stack */ + set_rxmode(dev, -1, false); +} + +/* + * Find the entry in the interrupt holdoff timer value array which comes + * closest to the specified interrupt holdoff value. + */ +static int closest_timer(const struct sge *s, int us) +{ + int i, timer_idx = 0, min_delta = INT_MAX; + + for (i = 0; i < ARRAY_SIZE(s->timer_val); i++) { + int delta = us - s->timer_val[i]; + if (delta < 0) + delta = -delta; + if (delta < min_delta) { + min_delta = delta; + timer_idx = i; + } + } + return timer_idx; +} + +static int closest_thres(const struct sge *s, int thres) +{ + int i, delta, pktcnt_idx = 0, min_delta = INT_MAX; + + for (i = 0; i < ARRAY_SIZE(s->counter_val); i++) { + delta = thres - s->counter_val[i]; + if (delta < 0) + delta = -delta; + if (delta < min_delta) { + min_delta = delta; + pktcnt_idx = i; + } + } + return pktcnt_idx; +} + +/* + * Return a queue's interrupt hold-off time in us. 0 means no timer. + */ +static unsigned int qtimer_val(const struct adapter *adapter, + const struct sge_rspq *rspq) +{ + unsigned int timer_idx = QINTR_TIMER_IDX_GET(rspq->intr_params); + + return timer_idx < SGE_NTIMERS + ? adapter->sge.timer_val[timer_idx] + : 0; +} + +/** + * set_rxq_intr_params - set a queue's interrupt holdoff parameters + * @adapter: the adapter + * @rspq: the RX response queue + * @us: the hold-off time in us, or 0 to disable timer + * @cnt: the hold-off packet count, or 0 to disable counter + * + * Sets an RX response queue's interrupt hold-off time and packet count. + * At least one of the two needs to be enabled for the queue to generate + * interrupts. + */ +static int set_rxq_intr_params(struct adapter *adapter, struct sge_rspq *rspq, + unsigned int us, unsigned int cnt) +{ + unsigned int timer_idx; + + /* + * If both the interrupt holdoff timer and count are specified as + * zero, default to a holdoff count of 1 ... + */ + if ((us | cnt) == 0) + cnt = 1; + + /* + * If an interrupt holdoff count has been specified, then find the + * closest configured holdoff count and use that. If the response + * queue has already been created, then update its queue context + * parameters ... + */ + if (cnt) { + int err; + u32 v, pktcnt_idx; + + pktcnt_idx = closest_thres(&adapter->sge, cnt); + if (rspq->desc && rspq->pktcnt_idx != pktcnt_idx) { + v = FW_PARAMS_MNEM(FW_PARAMS_MNEM_DMAQ) | + FW_PARAMS_PARAM_X( + FW_PARAMS_PARAM_DMAQ_IQ_INTCNTTHRESH) | + FW_PARAMS_PARAM_YZ(rspq->cntxt_id); + err = t4vf_set_params(adapter, 1, &v, &pktcnt_idx); + if (err) + return err; + } + rspq->pktcnt_idx = pktcnt_idx; + } + + /* + * Compute the closest holdoff timer index from the supplied holdoff + * timer value. + */ + timer_idx = (us == 0 + ? SGE_TIMER_RSTRT_CNTR + : closest_timer(&adapter->sge, us)); + + /* + * Update the response queue's interrupt coalescing parameters and + * return success. + */ + rspq->intr_params = (QINTR_TIMER_IDX(timer_idx) | + (cnt > 0 ? QINTR_CNT_EN : 0)); + return 0; +} + +/* + * Return a version number to identify the type of adapter. The scheme is: + * - bits 0..9: chip version + * - bits 10..15: chip revision + */ +static inline unsigned int mk_adap_vers(const struct adapter *adapter) +{ + /* + * Chip version 4, revision 0x3f (cxgb4vf). + */ + return 4 | (0x3f << 10); +} + +/* + * Execute the specified ioctl command. + */ +static int cxgb4vf_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + int ret = 0; + + switch (cmd) { + /* + * The VF Driver doesn't have access to any of the other + * common Ethernet device ioctl()'s (like reading/writing + * PHY registers, etc. + */ + + default: + ret = -EOPNOTSUPP; + break; + } + return ret; +} + +/* + * Change the device's MTU. + */ +static int cxgb4vf_change_mtu(struct net_device *dev, int new_mtu) +{ + int ret; + struct port_info *pi = netdev_priv(dev); + + /* accommodate SACK */ + if (new_mtu < 81) + return -EINVAL; + + ret = t4vf_set_rxmode(pi->adapter, pi->viid, new_mtu, + -1, -1, -1, -1, true); + if (!ret) + dev->mtu = new_mtu; + return ret; +} + +static u32 cxgb4vf_fix_features(struct net_device *dev, u32 features) +{ + /* + * Since there is no support for separate rx/tx vlan accel + * enable/disable make sure tx flag is always in same state as rx. + */ + if (features & NETIF_F_HW_VLAN_RX) + features |= NETIF_F_HW_VLAN_TX; + else + features &= ~NETIF_F_HW_VLAN_TX; + + return features; +} + +static int cxgb4vf_set_features(struct net_device *dev, u32 features) +{ + struct port_info *pi = netdev_priv(dev); + u32 changed = dev->features ^ features; + + if (changed & NETIF_F_HW_VLAN_RX) + t4vf_set_rxmode(pi->adapter, pi->viid, -1, -1, -1, -1, + features & NETIF_F_HW_VLAN_TX, 0); + + return 0; +} + +/* + * Change the devices MAC address. + */ +static int cxgb4vf_set_mac_addr(struct net_device *dev, void *_addr) +{ + int ret; + struct sockaddr *addr = _addr; + struct port_info *pi = netdev_priv(dev); + + if (!is_valid_ether_addr(addr->sa_data)) + return -EINVAL; + + ret = t4vf_change_mac(pi->adapter, pi->viid, pi->xact_addr_filt, + addr->sa_data, true); + if (ret < 0) + return ret; + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + pi->xact_addr_filt = ret; + return 0; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Poll all of our receive queues. This is called outside of normal interrupt + * context. + */ +static void cxgb4vf_poll_controller(struct net_device *dev) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + + if (adapter->flags & USING_MSIX) { + struct sge_eth_rxq *rxq; + int nqsets; + + rxq = &adapter->sge.ethrxq[pi->first_qset]; + for (nqsets = pi->nqsets; nqsets; nqsets--) { + t4vf_sge_intr_msix(0, &rxq->rspq); + rxq++; + } + } else + t4vf_intr_handler(adapter)(0, adapter); +} +#endif + +/* + * Ethtool operations. + * =================== + * + * Note that we don't support any ethtool operations which change the physical + * state of the port to which we're linked. + */ + +/* + * Return current port link settings. + */ +static int cxgb4vf_get_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + const struct port_info *pi = netdev_priv(dev); + + cmd->supported = pi->link_cfg.supported; + cmd->advertising = pi->link_cfg.advertising; + ethtool_cmd_speed_set(cmd, + netif_carrier_ok(dev) ? pi->link_cfg.speed : -1); + cmd->duplex = DUPLEX_FULL; + + cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE; + cmd->phy_address = pi->port_id; + cmd->transceiver = XCVR_EXTERNAL; + cmd->autoneg = pi->link_cfg.autoneg; + cmd->maxtxpkt = 0; + cmd->maxrxpkt = 0; + return 0; +} + +/* + * Return our driver information. + */ +static void cxgb4vf_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *drvinfo) +{ + struct adapter *adapter = netdev2adap(dev); + + strcpy(drvinfo->driver, KBUILD_MODNAME); + strcpy(drvinfo->version, DRV_VERSION); + strcpy(drvinfo->bus_info, pci_name(to_pci_dev(dev->dev.parent))); + snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), + "%u.%u.%u.%u, TP %u.%u.%u.%u", + FW_HDR_FW_VER_MAJOR_GET(adapter->params.dev.fwrev), + FW_HDR_FW_VER_MINOR_GET(adapter->params.dev.fwrev), + FW_HDR_FW_VER_MICRO_GET(adapter->params.dev.fwrev), + FW_HDR_FW_VER_BUILD_GET(adapter->params.dev.fwrev), + FW_HDR_FW_VER_MAJOR_GET(adapter->params.dev.tprev), + FW_HDR_FW_VER_MINOR_GET(adapter->params.dev.tprev), + FW_HDR_FW_VER_MICRO_GET(adapter->params.dev.tprev), + FW_HDR_FW_VER_BUILD_GET(adapter->params.dev.tprev)); +} + +/* + * Return current adapter message level. + */ +static u32 cxgb4vf_get_msglevel(struct net_device *dev) +{ + return netdev2adap(dev)->msg_enable; +} + +/* + * Set current adapter message level. + */ +static void cxgb4vf_set_msglevel(struct net_device *dev, u32 msglevel) +{ + netdev2adap(dev)->msg_enable = msglevel; +} + +/* + * Return the device's current Queue Set ring size parameters along with the + * allowed maximum values. Since ethtool doesn't understand the concept of + * multi-queue devices, we just return the current values associated with the + * first Queue Set. + */ +static void cxgb4vf_get_ringparam(struct net_device *dev, + struct ethtool_ringparam *rp) +{ + const struct port_info *pi = netdev_priv(dev); + const struct sge *s = &pi->adapter->sge; + + rp->rx_max_pending = MAX_RX_BUFFERS; + rp->rx_mini_max_pending = MAX_RSPQ_ENTRIES; + rp->rx_jumbo_max_pending = 0; + rp->tx_max_pending = MAX_TXQ_ENTRIES; + + rp->rx_pending = s->ethrxq[pi->first_qset].fl.size - MIN_FL_RESID; + rp->rx_mini_pending = s->ethrxq[pi->first_qset].rspq.size; + rp->rx_jumbo_pending = 0; + rp->tx_pending = s->ethtxq[pi->first_qset].q.size; +} + +/* + * Set the Queue Set ring size parameters for the device. Again, since + * ethtool doesn't allow for the concept of multiple queues per device, we'll + * apply these new values across all of the Queue Sets associated with the + * device -- after vetting them of course! + */ +static int cxgb4vf_set_ringparam(struct net_device *dev, + struct ethtool_ringparam *rp) +{ + const struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + struct sge *s = &adapter->sge; + int qs; + + if (rp->rx_pending > MAX_RX_BUFFERS || + rp->rx_jumbo_pending || + rp->tx_pending > MAX_TXQ_ENTRIES || + rp->rx_mini_pending > MAX_RSPQ_ENTRIES || + rp->rx_mini_pending < MIN_RSPQ_ENTRIES || + rp->rx_pending < MIN_FL_ENTRIES || + rp->tx_pending < MIN_TXQ_ENTRIES) + return -EINVAL; + + if (adapter->flags & FULL_INIT_DONE) + return -EBUSY; + + for (qs = pi->first_qset; qs < pi->first_qset + pi->nqsets; qs++) { + s->ethrxq[qs].fl.size = rp->rx_pending + MIN_FL_RESID; + s->ethrxq[qs].rspq.size = rp->rx_mini_pending; + s->ethtxq[qs].q.size = rp->tx_pending; + } + return 0; +} + +/* + * Return the interrupt holdoff timer and count for the first Queue Set on the + * device. Our extension ioctl() (the cxgbtool interface) allows the + * interrupt holdoff timer to be read on all of the device's Queue Sets. + */ +static int cxgb4vf_get_coalesce(struct net_device *dev, + struct ethtool_coalesce *coalesce) +{ + const struct port_info *pi = netdev_priv(dev); + const struct adapter *adapter = pi->adapter; + const struct sge_rspq *rspq = &adapter->sge.ethrxq[pi->first_qset].rspq; + + coalesce->rx_coalesce_usecs = qtimer_val(adapter, rspq); + coalesce->rx_max_coalesced_frames = + ((rspq->intr_params & QINTR_CNT_EN) + ? adapter->sge.counter_val[rspq->pktcnt_idx] + : 0); + return 0; +} + +/* + * Set the RX interrupt holdoff timer and count for the first Queue Set on the + * interface. Our extension ioctl() (the cxgbtool interface) allows us to set + * the interrupt holdoff timer on any of the device's Queue Sets. + */ +static int cxgb4vf_set_coalesce(struct net_device *dev, + struct ethtool_coalesce *coalesce) +{ + const struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + + return set_rxq_intr_params(adapter, + &adapter->sge.ethrxq[pi->first_qset].rspq, + coalesce->rx_coalesce_usecs, + coalesce->rx_max_coalesced_frames); +} + +/* + * Report current port link pause parameter settings. + */ +static void cxgb4vf_get_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *pauseparam) +{ + struct port_info *pi = netdev_priv(dev); + + pauseparam->autoneg = (pi->link_cfg.requested_fc & PAUSE_AUTONEG) != 0; + pauseparam->rx_pause = (pi->link_cfg.fc & PAUSE_RX) != 0; + pauseparam->tx_pause = (pi->link_cfg.fc & PAUSE_TX) != 0; +} + +/* + * Identify the port by blinking the port's LED. + */ +static int cxgb4vf_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) +{ + unsigned int val; + struct port_info *pi = netdev_priv(dev); + + if (state == ETHTOOL_ID_ACTIVE) + val = 0xffff; + else if (state == ETHTOOL_ID_INACTIVE) + val = 0; + else + return -EINVAL; + + return t4vf_identify_port(pi->adapter, pi->viid, val); +} + +/* + * Port stats maintained per queue of the port. + */ +struct queue_port_stats { + u64 tso; + u64 tx_csum; + u64 rx_csum; + u64 vlan_ex; + u64 vlan_ins; + u64 lro_pkts; + u64 lro_merged; +}; + +/* + * Strings for the ETH_SS_STATS statistics set ("ethtool -S"). Note that + * these need to match the order of statistics returned by + * t4vf_get_port_stats(). + */ +static const char stats_strings[][ETH_GSTRING_LEN] = { + /* + * These must match the layout of the t4vf_port_stats structure. + */ + "TxBroadcastBytes ", + "TxBroadcastFrames ", + "TxMulticastBytes ", + "TxMulticastFrames ", + "TxUnicastBytes ", + "TxUnicastFrames ", + "TxDroppedFrames ", + "TxOffloadBytes ", + "TxOffloadFrames ", + "RxBroadcastBytes ", + "RxBroadcastFrames ", + "RxMulticastBytes ", + "RxMulticastFrames ", + "RxUnicastBytes ", + "RxUnicastFrames ", + "RxErrorFrames ", + + /* + * These are accumulated per-queue statistics and must match the + * order of the fields in the queue_port_stats structure. + */ + "TSO ", + "TxCsumOffload ", + "RxCsumGood ", + "VLANextractions ", + "VLANinsertions ", + "GROPackets ", + "GROMerged ", +}; + +/* + * Return the number of statistics in the specified statistics set. + */ +static int cxgb4vf_get_sset_count(struct net_device *dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(stats_strings); + default: + return -EOPNOTSUPP; + } + /*NOTREACHED*/ +} + +/* + * Return the strings for the specified statistics set. + */ +static void cxgb4vf_get_strings(struct net_device *dev, + u32 sset, + u8 *data) +{ + switch (sset) { + case ETH_SS_STATS: + memcpy(data, stats_strings, sizeof(stats_strings)); + break; + } +} + +/* + * Small utility routine to accumulate queue statistics across the queues of + * a "port". + */ +static void collect_sge_port_stats(const struct adapter *adapter, + const struct port_info *pi, + struct queue_port_stats *stats) +{ + const struct sge_eth_txq *txq = &adapter->sge.ethtxq[pi->first_qset]; + const struct sge_eth_rxq *rxq = &adapter->sge.ethrxq[pi->first_qset]; + int qs; + + memset(stats, 0, sizeof(*stats)); + for (qs = 0; qs < pi->nqsets; qs++, rxq++, txq++) { + stats->tso += txq->tso; + stats->tx_csum += txq->tx_cso; + stats->rx_csum += rxq->stats.rx_cso; + stats->vlan_ex += rxq->stats.vlan_ex; + stats->vlan_ins += txq->vlan_ins; + stats->lro_pkts += rxq->stats.lro_pkts; + stats->lro_merged += rxq->stats.lro_merged; + } +} + +/* + * Return the ETH_SS_STATS statistics set. + */ +static void cxgb4vf_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, + u64 *data) +{ + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adapter = pi->adapter; + int err = t4vf_get_port_stats(adapter, pi->pidx, + (struct t4vf_port_stats *)data); + if (err) + memset(data, 0, sizeof(struct t4vf_port_stats)); + + data += sizeof(struct t4vf_port_stats) / sizeof(u64); + collect_sge_port_stats(adapter, pi, (struct queue_port_stats *)data); +} + +/* + * Return the size of our register map. + */ +static int cxgb4vf_get_regs_len(struct net_device *dev) +{ + return T4VF_REGMAP_SIZE; +} + +/* + * Dump a block of registers, start to end inclusive, into a buffer. + */ +static void reg_block_dump(struct adapter *adapter, void *regbuf, + unsigned int start, unsigned int end) +{ + u32 *bp = regbuf + start - T4VF_REGMAP_START; + + for ( ; start <= end; start += sizeof(u32)) { + /* + * Avoid reading the Mailbox Control register since that + * can trigger a Mailbox Ownership Arbitration cycle and + * interfere with communication with the firmware. + */ + if (start == T4VF_CIM_BASE_ADDR + CIM_VF_EXT_MAILBOX_CTRL) + *bp++ = 0xffff; + else + *bp++ = t4_read_reg(adapter, start); + } +} + +/* + * Copy our entire register map into the provided buffer. + */ +static void cxgb4vf_get_regs(struct net_device *dev, + struct ethtool_regs *regs, + void *regbuf) +{ + struct adapter *adapter = netdev2adap(dev); + + regs->version = mk_adap_vers(adapter); + + /* + * Fill in register buffer with our register map. + */ + memset(regbuf, 0, T4VF_REGMAP_SIZE); + + reg_block_dump(adapter, regbuf, + T4VF_SGE_BASE_ADDR + T4VF_MOD_MAP_SGE_FIRST, + T4VF_SGE_BASE_ADDR + T4VF_MOD_MAP_SGE_LAST); + reg_block_dump(adapter, regbuf, + T4VF_MPS_BASE_ADDR + T4VF_MOD_MAP_MPS_FIRST, + T4VF_MPS_BASE_ADDR + T4VF_MOD_MAP_MPS_LAST); + reg_block_dump(adapter, regbuf, + T4VF_PL_BASE_ADDR + T4VF_MOD_MAP_PL_FIRST, + T4VF_PL_BASE_ADDR + T4VF_MOD_MAP_PL_LAST); + reg_block_dump(adapter, regbuf, + T4VF_CIM_BASE_ADDR + T4VF_MOD_MAP_CIM_FIRST, + T4VF_CIM_BASE_ADDR + T4VF_MOD_MAP_CIM_LAST); + + reg_block_dump(adapter, regbuf, + T4VF_MBDATA_BASE_ADDR + T4VF_MBDATA_FIRST, + T4VF_MBDATA_BASE_ADDR + T4VF_MBDATA_LAST); +} + +/* + * Report current Wake On LAN settings. + */ +static void cxgb4vf_get_wol(struct net_device *dev, + struct ethtool_wolinfo *wol) +{ + wol->supported = 0; + wol->wolopts = 0; + memset(&wol->sopass, 0, sizeof(wol->sopass)); +} + +/* + * TCP Segmentation Offload flags which we support. + */ +#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN) + +static struct ethtool_ops cxgb4vf_ethtool_ops = { + .get_settings = cxgb4vf_get_settings, + .get_drvinfo = cxgb4vf_get_drvinfo, + .get_msglevel = cxgb4vf_get_msglevel, + .set_msglevel = cxgb4vf_set_msglevel, + .get_ringparam = cxgb4vf_get_ringparam, + .set_ringparam = cxgb4vf_set_ringparam, + .get_coalesce = cxgb4vf_get_coalesce, + .set_coalesce = cxgb4vf_set_coalesce, + .get_pauseparam = cxgb4vf_get_pauseparam, + .get_link = ethtool_op_get_link, + .get_strings = cxgb4vf_get_strings, + .set_phys_id = cxgb4vf_phys_id, + .get_sset_count = cxgb4vf_get_sset_count, + .get_ethtool_stats = cxgb4vf_get_ethtool_stats, + .get_regs_len = cxgb4vf_get_regs_len, + .get_regs = cxgb4vf_get_regs, + .get_wol = cxgb4vf_get_wol, +}; + +/* + * /sys/kernel/debug/cxgb4vf support code and data. + * ================================================ + */ + +/* + * Show SGE Queue Set information. We display QPL Queues Sets per line. + */ +#define QPL 4 + +static int sge_qinfo_show(struct seq_file *seq, void *v) +{ + struct adapter *adapter = seq->private; + int eth_entries = DIV_ROUND_UP(adapter->sge.ethqsets, QPL); + int qs, r = (uintptr_t)v - 1; + + if (r) + seq_putc(seq, '\n'); + + #define S3(fmt_spec, s, v) \ + do {\ + seq_printf(seq, "%-12s", s); \ + for (qs = 0; qs < n; ++qs) \ + seq_printf(seq, " %16" fmt_spec, v); \ + seq_putc(seq, '\n'); \ + } while (0) + #define S(s, v) S3("s", s, v) + #define T(s, v) S3("u", s, txq[qs].v) + #define R(s, v) S3("u", s, rxq[qs].v) + + if (r < eth_entries) { + const struct sge_eth_rxq *rxq = &adapter->sge.ethrxq[r * QPL]; + const struct sge_eth_txq *txq = &adapter->sge.ethtxq[r * QPL]; + int n = min(QPL, adapter->sge.ethqsets - QPL * r); + + S("QType:", "Ethernet"); + S("Interface:", + (rxq[qs].rspq.netdev + ? rxq[qs].rspq.netdev->name + : "N/A")); + S3("d", "Port:", + (rxq[qs].rspq.netdev + ? ((struct port_info *) + netdev_priv(rxq[qs].rspq.netdev))->port_id + : -1)); + T("TxQ ID:", q.abs_id); + T("TxQ size:", q.size); + T("TxQ inuse:", q.in_use); + T("TxQ PIdx:", q.pidx); + T("TxQ CIdx:", q.cidx); + R("RspQ ID:", rspq.abs_id); + R("RspQ size:", rspq.size); + R("RspQE size:", rspq.iqe_len); + S3("u", "Intr delay:", qtimer_val(adapter, &rxq[qs].rspq)); + S3("u", "Intr pktcnt:", + adapter->sge.counter_val[rxq[qs].rspq.pktcnt_idx]); + R("RspQ CIdx:", rspq.cidx); + R("RspQ Gen:", rspq.gen); + R("FL ID:", fl.abs_id); + R("FL size:", fl.size - MIN_FL_RESID); + R("FL avail:", fl.avail); + R("FL PIdx:", fl.pidx); + R("FL CIdx:", fl.cidx); + return 0; + } + + r -= eth_entries; + if (r == 0) { + const struct sge_rspq *evtq = &adapter->sge.fw_evtq; + + seq_printf(seq, "%-12s %16s\n", "QType:", "FW event queue"); + seq_printf(seq, "%-12s %16u\n", "RspQ ID:", evtq->abs_id); + seq_printf(seq, "%-12s %16u\n", "Intr delay:", + qtimer_val(adapter, evtq)); + seq_printf(seq, "%-12s %16u\n", "Intr pktcnt:", + adapter->sge.counter_val[evtq->pktcnt_idx]); + seq_printf(seq, "%-12s %16u\n", "RspQ Cidx:", evtq->cidx); + seq_printf(seq, "%-12s %16u\n", "RspQ Gen:", evtq->gen); + } else if (r == 1) { + const struct sge_rspq *intrq = &adapter->sge.intrq; + + seq_printf(seq, "%-12s %16s\n", "QType:", "Interrupt Queue"); + seq_printf(seq, "%-12s %16u\n", "RspQ ID:", intrq->abs_id); + seq_printf(seq, "%-12s %16u\n", "Intr delay:", + qtimer_val(adapter, intrq)); + seq_printf(seq, "%-12s %16u\n", "Intr pktcnt:", + adapter->sge.counter_val[intrq->pktcnt_idx]); + seq_printf(seq, "%-12s %16u\n", "RspQ Cidx:", intrq->cidx); + seq_printf(seq, "%-12s %16u\n", "RspQ Gen:", intrq->gen); + } + + #undef R + #undef T + #undef S + #undef S3 + + return 0; +} + +/* + * Return the number of "entries" in our "file". We group the multi-Queue + * sections with QPL Queue Sets per "entry". The sections of the output are: + * + * Ethernet RX/TX Queue Sets + * Firmware Event Queue + * Forwarded Interrupt Queue (if in MSI mode) + */ +static int sge_queue_entries(const struct adapter *adapter) +{ + return DIV_ROUND_UP(adapter->sge.ethqsets, QPL) + 1 + + ((adapter->flags & USING_MSI) != 0); +} + +static void *sge_queue_start(struct seq_file *seq, loff_t *pos) +{ + int entries = sge_queue_entries(seq->private); + + return *pos < entries ? (void *)((uintptr_t)*pos + 1) : NULL; +} + +static void sge_queue_stop(struct seq_file *seq, void *v) +{ +} + +static void *sge_queue_next(struct seq_file *seq, void *v, loff_t *pos) +{ + int entries = sge_queue_entries(seq->private); + + ++*pos; + return *pos < entries ? (void *)((uintptr_t)*pos + 1) : NULL; +} + +static const struct seq_operations sge_qinfo_seq_ops = { + .start = sge_queue_start, + .next = sge_queue_next, + .stop = sge_queue_stop, + .show = sge_qinfo_show +}; + +static int sge_qinfo_open(struct inode *inode, struct file *file) +{ + int res = seq_open(file, &sge_qinfo_seq_ops); + + if (!res) { + struct seq_file *seq = file->private_data; + seq->private = inode->i_private; + } + return res; +} + +static const struct file_operations sge_qinfo_debugfs_fops = { + .owner = THIS_MODULE, + .open = sge_qinfo_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/* + * Show SGE Queue Set statistics. We display QPL Queues Sets per line. + */ +#define QPL 4 + +static int sge_qstats_show(struct seq_file *seq, void *v) +{ + struct adapter *adapter = seq->private; + int eth_entries = DIV_ROUND_UP(adapter->sge.ethqsets, QPL); + int qs, r = (uintptr_t)v - 1; + + if (r) + seq_putc(seq, '\n'); + + #define S3(fmt, s, v) \ + do { \ + seq_printf(seq, "%-16s", s); \ + for (qs = 0; qs < n; ++qs) \ + seq_printf(seq, " %8" fmt, v); \ + seq_putc(seq, '\n'); \ + } while (0) + #define S(s, v) S3("s", s, v) + + #define T3(fmt, s, v) S3(fmt, s, txq[qs].v) + #define T(s, v) T3("lu", s, v) + + #define R3(fmt, s, v) S3(fmt, s, rxq[qs].v) + #define R(s, v) R3("lu", s, v) + + if (r < eth_entries) { + const struct sge_eth_rxq *rxq = &adapter->sge.ethrxq[r * QPL]; + const struct sge_eth_txq *txq = &adapter->sge.ethtxq[r * QPL]; + int n = min(QPL, adapter->sge.ethqsets - QPL * r); + + S("QType:", "Ethernet"); + S("Interface:", + (rxq[qs].rspq.netdev + ? rxq[qs].rspq.netdev->name + : "N/A")); + R3("u", "RspQNullInts:", rspq.unhandled_irqs); + R("RxPackets:", stats.pkts); + R("RxCSO:", stats.rx_cso); + R("VLANxtract:", stats.vlan_ex); + R("LROmerged:", stats.lro_merged); + R("LROpackets:", stats.lro_pkts); + R("RxDrops:", stats.rx_drops); + T("TSO:", tso); + T("TxCSO:", tx_cso); + T("VLANins:", vlan_ins); + T("TxQFull:", q.stops); + T("TxQRestarts:", q.restarts); + T("TxMapErr:", mapping_err); + R("FLAllocErr:", fl.alloc_failed); + R("FLLrgAlcErr:", fl.large_alloc_failed); + R("FLStarving:", fl.starving); + return 0; + } + + r -= eth_entries; + if (r == 0) { + const struct sge_rspq *evtq = &adapter->sge.fw_evtq; + + seq_printf(seq, "%-8s %16s\n", "QType:", "FW event queue"); + seq_printf(seq, "%-16s %8u\n", "RspQNullInts:", + evtq->unhandled_irqs); + seq_printf(seq, "%-16s %8u\n", "RspQ CIdx:", evtq->cidx); + seq_printf(seq, "%-16s %8u\n", "RspQ Gen:", evtq->gen); + } else if (r == 1) { + const struct sge_rspq *intrq = &adapter->sge.intrq; + + seq_printf(seq, "%-8s %16s\n", "QType:", "Interrupt Queue"); + seq_printf(seq, "%-16s %8u\n", "RspQNullInts:", + intrq->unhandled_irqs); + seq_printf(seq, "%-16s %8u\n", "RspQ CIdx:", intrq->cidx); + seq_printf(seq, "%-16s %8u\n", "RspQ Gen:", intrq->gen); + } + + #undef R + #undef T + #undef S + #undef R3 + #undef T3 + #undef S3 + + return 0; +} + +/* + * Return the number of "entries" in our "file". We group the multi-Queue + * sections with QPL Queue Sets per "entry". The sections of the output are: + * + * Ethernet RX/TX Queue Sets + * Firmware Event Queue + * Forwarded Interrupt Queue (if in MSI mode) + */ +static int sge_qstats_entries(const struct adapter *adapter) +{ + return DIV_ROUND_UP(adapter->sge.ethqsets, QPL) + 1 + + ((adapter->flags & USING_MSI) != 0); +} + +static void *sge_qstats_start(struct seq_file *seq, loff_t *pos) +{ + int entries = sge_qstats_entries(seq->private); + + return *pos < entries ? (void *)((uintptr_t)*pos + 1) : NULL; +} + +static void sge_qstats_stop(struct seq_file *seq, void *v) +{ +} + +static void *sge_qstats_next(struct seq_file *seq, void *v, loff_t *pos) +{ + int entries = sge_qstats_entries(seq->private); + + (*pos)++; + return *pos < entries ? (void *)((uintptr_t)*pos + 1) : NULL; +} + +static const struct seq_operations sge_qstats_seq_ops = { + .start = sge_qstats_start, + .next = sge_qstats_next, + .stop = sge_qstats_stop, + .show = sge_qstats_show +}; + +static int sge_qstats_open(struct inode *inode, struct file *file) +{ + int res = seq_open(file, &sge_qstats_seq_ops); + + if (res == 0) { + struct seq_file *seq = file->private_data; + seq->private = inode->i_private; + } + return res; +} + +static const struct file_operations sge_qstats_proc_fops = { + .owner = THIS_MODULE, + .open = sge_qstats_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/* + * Show PCI-E SR-IOV Virtual Function Resource Limits. + */ +static int resources_show(struct seq_file *seq, void *v) +{ + struct adapter *adapter = seq->private; + struct vf_resources *vfres = &adapter->params.vfres; + + #define S(desc, fmt, var) \ + seq_printf(seq, "%-60s " fmt "\n", \ + desc " (" #var "):", vfres->var) + + S("Virtual Interfaces", "%d", nvi); + S("Egress Queues", "%d", neq); + S("Ethernet Control", "%d", nethctrl); + S("Ingress Queues/w Free Lists/Interrupts", "%d", niqflint); + S("Ingress Queues", "%d", niq); + S("Traffic Class", "%d", tc); + S("Port Access Rights Mask", "%#x", pmask); + S("MAC Address Filters", "%d", nexactf); + S("Firmware Command Read Capabilities", "%#x", r_caps); + S("Firmware Command Write/Execute Capabilities", "%#x", wx_caps); + + #undef S + + return 0; +} + +static int resources_open(struct inode *inode, struct file *file) +{ + return single_open(file, resources_show, inode->i_private); +} + +static const struct file_operations resources_proc_fops = { + .owner = THIS_MODULE, + .open = resources_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +/* + * Show Virtual Interfaces. + */ +static int interfaces_show(struct seq_file *seq, void *v) +{ + if (v == SEQ_START_TOKEN) { + seq_puts(seq, "Interface Port VIID\n"); + } else { + struct adapter *adapter = seq->private; + int pidx = (uintptr_t)v - 2; + struct net_device *dev = adapter->port[pidx]; + struct port_info *pi = netdev_priv(dev); + + seq_printf(seq, "%9s %4d %#5x\n", + dev->name, pi->port_id, pi->viid); + } + return 0; +} + +static inline void *interfaces_get_idx(struct adapter *adapter, loff_t pos) +{ + return pos <= adapter->params.nports + ? (void *)(uintptr_t)(pos + 1) + : NULL; +} + +static void *interfaces_start(struct seq_file *seq, loff_t *pos) +{ + return *pos + ? interfaces_get_idx(seq->private, *pos) + : SEQ_START_TOKEN; +} + +static void *interfaces_next(struct seq_file *seq, void *v, loff_t *pos) +{ + (*pos)++; + return interfaces_get_idx(seq->private, *pos); +} + +static void interfaces_stop(struct seq_file *seq, void *v) +{ +} + +static const struct seq_operations interfaces_seq_ops = { + .start = interfaces_start, + .next = interfaces_next, + .stop = interfaces_stop, + .show = interfaces_show +}; + +static int interfaces_open(struct inode *inode, struct file *file) +{ + int res = seq_open(file, &interfaces_seq_ops); + + if (res == 0) { + struct seq_file *seq = file->private_data; + seq->private = inode->i_private; + } + return res; +} + +static const struct file_operations interfaces_proc_fops = { + .owner = THIS_MODULE, + .open = interfaces_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/* + * /sys/kernel/debugfs/cxgb4vf/ files list. + */ +struct cxgb4vf_debugfs_entry { + const char *name; /* name of debugfs node */ + mode_t mode; /* file system mode */ + const struct file_operations *fops; +}; + +static struct cxgb4vf_debugfs_entry debugfs_files[] = { + { "sge_qinfo", S_IRUGO, &sge_qinfo_debugfs_fops }, + { "sge_qstats", S_IRUGO, &sge_qstats_proc_fops }, + { "resources", S_IRUGO, &resources_proc_fops }, + { "interfaces", S_IRUGO, &interfaces_proc_fops }, +}; + +/* + * Module and device initialization and cleanup code. + * ================================================== + */ + +/* + * Set up out /sys/kernel/debug/cxgb4vf sub-nodes. We assume that the + * directory (debugfs_root) has already been set up. + */ +static int __devinit setup_debugfs(struct adapter *adapter) +{ + int i; + + BUG_ON(IS_ERR_OR_NULL(adapter->debugfs_root)); + + /* + * Debugfs support is best effort. + */ + for (i = 0; i < ARRAY_SIZE(debugfs_files); i++) + (void)debugfs_create_file(debugfs_files[i].name, + debugfs_files[i].mode, + adapter->debugfs_root, + (void *)adapter, + debugfs_files[i].fops); + + return 0; +} + +/* + * Tear down the /sys/kernel/debug/cxgb4vf sub-nodes created above. We leave + * it to our caller to tear down the directory (debugfs_root). + */ +static void cleanup_debugfs(struct adapter *adapter) +{ + BUG_ON(IS_ERR_OR_NULL(adapter->debugfs_root)); + + /* + * Unlike our sister routine cleanup_proc(), we don't need to remove + * individual entries because a call will be made to + * debugfs_remove_recursive(). We just need to clean up any ancillary + * persistent state. + */ + /* nothing to do */ +} + +/* + * Perform early "adapter" initialization. This is where we discover what + * adapter parameters we're going to be using and initialize basic adapter + * hardware support. + */ +static int __devinit adap_init0(struct adapter *adapter) +{ + struct vf_resources *vfres = &adapter->params.vfres; + struct sge_params *sge_params = &adapter->params.sge; + struct sge *s = &adapter->sge; + unsigned int ethqsets; + int err; + + /* + * Wait for the device to become ready before proceeding ... + */ + err = t4vf_wait_dev_ready(adapter); + if (err) { + dev_err(adapter->pdev_dev, "device didn't become ready:" + " err=%d\n", err); + return err; + } + + /* + * Some environments do not properly handle PCIE FLRs -- e.g. in Linux + * 2.6.31 and later we can't call pci_reset_function() in order to + * issue an FLR because of a self- deadlock on the device semaphore. + * Meanwhile, the OS infrastructure doesn't issue FLRs in all the + * cases where they're needed -- for instance, some versions of KVM + * fail to reset "Assigned Devices" when the VM reboots. Therefore we + * use the firmware based reset in order to reset any per function + * state. + */ + err = t4vf_fw_reset(adapter); + if (err < 0) { + dev_err(adapter->pdev_dev, "FW reset failed: err=%d\n", err); + return err; + } + + /* + * Grab basic operational parameters. These will predominantly have + * been set up by the Physical Function Driver or will be hard coded + * into the adapter. We just have to live with them ... Note that + * we _must_ get our VPD parameters before our SGE parameters because + * we need to know the adapter's core clock from the VPD in order to + * properly decode the SGE Timer Values. + */ + err = t4vf_get_dev_params(adapter); + if (err) { + dev_err(adapter->pdev_dev, "unable to retrieve adapter" + " device parameters: err=%d\n", err); + return err; + } + err = t4vf_get_vpd_params(adapter); + if (err) { + dev_err(adapter->pdev_dev, "unable to retrieve adapter" + " VPD parameters: err=%d\n", err); + return err; + } + err = t4vf_get_sge_params(adapter); + if (err) { + dev_err(adapter->pdev_dev, "unable to retrieve adapter" + " SGE parameters: err=%d\n", err); + return err; + } + err = t4vf_get_rss_glb_config(adapter); + if (err) { + dev_err(adapter->pdev_dev, "unable to retrieve adapter" + " RSS parameters: err=%d\n", err); + return err; + } + if (adapter->params.rss.mode != + FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL) { + dev_err(adapter->pdev_dev, "unable to operate with global RSS" + " mode %d\n", adapter->params.rss.mode); + return -EINVAL; + } + err = t4vf_sge_init(adapter); + if (err) { + dev_err(adapter->pdev_dev, "unable to use adapter parameters:" + " err=%d\n", err); + return err; + } + + /* + * Retrieve our RX interrupt holdoff timer values and counter + * threshold values from the SGE parameters. + */ + s->timer_val[0] = core_ticks_to_us(adapter, + TIMERVALUE0_GET(sge_params->sge_timer_value_0_and_1)); + s->timer_val[1] = core_ticks_to_us(adapter, + TIMERVALUE1_GET(sge_params->sge_timer_value_0_and_1)); + s->timer_val[2] = core_ticks_to_us(adapter, + TIMERVALUE0_GET(sge_params->sge_timer_value_2_and_3)); + s->timer_val[3] = core_ticks_to_us(adapter, + TIMERVALUE1_GET(sge_params->sge_timer_value_2_and_3)); + s->timer_val[4] = core_ticks_to_us(adapter, + TIMERVALUE0_GET(sge_params->sge_timer_value_4_and_5)); + s->timer_val[5] = core_ticks_to_us(adapter, + TIMERVALUE1_GET(sge_params->sge_timer_value_4_and_5)); + + s->counter_val[0] = + THRESHOLD_0_GET(sge_params->sge_ingress_rx_threshold); + s->counter_val[1] = + THRESHOLD_1_GET(sge_params->sge_ingress_rx_threshold); + s->counter_val[2] = + THRESHOLD_2_GET(sge_params->sge_ingress_rx_threshold); + s->counter_val[3] = + THRESHOLD_3_GET(sge_params->sge_ingress_rx_threshold); + + /* + * Grab our Virtual Interface resource allocation, extract the + * features that we're interested in and do a bit of sanity testing on + * what we discover. + */ + err = t4vf_get_vfres(adapter); + if (err) { + dev_err(adapter->pdev_dev, "unable to get virtual interface" + " resources: err=%d\n", err); + return err; + } + + /* + * The number of "ports" which we support is equal to the number of + * Virtual Interfaces with which we've been provisioned. + */ + adapter->params.nports = vfres->nvi; + if (adapter->params.nports > MAX_NPORTS) { + dev_warn(adapter->pdev_dev, "only using %d of %d allowed" + " virtual interfaces\n", MAX_NPORTS, + adapter->params.nports); + adapter->params.nports = MAX_NPORTS; + } + + /* + * We need to reserve a number of the ingress queues with Free List + * and Interrupt capabilities for special interrupt purposes (like + * asynchronous firmware messages, or forwarded interrupts if we're + * using MSI). The rest of the FL/Intr-capable ingress queues will be + * matched up one-for-one with Ethernet/Control egress queues in order + * to form "Queue Sets" which will be aportioned between the "ports". + * For each Queue Set, we'll need the ability to allocate two Egress + * Contexts -- one for the Ingress Queue Free List and one for the TX + * Ethernet Queue. + */ + ethqsets = vfres->niqflint - INGQ_EXTRAS; + if (vfres->nethctrl != ethqsets) { + dev_warn(adapter->pdev_dev, "unequal number of [available]" + " ingress/egress queues (%d/%d); using minimum for" + " number of Queue Sets\n", ethqsets, vfres->nethctrl); + ethqsets = min(vfres->nethctrl, ethqsets); + } + if (vfres->neq < ethqsets*2) { + dev_warn(adapter->pdev_dev, "Not enough Egress Contexts (%d)" + " to support Queue Sets (%d); reducing allowed Queue" + " Sets\n", vfres->neq, ethqsets); + ethqsets = vfres->neq/2; + } + if (ethqsets > MAX_ETH_QSETS) { + dev_warn(adapter->pdev_dev, "only using %d of %d allowed Queue" + " Sets\n", MAX_ETH_QSETS, adapter->sge.max_ethqsets); + ethqsets = MAX_ETH_QSETS; + } + if (vfres->niq != 0 || vfres->neq > ethqsets*2) { + dev_warn(adapter->pdev_dev, "unused resources niq/neq (%d/%d)" + " ignored\n", vfres->niq, vfres->neq - ethqsets*2); + } + adapter->sge.max_ethqsets = ethqsets; + + /* + * Check for various parameter sanity issues. Most checks simply + * result in us using fewer resources than our provissioning but we + * do need at least one "port" with which to work ... + */ + if (adapter->sge.max_ethqsets < adapter->params.nports) { + dev_warn(adapter->pdev_dev, "only using %d of %d available" + " virtual interfaces (too few Queue Sets)\n", + adapter->sge.max_ethqsets, adapter->params.nports); + adapter->params.nports = adapter->sge.max_ethqsets; + } + if (adapter->params.nports == 0) { + dev_err(adapter->pdev_dev, "no virtual interfaces configured/" + "usable!\n"); + return -EINVAL; + } + return 0; +} + +static inline void init_rspq(struct sge_rspq *rspq, u8 timer_idx, + u8 pkt_cnt_idx, unsigned int size, + unsigned int iqe_size) +{ + rspq->intr_params = (QINTR_TIMER_IDX(timer_idx) | + (pkt_cnt_idx < SGE_NCOUNTERS ? QINTR_CNT_EN : 0)); + rspq->pktcnt_idx = (pkt_cnt_idx < SGE_NCOUNTERS + ? pkt_cnt_idx + : 0); + rspq->iqe_len = iqe_size; + rspq->size = size; +} + +/* + * Perform default configuration of DMA queues depending on the number and + * type of ports we found and the number of available CPUs. Most settings can + * be modified by the admin via ethtool and cxgbtool prior to the adapter + * being brought up for the first time. + */ +static void __devinit cfg_queues(struct adapter *adapter) +{ + struct sge *s = &adapter->sge; + int q10g, n10g, qidx, pidx, qs; + size_t iqe_size; + + /* + * We should not be called till we know how many Queue Sets we can + * support. In particular, this means that we need to know what kind + * of interrupts we'll be using ... + */ + BUG_ON((adapter->flags & (USING_MSIX|USING_MSI)) == 0); + + /* + * Count the number of 10GbE Virtual Interfaces that we have. + */ + n10g = 0; + for_each_port(adapter, pidx) + n10g += is_10g_port(&adap2pinfo(adapter, pidx)->link_cfg); + + /* + * We default to 1 queue per non-10G port and up to # of cores queues + * per 10G port. + */ + if (n10g == 0) + q10g = 0; + else { + int n1g = (adapter->params.nports - n10g); + q10g = (adapter->sge.max_ethqsets - n1g) / n10g; + if (q10g > num_online_cpus()) + q10g = num_online_cpus(); + } + + /* + * Allocate the "Queue Sets" to the various Virtual Interfaces. + * The layout will be established in setup_sge_queues() when the + * adapter is brough up for the first time. + */ + qidx = 0; + for_each_port(adapter, pidx) { + struct port_info *pi = adap2pinfo(adapter, pidx); + + pi->first_qset = qidx; + pi->nqsets = is_10g_port(&pi->link_cfg) ? q10g : 1; + qidx += pi->nqsets; + } + s->ethqsets = qidx; + + /* + * The Ingress Queue Entry Size for our various Response Queues needs + * to be big enough to accommodate the largest message we can receive + * from the chip/firmware; which is 64 bytes ... + */ + iqe_size = 64; + + /* + * Set up default Queue Set parameters ... Start off with the + * shortest interrupt holdoff timer. + */ + for (qs = 0; qs < s->max_ethqsets; qs++) { + struct sge_eth_rxq *rxq = &s->ethrxq[qs]; + struct sge_eth_txq *txq = &s->ethtxq[qs]; + + init_rspq(&rxq->rspq, 0, 0, 1024, iqe_size); + rxq->fl.size = 72; + txq->q.size = 1024; + } + + /* + * The firmware event queue is used for link state changes and + * notifications of TX DMA completions. + */ + init_rspq(&s->fw_evtq, SGE_TIMER_RSTRT_CNTR, 0, 512, iqe_size); + + /* + * The forwarded interrupt queue is used when we're in MSI interrupt + * mode. In this mode all interrupts associated with RX queues will + * be forwarded to a single queue which we'll associate with our MSI + * interrupt vector. The messages dropped in the forwarded interrupt + * queue will indicate which ingress queue needs servicing ... This + * queue needs to be large enough to accommodate all of the ingress + * queues which are forwarding their interrupt (+1 to prevent the PIDX + * from equalling the CIDX if every ingress queue has an outstanding + * interrupt). The queue doesn't need to be any larger because no + * ingress queue will ever have more than one outstanding interrupt at + * any time ... + */ + init_rspq(&s->intrq, SGE_TIMER_RSTRT_CNTR, 0, MSIX_ENTRIES + 1, + iqe_size); +} + +/* + * Reduce the number of Ethernet queues across all ports to at most n. + * n provides at least one queue per port. + */ +static void __devinit reduce_ethqs(struct adapter *adapter, int n) +{ + int i; + struct port_info *pi; + + /* + * While we have too many active Ether Queue Sets, interate across the + * "ports" and reduce their individual Queue Set allocations. + */ + BUG_ON(n < adapter->params.nports); + while (n < adapter->sge.ethqsets) + for_each_port(adapter, i) { + pi = adap2pinfo(adapter, i); + if (pi->nqsets > 1) { + pi->nqsets--; + adapter->sge.ethqsets--; + if (adapter->sge.ethqsets <= n) + break; + } + } + + /* + * Reassign the starting Queue Sets for each of the "ports" ... + */ + n = 0; + for_each_port(adapter, i) { + pi = adap2pinfo(adapter, i); + pi->first_qset = n; + n += pi->nqsets; + } +} + +/* + * We need to grab enough MSI-X vectors to cover our interrupt needs. Ideally + * we get a separate MSI-X vector for every "Queue Set" plus any extras we + * need. Minimally we need one for every Virtual Interface plus those needed + * for our "extras". Note that this process may lower the maximum number of + * allowed Queue Sets ... + */ +static int __devinit enable_msix(struct adapter *adapter) +{ + int i, err, want, need; + struct msix_entry entries[MSIX_ENTRIES]; + struct sge *s = &adapter->sge; + + for (i = 0; i < MSIX_ENTRIES; ++i) + entries[i].entry = i; + + /* + * We _want_ enough MSI-X interrupts to cover all of our "Queue Sets" + * plus those needed for our "extras" (for example, the firmware + * message queue). We _need_ at least one "Queue Set" per Virtual + * Interface plus those needed for our "extras". So now we get to see + * if the song is right ... + */ + want = s->max_ethqsets + MSIX_EXTRAS; + need = adapter->params.nports + MSIX_EXTRAS; + while ((err = pci_enable_msix(adapter->pdev, entries, want)) >= need) + want = err; + + if (err == 0) { + int nqsets = want - MSIX_EXTRAS; + if (nqsets < s->max_ethqsets) { + dev_warn(adapter->pdev_dev, "only enough MSI-X vectors" + " for %d Queue Sets\n", nqsets); + s->max_ethqsets = nqsets; + if (nqsets < s->ethqsets) + reduce_ethqs(adapter, nqsets); + } + for (i = 0; i < want; ++i) + adapter->msix_info[i].vec = entries[i].vector; + } else if (err > 0) { + pci_disable_msix(adapter->pdev); + dev_info(adapter->pdev_dev, "only %d MSI-X vectors left," + " not using MSI-X\n", err); + } + return err; +} + +static const struct net_device_ops cxgb4vf_netdev_ops = { + .ndo_open = cxgb4vf_open, + .ndo_stop = cxgb4vf_stop, + .ndo_start_xmit = t4vf_eth_xmit, + .ndo_get_stats = cxgb4vf_get_stats, + .ndo_set_rx_mode = cxgb4vf_set_rxmode, + .ndo_set_mac_address = cxgb4vf_set_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = cxgb4vf_do_ioctl, + .ndo_change_mtu = cxgb4vf_change_mtu, + .ndo_fix_features = cxgb4vf_fix_features, + .ndo_set_features = cxgb4vf_set_features, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = cxgb4vf_poll_controller, +#endif +}; + +/* + * "Probe" a device: initialize a device and construct all kernel and driver + * state needed to manage the device. This routine is called "init_one" in + * the PF Driver ... + */ +static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + static int version_printed; + + int pci_using_dac; + int err, pidx; + unsigned int pmask; + struct adapter *adapter; + struct port_info *pi; + struct net_device *netdev; + + /* + * Print our driver banner the first time we're called to initialize a + * device. + */ + if (version_printed == 0) { + printk(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION); + version_printed = 1; + } + + /* + * Initialize generic PCI device state. + */ + err = pci_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, "cannot enable PCI device\n"); + return err; + } + + /* + * Reserve PCI resources for the device. If we can't get them some + * other driver may have already claimed the device ... + */ + err = pci_request_regions(pdev, KBUILD_MODNAME); + if (err) { + dev_err(&pdev->dev, "cannot obtain PCI resources\n"); + goto err_disable_device; + } + + /* + * Set up our DMA mask: try for 64-bit address masking first and + * fall back to 32-bit if we can't get 64 bits ... + */ + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + if (err == 0) { + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + if (err) { + dev_err(&pdev->dev, "unable to obtain 64-bit DMA for" + " coherent allocations\n"); + goto err_release_regions; + } + pci_using_dac = 1; + } else { + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (err != 0) { + dev_err(&pdev->dev, "no usable DMA configuration\n"); + goto err_release_regions; + } + pci_using_dac = 0; + } + + /* + * Enable bus mastering for the device ... + */ + pci_set_master(pdev); + + /* + * Allocate our adapter data structure and attach it to the device. + */ + adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); + if (!adapter) { + err = -ENOMEM; + goto err_release_regions; + } + pci_set_drvdata(pdev, adapter); + adapter->pdev = pdev; + adapter->pdev_dev = &pdev->dev; + + /* + * Initialize SMP data synchronization resources. + */ + spin_lock_init(&adapter->stats_lock); + + /* + * Map our I/O registers in BAR0. + */ + adapter->regs = pci_ioremap_bar(pdev, 0); + if (!adapter->regs) { + dev_err(&pdev->dev, "cannot map device registers\n"); + err = -ENOMEM; + goto err_free_adapter; + } + + /* + * Initialize adapter level features. + */ + adapter->name = pci_name(pdev); + adapter->msg_enable = dflt_msg_enable; + err = adap_init0(adapter); + if (err) + goto err_unmap_bar; + + /* + * Allocate our "adapter ports" and stitch everything together. + */ + pmask = adapter->params.vfres.pmask; + for_each_port(adapter, pidx) { + int port_id, viid; + + /* + * We simplistically allocate our virtual interfaces + * sequentially across the port numbers to which we have + * access rights. This should be configurable in some manner + * ... + */ + if (pmask == 0) + break; + port_id = ffs(pmask) - 1; + pmask &= ~(1 << port_id); + viid = t4vf_alloc_vi(adapter, port_id); + if (viid < 0) { + dev_err(&pdev->dev, "cannot allocate VI for port %d:" + " err=%d\n", port_id, viid); + err = viid; + goto err_free_dev; + } + + /* + * Allocate our network device and stitch things together. + */ + netdev = alloc_etherdev_mq(sizeof(struct port_info), + MAX_PORT_QSETS); + if (netdev == NULL) { + dev_err(&pdev->dev, "cannot allocate netdev for" + " port %d\n", port_id); + t4vf_free_vi(adapter, viid); + err = -ENOMEM; + goto err_free_dev; + } + adapter->port[pidx] = netdev; + SET_NETDEV_DEV(netdev, &pdev->dev); + pi = netdev_priv(netdev); + pi->adapter = adapter; + pi->pidx = pidx; + pi->port_id = port_id; + pi->viid = viid; + + /* + * Initialize the starting state of our "port" and register + * it. + */ + pi->xact_addr_filt = -1; + netif_carrier_off(netdev); + netdev->irq = pdev->irq; + + netdev->hw_features = NETIF_F_SG | TSO_FLAGS | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_HW_VLAN_RX | NETIF_F_RXCSUM; + netdev->vlan_features = NETIF_F_SG | TSO_FLAGS | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_HIGHDMA; + netdev->features = netdev->hw_features | NETIF_F_HW_VLAN_TX; + if (pci_using_dac) + netdev->features |= NETIF_F_HIGHDMA; + + netdev->netdev_ops = &cxgb4vf_netdev_ops; + SET_ETHTOOL_OPS(netdev, &cxgb4vf_ethtool_ops); + + /* + * Initialize the hardware/software state for the port. + */ + err = t4vf_port_init(adapter, pidx); + if (err) { + dev_err(&pdev->dev, "cannot initialize port %d\n", + pidx); + goto err_free_dev; + } + } + + /* + * The "card" is now ready to go. If any errors occur during device + * registration we do not fail the whole "card" but rather proceed + * only with the ports we manage to register successfully. However we + * must register at least one net device. + */ + for_each_port(adapter, pidx) { + netdev = adapter->port[pidx]; + if (netdev == NULL) + continue; + + err = register_netdev(netdev); + if (err) { + dev_warn(&pdev->dev, "cannot register net device %s," + " skipping\n", netdev->name); + continue; + } + + set_bit(pidx, &adapter->registered_device_map); + } + if (adapter->registered_device_map == 0) { + dev_err(&pdev->dev, "could not register any net devices\n"); + goto err_free_dev; + } + + /* + * Set up our debugfs entries. + */ + if (!IS_ERR_OR_NULL(cxgb4vf_debugfs_root)) { + adapter->debugfs_root = + debugfs_create_dir(pci_name(pdev), + cxgb4vf_debugfs_root); + if (IS_ERR_OR_NULL(adapter->debugfs_root)) + dev_warn(&pdev->dev, "could not create debugfs" + " directory"); + else + setup_debugfs(adapter); + } + + /* + * See what interrupts we'll be using. If we've been configured to + * use MSI-X interrupts, try to enable them but fall back to using + * MSI interrupts if we can't enable MSI-X interrupts. If we can't + * get MSI interrupts we bail with the error. + */ + if (msi == MSI_MSIX && enable_msix(adapter) == 0) + adapter->flags |= USING_MSIX; + else { + err = pci_enable_msi(pdev); + if (err) { + dev_err(&pdev->dev, "Unable to allocate %s interrupts;" + " err=%d\n", + msi == MSI_MSIX ? "MSI-X or MSI" : "MSI", err); + goto err_free_debugfs; + } + adapter->flags |= USING_MSI; + } + + /* + * Now that we know how many "ports" we have and what their types are, + * and how many Queue Sets we can support, we can configure our queue + * resources. + */ + cfg_queues(adapter); + + /* + * Print a short notice on the existence and configuration of the new + * VF network device ... + */ + for_each_port(adapter, pidx) { + dev_info(adapter->pdev_dev, "%s: Chelsio VF NIC PCIe %s\n", + adapter->port[pidx]->name, + (adapter->flags & USING_MSIX) ? "MSI-X" : + (adapter->flags & USING_MSI) ? "MSI" : ""); + } + + /* + * Return success! + */ + return 0; + + /* + * Error recovery and exit code. Unwind state that's been created + * so far and return the error. + */ + +err_free_debugfs: + if (!IS_ERR_OR_NULL(adapter->debugfs_root)) { + cleanup_debugfs(adapter); + debugfs_remove_recursive(adapter->debugfs_root); + } + +err_free_dev: + for_each_port(adapter, pidx) { + netdev = adapter->port[pidx]; + if (netdev == NULL) + continue; + pi = netdev_priv(netdev); + t4vf_free_vi(adapter, pi->viid); + if (test_bit(pidx, &adapter->registered_device_map)) + unregister_netdev(netdev); + free_netdev(netdev); + } + +err_unmap_bar: + iounmap(adapter->regs); + +err_free_adapter: + kfree(adapter); + pci_set_drvdata(pdev, NULL); + +err_release_regions: + pci_release_regions(pdev); + pci_set_drvdata(pdev, NULL); + pci_clear_master(pdev); + +err_disable_device: + pci_disable_device(pdev); + + return err; +} + +/* + * "Remove" a device: tear down all kernel and driver state created in the + * "probe" routine and quiesce the device (disable interrupts, etc.). (Note + * that this is called "remove_one" in the PF Driver.) + */ +static void __devexit cxgb4vf_pci_remove(struct pci_dev *pdev) +{ + struct adapter *adapter = pci_get_drvdata(pdev); + + /* + * Tear down driver state associated with device. + */ + if (adapter) { + int pidx; + + /* + * Stop all of our activity. Unregister network port, + * disable interrupts, etc. + */ + for_each_port(adapter, pidx) + if (test_bit(pidx, &adapter->registered_device_map)) + unregister_netdev(adapter->port[pidx]); + t4vf_sge_stop(adapter); + if (adapter->flags & USING_MSIX) { + pci_disable_msix(adapter->pdev); + adapter->flags &= ~USING_MSIX; + } else if (adapter->flags & USING_MSI) { + pci_disable_msi(adapter->pdev); + adapter->flags &= ~USING_MSI; + } + + /* + * Tear down our debugfs entries. + */ + if (!IS_ERR_OR_NULL(adapter->debugfs_root)) { + cleanup_debugfs(adapter); + debugfs_remove_recursive(adapter->debugfs_root); + } + + /* + * Free all of the various resources which we've acquired ... + */ + t4vf_free_sge_resources(adapter); + for_each_port(adapter, pidx) { + struct net_device *netdev = adapter->port[pidx]; + struct port_info *pi; + + if (netdev == NULL) + continue; + + pi = netdev_priv(netdev); + t4vf_free_vi(adapter, pi->viid); + free_netdev(netdev); + } + iounmap(adapter->regs); + kfree(adapter); + pci_set_drvdata(pdev, NULL); + } + + /* + * Disable the device and release its PCI resources. + */ + pci_disable_device(pdev); + pci_clear_master(pdev); + pci_release_regions(pdev); +} + +/* + * "Shutdown" quiesce the device, stopping Ingress Packet and Interrupt + * delivery. + */ +static void __devexit cxgb4vf_pci_shutdown(struct pci_dev *pdev) +{ + struct adapter *adapter; + int pidx; + + adapter = pci_get_drvdata(pdev); + if (!adapter) + return; + + /* + * Disable all Virtual Interfaces. This will shut down the + * delivery of all ingress packets into the chip for these + * Virtual Interfaces. + */ + for_each_port(adapter, pidx) { + struct net_device *netdev; + struct port_info *pi; + + if (!test_bit(pidx, &adapter->registered_device_map)) + continue; + + netdev = adapter->port[pidx]; + if (!netdev) + continue; + + pi = netdev_priv(netdev); + t4vf_enable_vi(adapter, pi->viid, false, false); + } + + /* + * Free up all Queues which will prevent further DMA and + * Interrupts allowing various internal pathways to drain. + */ + t4vf_free_sge_resources(adapter); +} + +/* + * PCI Device registration data structures. + */ +#define CH_DEVICE(devid, idx) \ + { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, PCI_ANY_ID, 0, 0, idx } + +static struct pci_device_id cxgb4vf_pci_tbl[] = { + CH_DEVICE(0xb000, 0), /* PE10K FPGA */ + CH_DEVICE(0x4800, 0), /* T440-dbg */ + CH_DEVICE(0x4801, 0), /* T420-cr */ + CH_DEVICE(0x4802, 0), /* T422-cr */ + CH_DEVICE(0x4803, 0), /* T440-cr */ + CH_DEVICE(0x4804, 0), /* T420-bch */ + CH_DEVICE(0x4805, 0), /* T440-bch */ + CH_DEVICE(0x4806, 0), /* T460-ch */ + CH_DEVICE(0x4807, 0), /* T420-so */ + CH_DEVICE(0x4808, 0), /* T420-cx */ + CH_DEVICE(0x4809, 0), /* T420-bt */ + CH_DEVICE(0x480a, 0), /* T404-bt */ + { 0, } +}; + +MODULE_DESCRIPTION(DRV_DESC); +MODULE_AUTHOR("Chelsio Communications"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_VERSION(DRV_VERSION); +MODULE_DEVICE_TABLE(pci, cxgb4vf_pci_tbl); + +static struct pci_driver cxgb4vf_driver = { + .name = KBUILD_MODNAME, + .id_table = cxgb4vf_pci_tbl, + .probe = cxgb4vf_pci_probe, + .remove = __devexit_p(cxgb4vf_pci_remove), + .shutdown = __devexit_p(cxgb4vf_pci_shutdown), +}; + +/* + * Initialize global driver state. + */ +static int __init cxgb4vf_module_init(void) +{ + int ret; + + /* + * Vet our module parameters. + */ + if (msi != MSI_MSIX && msi != MSI_MSI) { + printk(KERN_WARNING KBUILD_MODNAME + ": bad module parameter msi=%d; must be %d" + " (MSI-X or MSI) or %d (MSI)\n", + msi, MSI_MSIX, MSI_MSI); + return -EINVAL; + } + + /* Debugfs support is optional, just warn if this fails */ + cxgb4vf_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); + if (IS_ERR_OR_NULL(cxgb4vf_debugfs_root)) + printk(KERN_WARNING KBUILD_MODNAME ": could not create" + " debugfs entry, continuing\n"); + + ret = pci_register_driver(&cxgb4vf_driver); + if (ret < 0 && !IS_ERR_OR_NULL(cxgb4vf_debugfs_root)) + debugfs_remove(cxgb4vf_debugfs_root); + return ret; +} + +/* + * Tear down global driver state. + */ +static void __exit cxgb4vf_module_exit(void) +{ + pci_unregister_driver(&cxgb4vf_driver); + debugfs_remove(cxgb4vf_debugfs_root); +} + +module_init(cxgb4vf_module_init); +module_exit(cxgb4vf_module_exit); diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c new file mode 100644 index 000000000000..cffb328c46c3 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c @@ -0,0 +1,2465 @@ +/* + * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet + * driver for Linux. + * + * Copyright (c) 2009-2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "t4vf_common.h" +#include "t4vf_defs.h" + +#include "../cxgb4/t4_regs.h" +#include "../cxgb4/t4fw_api.h" +#include "../cxgb4/t4_msg.h" + +/* + * Decoded Adapter Parameters. + */ +static u32 FL_PG_ORDER; /* large page allocation size */ +static u32 STAT_LEN; /* length of status page at ring end */ +static u32 PKTSHIFT; /* padding between CPL and packet data */ +static u32 FL_ALIGN; /* response queue message alignment */ + +/* + * Constants ... + */ +enum { + /* + * Egress Queue sizes, producer and consumer indices are all in units + * of Egress Context Units bytes. Note that as far as the hardware is + * concerned, the free list is an Egress Queue (the host produces free + * buffers which the hardware consumes) and free list entries are + * 64-bit PCI DMA addresses. + */ + EQ_UNIT = SGE_EQ_IDXSIZE, + FL_PER_EQ_UNIT = EQ_UNIT / sizeof(__be64), + TXD_PER_EQ_UNIT = EQ_UNIT / sizeof(__be64), + + /* + * Max number of TX descriptors we clean up at a time. Should be + * modest as freeing skbs isn't cheap and it happens while holding + * locks. We just need to free packets faster than they arrive, we + * eventually catch up and keep the amortized cost reasonable. + */ + MAX_TX_RECLAIM = 16, + + /* + * Max number of Rx buffers we replenish at a time. Again keep this + * modest, allocating buffers isn't cheap either. + */ + MAX_RX_REFILL = 16, + + /* + * Period of the Rx queue check timer. This timer is infrequent as it + * has something to do only when the system experiences severe memory + * shortage. + */ + RX_QCHECK_PERIOD = (HZ / 2), + + /* + * Period of the TX queue check timer and the maximum number of TX + * descriptors to be reclaimed by the TX timer. + */ + TX_QCHECK_PERIOD = (HZ / 2), + MAX_TIMER_TX_RECLAIM = 100, + + /* + * An FL with <= FL_STARVE_THRES buffers is starving and a periodic + * timer will attempt to refill it. + */ + FL_STARVE_THRES = 4, + + /* + * Suspend an Ethernet TX queue with fewer available descriptors than + * this. We always want to have room for a maximum sized packet: + * inline immediate data + MAX_SKB_FRAGS. This is the same as + * calc_tx_flits() for a TSO packet with nr_frags == MAX_SKB_FRAGS + * (see that function and its helpers for a description of the + * calculation). + */ + ETHTXQ_MAX_FRAGS = MAX_SKB_FRAGS + 1, + ETHTXQ_MAX_SGL_LEN = ((3 * (ETHTXQ_MAX_FRAGS-1))/2 + + ((ETHTXQ_MAX_FRAGS-1) & 1) + + 2), + ETHTXQ_MAX_HDR = (sizeof(struct fw_eth_tx_pkt_vm_wr) + + sizeof(struct cpl_tx_pkt_lso_core) + + sizeof(struct cpl_tx_pkt_core)) / sizeof(__be64), + ETHTXQ_MAX_FLITS = ETHTXQ_MAX_SGL_LEN + ETHTXQ_MAX_HDR, + + ETHTXQ_STOP_THRES = 1 + DIV_ROUND_UP(ETHTXQ_MAX_FLITS, TXD_PER_EQ_UNIT), + + /* + * Max TX descriptor space we allow for an Ethernet packet to be + * inlined into a WR. This is limited by the maximum value which + * we can specify for immediate data in the firmware Ethernet TX + * Work Request. + */ + MAX_IMM_TX_PKT_LEN = FW_WR_IMMDLEN_MASK, + + /* + * Max size of a WR sent through a control TX queue. + */ + MAX_CTRL_WR_LEN = 256, + + /* + * Maximum amount of data which we'll ever need to inline into a + * TX ring: max(MAX_IMM_TX_PKT_LEN, MAX_CTRL_WR_LEN). + */ + MAX_IMM_TX_LEN = (MAX_IMM_TX_PKT_LEN > MAX_CTRL_WR_LEN + ? MAX_IMM_TX_PKT_LEN + : MAX_CTRL_WR_LEN), + + /* + * For incoming packets less than RX_COPY_THRES, we copy the data into + * an skb rather than referencing the data. We allocate enough + * in-line room in skb's to accommodate pulling in RX_PULL_LEN bytes + * of the data (header). + */ + RX_COPY_THRES = 256, + RX_PULL_LEN = 128, + + /* + * Main body length for sk_buffs used for RX Ethernet packets with + * fragments. Should be >= RX_PULL_LEN but possibly bigger to give + * pskb_may_pull() some room. + */ + RX_SKB_LEN = 512, +}; + +/* + * Software state per TX descriptor. + */ +struct tx_sw_desc { + struct sk_buff *skb; /* socket buffer of TX data source */ + struct ulptx_sgl *sgl; /* scatter/gather list in TX Queue */ +}; + +/* + * Software state per RX Free List descriptor. We keep track of the allocated + * FL page, its size, and its PCI DMA address (if the page is mapped). The FL + * page size and its PCI DMA mapped state are stored in the low bits of the + * PCI DMA address as per below. + */ +struct rx_sw_desc { + struct page *page; /* Free List page buffer */ + dma_addr_t dma_addr; /* PCI DMA address (if mapped) */ + /* and flags (see below) */ +}; + +/* + * The low bits of rx_sw_desc.dma_addr have special meaning. Note that the + * SGE also uses the low 4 bits to determine the size of the buffer. It uses + * those bits to index into the SGE_FL_BUFFER_SIZE[index] register array. + * Since we only use SGE_FL_BUFFER_SIZE0 and SGE_FL_BUFFER_SIZE1, these low 4 + * bits can only contain a 0 or a 1 to indicate which size buffer we're giving + * to the SGE. Thus, our software state of "is the buffer mapped for DMA" is + * maintained in an inverse sense so the hardware never sees that bit high. + */ +enum { + RX_LARGE_BUF = 1 << 0, /* buffer is SGE_FL_BUFFER_SIZE[1] */ + RX_UNMAPPED_BUF = 1 << 1, /* buffer is not mapped */ +}; + +/** + * get_buf_addr - return DMA buffer address of software descriptor + * @sdesc: pointer to the software buffer descriptor + * + * Return the DMA buffer address of a software descriptor (stripping out + * our low-order flag bits). + */ +static inline dma_addr_t get_buf_addr(const struct rx_sw_desc *sdesc) +{ + return sdesc->dma_addr & ~(dma_addr_t)(RX_LARGE_BUF | RX_UNMAPPED_BUF); +} + +/** + * is_buf_mapped - is buffer mapped for DMA? + * @sdesc: pointer to the software buffer descriptor + * + * Determine whether the buffer associated with a software descriptor in + * mapped for DMA or not. + */ +static inline bool is_buf_mapped(const struct rx_sw_desc *sdesc) +{ + return !(sdesc->dma_addr & RX_UNMAPPED_BUF); +} + +/** + * need_skb_unmap - does the platform need unmapping of sk_buffs? + * + * Returns true if the platform needs sk_buff unmapping. The compiler + * optimizes away unnecessary code if this returns true. + */ +static inline int need_skb_unmap(void) +{ +#ifdef CONFIG_NEED_DMA_MAP_STATE + return 1; +#else + return 0; +#endif +} + +/** + * txq_avail - return the number of available slots in a TX queue + * @tq: the TX queue + * + * Returns the number of available descriptors in a TX queue. + */ +static inline unsigned int txq_avail(const struct sge_txq *tq) +{ + return tq->size - 1 - tq->in_use; +} + +/** + * fl_cap - return the capacity of a Free List + * @fl: the Free List + * + * Returns the capacity of a Free List. The capacity is less than the + * size because an Egress Queue Index Unit worth of descriptors needs to + * be left unpopulated, otherwise the Producer and Consumer indices PIDX + * and CIDX will match and the hardware will think the FL is empty. + */ +static inline unsigned int fl_cap(const struct sge_fl *fl) +{ + return fl->size - FL_PER_EQ_UNIT; +} + +/** + * fl_starving - return whether a Free List is starving. + * @fl: the Free List + * + * Tests specified Free List to see whether the number of buffers + * available to the hardware has falled below our "starvation" + * threshold. + */ +static inline bool fl_starving(const struct sge_fl *fl) +{ + return fl->avail - fl->pend_cred <= FL_STARVE_THRES; +} + +/** + * map_skb - map an skb for DMA to the device + * @dev: the egress net device + * @skb: the packet to map + * @addr: a pointer to the base of the DMA mapping array + * + * Map an skb for DMA to the device and return an array of DMA addresses. + */ +static int map_skb(struct device *dev, const struct sk_buff *skb, + dma_addr_t *addr) +{ + const skb_frag_t *fp, *end; + const struct skb_shared_info *si; + + *addr = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); + if (dma_mapping_error(dev, *addr)) + goto out_err; + + si = skb_shinfo(skb); + end = &si->frags[si->nr_frags]; + for (fp = si->frags; fp < end; fp++) { + *++addr = dma_map_page(dev, fp->page, fp->page_offset, fp->size, + DMA_TO_DEVICE); + if (dma_mapping_error(dev, *addr)) + goto unwind; + } + return 0; + +unwind: + while (fp-- > si->frags) + dma_unmap_page(dev, *--addr, fp->size, DMA_TO_DEVICE); + dma_unmap_single(dev, addr[-1], skb_headlen(skb), DMA_TO_DEVICE); + +out_err: + return -ENOMEM; +} + +static void unmap_sgl(struct device *dev, const struct sk_buff *skb, + const struct ulptx_sgl *sgl, const struct sge_txq *tq) +{ + const struct ulptx_sge_pair *p; + unsigned int nfrags = skb_shinfo(skb)->nr_frags; + + if (likely(skb_headlen(skb))) + dma_unmap_single(dev, be64_to_cpu(sgl->addr0), + be32_to_cpu(sgl->len0), DMA_TO_DEVICE); + else { + dma_unmap_page(dev, be64_to_cpu(sgl->addr0), + be32_to_cpu(sgl->len0), DMA_TO_DEVICE); + nfrags--; + } + + /* + * the complexity below is because of the possibility of a wrap-around + * in the middle of an SGL + */ + for (p = sgl->sge; nfrags >= 2; nfrags -= 2) { + if (likely((u8 *)(p + 1) <= (u8 *)tq->stat)) { +unmap: + dma_unmap_page(dev, be64_to_cpu(p->addr[0]), + be32_to_cpu(p->len[0]), DMA_TO_DEVICE); + dma_unmap_page(dev, be64_to_cpu(p->addr[1]), + be32_to_cpu(p->len[1]), DMA_TO_DEVICE); + p++; + } else if ((u8 *)p == (u8 *)tq->stat) { + p = (const struct ulptx_sge_pair *)tq->desc; + goto unmap; + } else if ((u8 *)p + 8 == (u8 *)tq->stat) { + const __be64 *addr = (const __be64 *)tq->desc; + + dma_unmap_page(dev, be64_to_cpu(addr[0]), + be32_to_cpu(p->len[0]), DMA_TO_DEVICE); + dma_unmap_page(dev, be64_to_cpu(addr[1]), + be32_to_cpu(p->len[1]), DMA_TO_DEVICE); + p = (const struct ulptx_sge_pair *)&addr[2]; + } else { + const __be64 *addr = (const __be64 *)tq->desc; + + dma_unmap_page(dev, be64_to_cpu(p->addr[0]), + be32_to_cpu(p->len[0]), DMA_TO_DEVICE); + dma_unmap_page(dev, be64_to_cpu(addr[0]), + be32_to_cpu(p->len[1]), DMA_TO_DEVICE); + p = (const struct ulptx_sge_pair *)&addr[1]; + } + } + if (nfrags) { + __be64 addr; + + if ((u8 *)p == (u8 *)tq->stat) + p = (const struct ulptx_sge_pair *)tq->desc; + addr = ((u8 *)p + 16 <= (u8 *)tq->stat + ? p->addr[0] + : *(const __be64 *)tq->desc); + dma_unmap_page(dev, be64_to_cpu(addr), be32_to_cpu(p->len[0]), + DMA_TO_DEVICE); + } +} + +/** + * free_tx_desc - reclaims TX descriptors and their buffers + * @adapter: the adapter + * @tq: the TX queue to reclaim descriptors from + * @n: the number of descriptors to reclaim + * @unmap: whether the buffers should be unmapped for DMA + * + * Reclaims TX descriptors from an SGE TX queue and frees the associated + * TX buffers. Called with the TX queue lock held. + */ +static void free_tx_desc(struct adapter *adapter, struct sge_txq *tq, + unsigned int n, bool unmap) +{ + struct tx_sw_desc *sdesc; + unsigned int cidx = tq->cidx; + struct device *dev = adapter->pdev_dev; + + const int need_unmap = need_skb_unmap() && unmap; + + sdesc = &tq->sdesc[cidx]; + while (n--) { + /* + * If we kept a reference to the original TX skb, we need to + * unmap it from PCI DMA space (if required) and free it. + */ + if (sdesc->skb) { + if (need_unmap) + unmap_sgl(dev, sdesc->skb, sdesc->sgl, tq); + kfree_skb(sdesc->skb); + sdesc->skb = NULL; + } + + sdesc++; + if (++cidx == tq->size) { + cidx = 0; + sdesc = tq->sdesc; + } + } + tq->cidx = cidx; +} + +/* + * Return the number of reclaimable descriptors in a TX queue. + */ +static inline int reclaimable(const struct sge_txq *tq) +{ + int hw_cidx = be16_to_cpu(tq->stat->cidx); + int reclaimable = hw_cidx - tq->cidx; + if (reclaimable < 0) + reclaimable += tq->size; + return reclaimable; +} + +/** + * reclaim_completed_tx - reclaims completed TX descriptors + * @adapter: the adapter + * @tq: the TX queue to reclaim completed descriptors from + * @unmap: whether the buffers should be unmapped for DMA + * + * Reclaims TX descriptors that the SGE has indicated it has processed, + * and frees the associated buffers if possible. Called with the TX + * queue locked. + */ +static inline void reclaim_completed_tx(struct adapter *adapter, + struct sge_txq *tq, + bool unmap) +{ + int avail = reclaimable(tq); + + if (avail) { + /* + * Limit the amount of clean up work we do at a time to keep + * the TX lock hold time O(1). + */ + if (avail > MAX_TX_RECLAIM) + avail = MAX_TX_RECLAIM; + + free_tx_desc(adapter, tq, avail, unmap); + tq->in_use -= avail; + } +} + +/** + * get_buf_size - return the size of an RX Free List buffer. + * @sdesc: pointer to the software buffer descriptor + */ +static inline int get_buf_size(const struct rx_sw_desc *sdesc) +{ + return FL_PG_ORDER > 0 && (sdesc->dma_addr & RX_LARGE_BUF) + ? (PAGE_SIZE << FL_PG_ORDER) + : PAGE_SIZE; +} + +/** + * free_rx_bufs - free RX buffers on an SGE Free List + * @adapter: the adapter + * @fl: the SGE Free List to free buffers from + * @n: how many buffers to free + * + * Release the next @n buffers on an SGE Free List RX queue. The + * buffers must be made inaccessible to hardware before calling this + * function. + */ +static void free_rx_bufs(struct adapter *adapter, struct sge_fl *fl, int n) +{ + while (n--) { + struct rx_sw_desc *sdesc = &fl->sdesc[fl->cidx]; + + if (is_buf_mapped(sdesc)) + dma_unmap_page(adapter->pdev_dev, get_buf_addr(sdesc), + get_buf_size(sdesc), PCI_DMA_FROMDEVICE); + put_page(sdesc->page); + sdesc->page = NULL; + if (++fl->cidx == fl->size) + fl->cidx = 0; + fl->avail--; + } +} + +/** + * unmap_rx_buf - unmap the current RX buffer on an SGE Free List + * @adapter: the adapter + * @fl: the SGE Free List + * + * Unmap the current buffer on an SGE Free List RX queue. The + * buffer must be made inaccessible to HW before calling this function. + * + * This is similar to @free_rx_bufs above but does not free the buffer. + * Do note that the FL still loses any further access to the buffer. + * This is used predominantly to "transfer ownership" of an FL buffer + * to another entity (typically an skb's fragment list). + */ +static void unmap_rx_buf(struct adapter *adapter, struct sge_fl *fl) +{ + struct rx_sw_desc *sdesc = &fl->sdesc[fl->cidx]; + + if (is_buf_mapped(sdesc)) + dma_unmap_page(adapter->pdev_dev, get_buf_addr(sdesc), + get_buf_size(sdesc), PCI_DMA_FROMDEVICE); + sdesc->page = NULL; + if (++fl->cidx == fl->size) + fl->cidx = 0; + fl->avail--; +} + +/** + * ring_fl_db - righ doorbell on free list + * @adapter: the adapter + * @fl: the Free List whose doorbell should be rung ... + * + * Tell the Scatter Gather Engine that there are new free list entries + * available. + */ +static inline void ring_fl_db(struct adapter *adapter, struct sge_fl *fl) +{ + /* + * The SGE keeps track of its Producer and Consumer Indices in terms + * of Egress Queue Units so we can only tell it about integral numbers + * of multiples of Free List Entries per Egress Queue Units ... + */ + if (fl->pend_cred >= FL_PER_EQ_UNIT) { + wmb(); + t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_KDOORBELL, + DBPRIO | + QID(fl->cntxt_id) | + PIDX(fl->pend_cred / FL_PER_EQ_UNIT)); + fl->pend_cred %= FL_PER_EQ_UNIT; + } +} + +/** + * set_rx_sw_desc - initialize software RX buffer descriptor + * @sdesc: pointer to the softwore RX buffer descriptor + * @page: pointer to the page data structure backing the RX buffer + * @dma_addr: PCI DMA address (possibly with low-bit flags) + */ +static inline void set_rx_sw_desc(struct rx_sw_desc *sdesc, struct page *page, + dma_addr_t dma_addr) +{ + sdesc->page = page; + sdesc->dma_addr = dma_addr; +} + +/* + * Support for poisoning RX buffers ... + */ +#define POISON_BUF_VAL -1 + +static inline void poison_buf(struct page *page, size_t sz) +{ +#if POISON_BUF_VAL >= 0 + memset(page_address(page), POISON_BUF_VAL, sz); +#endif +} + +/** + * refill_fl - refill an SGE RX buffer ring + * @adapter: the adapter + * @fl: the Free List ring to refill + * @n: the number of new buffers to allocate + * @gfp: the gfp flags for the allocations + * + * (Re)populate an SGE free-buffer queue with up to @n new packet buffers, + * allocated with the supplied gfp flags. The caller must assure that + * @n does not exceed the queue's capacity -- i.e. (cidx == pidx) _IN + * EGRESS QUEUE UNITS_ indicates an empty Free List! Returns the number + * of buffers allocated. If afterwards the queue is found critically low, + * mark it as starving in the bitmap of starving FLs. + */ +static unsigned int refill_fl(struct adapter *adapter, struct sge_fl *fl, + int n, gfp_t gfp) +{ + struct page *page; + dma_addr_t dma_addr; + unsigned int cred = fl->avail; + __be64 *d = &fl->desc[fl->pidx]; + struct rx_sw_desc *sdesc = &fl->sdesc[fl->pidx]; + + /* + * Sanity: ensure that the result of adding n Free List buffers + * won't result in wrapping the SGE's Producer Index around to + * it's Consumer Index thereby indicating an empty Free List ... + */ + BUG_ON(fl->avail + n > fl->size - FL_PER_EQ_UNIT); + + /* + * If we support large pages, prefer large buffers and fail over to + * small pages if we can't allocate large pages to satisfy the refill. + * If we don't support large pages, drop directly into the small page + * allocation code. + */ + if (FL_PG_ORDER == 0) + goto alloc_small_pages; + + while (n) { + page = alloc_pages(gfp | __GFP_COMP | __GFP_NOWARN, + FL_PG_ORDER); + if (unlikely(!page)) { + /* + * We've failed inour attempt to allocate a "large + * page". Fail over to the "small page" allocation + * below. + */ + fl->large_alloc_failed++; + break; + } + poison_buf(page, PAGE_SIZE << FL_PG_ORDER); + + dma_addr = dma_map_page(adapter->pdev_dev, page, 0, + PAGE_SIZE << FL_PG_ORDER, + PCI_DMA_FROMDEVICE); + if (unlikely(dma_mapping_error(adapter->pdev_dev, dma_addr))) { + /* + * We've run out of DMA mapping space. Free up the + * buffer and return with what we've managed to put + * into the free list. We don't want to fail over to + * the small page allocation below in this case + * because DMA mapping resources are typically + * critical resources once they become scarse. + */ + __free_pages(page, FL_PG_ORDER); + goto out; + } + dma_addr |= RX_LARGE_BUF; + *d++ = cpu_to_be64(dma_addr); + + set_rx_sw_desc(sdesc, page, dma_addr); + sdesc++; + + fl->avail++; + if (++fl->pidx == fl->size) { + fl->pidx = 0; + sdesc = fl->sdesc; + d = fl->desc; + } + n--; + } + +alloc_small_pages: + while (n--) { + page = __netdev_alloc_page(adapter->port[0], + gfp | __GFP_NOWARN); + if (unlikely(!page)) { + fl->alloc_failed++; + break; + } + poison_buf(page, PAGE_SIZE); + + dma_addr = dma_map_page(adapter->pdev_dev, page, 0, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + if (unlikely(dma_mapping_error(adapter->pdev_dev, dma_addr))) { + netdev_free_page(adapter->port[0], page); + break; + } + *d++ = cpu_to_be64(dma_addr); + + set_rx_sw_desc(sdesc, page, dma_addr); + sdesc++; + + fl->avail++; + if (++fl->pidx == fl->size) { + fl->pidx = 0; + sdesc = fl->sdesc; + d = fl->desc; + } + } + +out: + /* + * Update our accounting state to incorporate the new Free List + * buffers, tell the hardware about them and return the number of + * bufers which we were able to allocate. + */ + cred = fl->avail - cred; + fl->pend_cred += cred; + ring_fl_db(adapter, fl); + + if (unlikely(fl_starving(fl))) { + smp_wmb(); + set_bit(fl->cntxt_id, adapter->sge.starving_fl); + } + + return cred; +} + +/* + * Refill a Free List to its capacity or the Maximum Refill Increment, + * whichever is smaller ... + */ +static inline void __refill_fl(struct adapter *adapter, struct sge_fl *fl) +{ + refill_fl(adapter, fl, + min((unsigned int)MAX_RX_REFILL, fl_cap(fl) - fl->avail), + GFP_ATOMIC); +} + +/** + * alloc_ring - allocate resources for an SGE descriptor ring + * @dev: the PCI device's core device + * @nelem: the number of descriptors + * @hwsize: the size of each hardware descriptor + * @swsize: the size of each software descriptor + * @busaddrp: the physical PCI bus address of the allocated ring + * @swringp: return address pointer for software ring + * @stat_size: extra space in hardware ring for status information + * + * Allocates resources for an SGE descriptor ring, such as TX queues, + * free buffer lists, response queues, etc. Each SGE ring requires + * space for its hardware descriptors plus, optionally, space for software + * state associated with each hardware entry (the metadata). The function + * returns three values: the virtual address for the hardware ring (the + * return value of the function), the PCI bus address of the hardware + * ring (in *busaddrp), and the address of the software ring (in swringp). + * Both the hardware and software rings are returned zeroed out. + */ +static void *alloc_ring(struct device *dev, size_t nelem, size_t hwsize, + size_t swsize, dma_addr_t *busaddrp, void *swringp, + size_t stat_size) +{ + /* + * Allocate the hardware ring and PCI DMA bus address space for said. + */ + size_t hwlen = nelem * hwsize + stat_size; + void *hwring = dma_alloc_coherent(dev, hwlen, busaddrp, GFP_KERNEL); + + if (!hwring) + return NULL; + + /* + * If the caller wants a software ring, allocate it and return a + * pointer to it in *swringp. + */ + BUG_ON((swsize != 0) != (swringp != NULL)); + if (swsize) { + void *swring = kcalloc(nelem, swsize, GFP_KERNEL); + + if (!swring) { + dma_free_coherent(dev, hwlen, hwring, *busaddrp); + return NULL; + } + *(void **)swringp = swring; + } + + /* + * Zero out the hardware ring and return its address as our function + * value. + */ + memset(hwring, 0, hwlen); + return hwring; +} + +/** + * sgl_len - calculates the size of an SGL of the given capacity + * @n: the number of SGL entries + * + * Calculates the number of flits (8-byte units) needed for a Direct + * Scatter/Gather List that can hold the given number of entries. + */ +static inline unsigned int sgl_len(unsigned int n) +{ + /* + * A Direct Scatter Gather List uses 32-bit lengths and 64-bit PCI DMA + * addresses. The DSGL Work Request starts off with a 32-bit DSGL + * ULPTX header, then Length0, then Address0, then, for 1 <= i <= N, + * repeated sequences of { Length[i], Length[i+1], Address[i], + * Address[i+1] } (this ensures that all addresses are on 64-bit + * boundaries). If N is even, then Length[N+1] should be set to 0 and + * Address[N+1] is omitted. + * + * The following calculation incorporates all of the above. It's + * somewhat hard to follow but, briefly: the "+2" accounts for the + * first two flits which include the DSGL header, Length0 and + * Address0; the "(3*(n-1))/2" covers the main body of list entries (3 + * flits for every pair of the remaining N) +1 if (n-1) is odd; and + * finally the "+((n-1)&1)" adds the one remaining flit needed if + * (n-1) is odd ... + */ + n--; + return (3 * n) / 2 + (n & 1) + 2; +} + +/** + * flits_to_desc - returns the num of TX descriptors for the given flits + * @flits: the number of flits + * + * Returns the number of TX descriptors needed for the supplied number + * of flits. + */ +static inline unsigned int flits_to_desc(unsigned int flits) +{ + BUG_ON(flits > SGE_MAX_WR_LEN / sizeof(__be64)); + return DIV_ROUND_UP(flits, TXD_PER_EQ_UNIT); +} + +/** + * is_eth_imm - can an Ethernet packet be sent as immediate data? + * @skb: the packet + * + * Returns whether an Ethernet packet is small enough to fit completely as + * immediate data. + */ +static inline int is_eth_imm(const struct sk_buff *skb) +{ + /* + * The VF Driver uses the FW_ETH_TX_PKT_VM_WR firmware Work Request + * which does not accommodate immediate data. We could dike out all + * of the support code for immediate data but that would tie our hands + * too much if we ever want to enhace the firmware. It would also + * create more differences between the PF and VF Drivers. + */ + return false; +} + +/** + * calc_tx_flits - calculate the number of flits for a packet TX WR + * @skb: the packet + * + * Returns the number of flits needed for a TX Work Request for the + * given Ethernet packet, including the needed WR and CPL headers. + */ +static inline unsigned int calc_tx_flits(const struct sk_buff *skb) +{ + unsigned int flits; + + /* + * If the skb is small enough, we can pump it out as a work request + * with only immediate data. In that case we just have to have the + * TX Packet header plus the skb data in the Work Request. + */ + if (is_eth_imm(skb)) + return DIV_ROUND_UP(skb->len + sizeof(struct cpl_tx_pkt), + sizeof(__be64)); + + /* + * Otherwise, we're going to have to construct a Scatter gather list + * of the skb body and fragments. We also include the flits necessary + * for the TX Packet Work Request and CPL. We always have a firmware + * Write Header (incorporated as part of the cpl_tx_pkt_lso and + * cpl_tx_pkt structures), followed by either a TX Packet Write CPL + * message or, if we're doing a Large Send Offload, an LSO CPL message + * with an embeded TX Packet Write CPL message. + */ + flits = sgl_len(skb_shinfo(skb)->nr_frags + 1); + if (skb_shinfo(skb)->gso_size) + flits += (sizeof(struct fw_eth_tx_pkt_vm_wr) + + sizeof(struct cpl_tx_pkt_lso_core) + + sizeof(struct cpl_tx_pkt_core)) / sizeof(__be64); + else + flits += (sizeof(struct fw_eth_tx_pkt_vm_wr) + + sizeof(struct cpl_tx_pkt_core)) / sizeof(__be64); + return flits; +} + +/** + * write_sgl - populate a Scatter/Gather List for a packet + * @skb: the packet + * @tq: the TX queue we are writing into + * @sgl: starting location for writing the SGL + * @end: points right after the end of the SGL + * @start: start offset into skb main-body data to include in the SGL + * @addr: the list of DMA bus addresses for the SGL elements + * + * Generates a Scatter/Gather List for the buffers that make up a packet. + * The caller must provide adequate space for the SGL that will be written. + * The SGL includes all of the packet's page fragments and the data in its + * main body except for the first @start bytes. @pos must be 16-byte + * aligned and within a TX descriptor with available space. @end points + * write after the end of the SGL but does not account for any potential + * wrap around, i.e., @end > @tq->stat. + */ +static void write_sgl(const struct sk_buff *skb, struct sge_txq *tq, + struct ulptx_sgl *sgl, u64 *end, unsigned int start, + const dma_addr_t *addr) +{ + unsigned int i, len; + struct ulptx_sge_pair *to; + const struct skb_shared_info *si = skb_shinfo(skb); + unsigned int nfrags = si->nr_frags; + struct ulptx_sge_pair buf[MAX_SKB_FRAGS / 2 + 1]; + + len = skb_headlen(skb) - start; + if (likely(len)) { + sgl->len0 = htonl(len); + sgl->addr0 = cpu_to_be64(addr[0] + start); + nfrags++; + } else { + sgl->len0 = htonl(si->frags[0].size); + sgl->addr0 = cpu_to_be64(addr[1]); + } + + sgl->cmd_nsge = htonl(ULPTX_CMD(ULP_TX_SC_DSGL) | + ULPTX_NSGE(nfrags)); + if (likely(--nfrags == 0)) + return; + /* + * Most of the complexity below deals with the possibility we hit the + * end of the queue in the middle of writing the SGL. For this case + * only we create the SGL in a temporary buffer and then copy it. + */ + to = (u8 *)end > (u8 *)tq->stat ? buf : sgl->sge; + + for (i = (nfrags != si->nr_frags); nfrags >= 2; nfrags -= 2, to++) { + to->len[0] = cpu_to_be32(si->frags[i].size); + to->len[1] = cpu_to_be32(si->frags[++i].size); + to->addr[0] = cpu_to_be64(addr[i]); + to->addr[1] = cpu_to_be64(addr[++i]); + } + if (nfrags) { + to->len[0] = cpu_to_be32(si->frags[i].size); + to->len[1] = cpu_to_be32(0); + to->addr[0] = cpu_to_be64(addr[i + 1]); + } + if (unlikely((u8 *)end > (u8 *)tq->stat)) { + unsigned int part0 = (u8 *)tq->stat - (u8 *)sgl->sge, part1; + + if (likely(part0)) + memcpy(sgl->sge, buf, part0); + part1 = (u8 *)end - (u8 *)tq->stat; + memcpy(tq->desc, (u8 *)buf + part0, part1); + end = (void *)tq->desc + part1; + } + if ((uintptr_t)end & 8) /* 0-pad to multiple of 16 */ + *(u64 *)end = 0; +} + +/** + * check_ring_tx_db - check and potentially ring a TX queue's doorbell + * @adapter: the adapter + * @tq: the TX queue + * @n: number of new descriptors to give to HW + * + * Ring the doorbel for a TX queue. + */ +static inline void ring_tx_db(struct adapter *adapter, struct sge_txq *tq, + int n) +{ + /* + * Warn if we write doorbells with the wrong priority and write + * descriptors before telling HW. + */ + WARN_ON((QID(tq->cntxt_id) | PIDX(n)) & DBPRIO); + wmb(); + t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_KDOORBELL, + QID(tq->cntxt_id) | PIDX(n)); +} + +/** + * inline_tx_skb - inline a packet's data into TX descriptors + * @skb: the packet + * @tq: the TX queue where the packet will be inlined + * @pos: starting position in the TX queue to inline the packet + * + * Inline a packet's contents directly into TX descriptors, starting at + * the given position within the TX DMA ring. + * Most of the complexity of this operation is dealing with wrap arounds + * in the middle of the packet we want to inline. + */ +static void inline_tx_skb(const struct sk_buff *skb, const struct sge_txq *tq, + void *pos) +{ + u64 *p; + int left = (void *)tq->stat - pos; + + if (likely(skb->len <= left)) { + if (likely(!skb->data_len)) + skb_copy_from_linear_data(skb, pos, skb->len); + else + skb_copy_bits(skb, 0, pos, skb->len); + pos += skb->len; + } else { + skb_copy_bits(skb, 0, pos, left); + skb_copy_bits(skb, left, tq->desc, skb->len - left); + pos = (void *)tq->desc + (skb->len - left); + } + + /* 0-pad to multiple of 16 */ + p = PTR_ALIGN(pos, 8); + if ((uintptr_t)p & 8) + *p = 0; +} + +/* + * Figure out what HW csum a packet wants and return the appropriate control + * bits. + */ +static u64 hwcsum(const struct sk_buff *skb) +{ + int csum_type; + const struct iphdr *iph = ip_hdr(skb); + + if (iph->version == 4) { + if (iph->protocol == IPPROTO_TCP) + csum_type = TX_CSUM_TCPIP; + else if (iph->protocol == IPPROTO_UDP) + csum_type = TX_CSUM_UDPIP; + else { +nocsum: + /* + * unknown protocol, disable HW csum + * and hope a bad packet is detected + */ + return TXPKT_L4CSUM_DIS; + } + } else { + /* + * this doesn't work with extension headers + */ + const struct ipv6hdr *ip6h = (const struct ipv6hdr *)iph; + + if (ip6h->nexthdr == IPPROTO_TCP) + csum_type = TX_CSUM_TCPIP6; + else if (ip6h->nexthdr == IPPROTO_UDP) + csum_type = TX_CSUM_UDPIP6; + else + goto nocsum; + } + + if (likely(csum_type >= TX_CSUM_TCPIP)) + return TXPKT_CSUM_TYPE(csum_type) | + TXPKT_IPHDR_LEN(skb_network_header_len(skb)) | + TXPKT_ETHHDR_LEN(skb_network_offset(skb) - ETH_HLEN); + else { + int start = skb_transport_offset(skb); + + return TXPKT_CSUM_TYPE(csum_type) | + TXPKT_CSUM_START(start) | + TXPKT_CSUM_LOC(start + skb->csum_offset); + } +} + +/* + * Stop an Ethernet TX queue and record that state change. + */ +static void txq_stop(struct sge_eth_txq *txq) +{ + netif_tx_stop_queue(txq->txq); + txq->q.stops++; +} + +/* + * Advance our software state for a TX queue by adding n in use descriptors. + */ +static inline void txq_advance(struct sge_txq *tq, unsigned int n) +{ + tq->in_use += n; + tq->pidx += n; + if (tq->pidx >= tq->size) + tq->pidx -= tq->size; +} + +/** + * t4vf_eth_xmit - add a packet to an Ethernet TX queue + * @skb: the packet + * @dev: the egress net device + * + * Add a packet to an SGE Ethernet TX queue. Runs with softirqs disabled. + */ +int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev) +{ + u32 wr_mid; + u64 cntrl, *end; + int qidx, credits; + unsigned int flits, ndesc; + struct adapter *adapter; + struct sge_eth_txq *txq; + const struct port_info *pi; + struct fw_eth_tx_pkt_vm_wr *wr; + struct cpl_tx_pkt_core *cpl; + const struct skb_shared_info *ssi; + dma_addr_t addr[MAX_SKB_FRAGS + 1]; + const size_t fw_hdr_copy_len = (sizeof(wr->ethmacdst) + + sizeof(wr->ethmacsrc) + + sizeof(wr->ethtype) + + sizeof(wr->vlantci)); + + /* + * The chip minimum packet length is 10 octets but the firmware + * command that we are using requires that we copy the Ethernet header + * (including the VLAN tag) into the header so we reject anything + * smaller than that ... + */ + if (unlikely(skb->len < fw_hdr_copy_len)) + goto out_free; + + /* + * Figure out which TX Queue we're going to use. + */ + pi = netdev_priv(dev); + adapter = pi->adapter; + qidx = skb_get_queue_mapping(skb); + BUG_ON(qidx >= pi->nqsets); + txq = &adapter->sge.ethtxq[pi->first_qset + qidx]; + + /* + * Take this opportunity to reclaim any TX Descriptors whose DMA + * transfers have completed. + */ + reclaim_completed_tx(adapter, &txq->q, true); + + /* + * Calculate the number of flits and TX Descriptors we're going to + * need along with how many TX Descriptors will be left over after + * we inject our Work Request. + */ + flits = calc_tx_flits(skb); + ndesc = flits_to_desc(flits); + credits = txq_avail(&txq->q) - ndesc; + + if (unlikely(credits < 0)) { + /* + * Not enough room for this packet's Work Request. Stop the + * TX Queue and return a "busy" condition. The queue will get + * started later on when the firmware informs us that space + * has opened up. + */ + txq_stop(txq); + dev_err(adapter->pdev_dev, + "%s: TX ring %u full while queue awake!\n", + dev->name, qidx); + return NETDEV_TX_BUSY; + } + + if (!is_eth_imm(skb) && + unlikely(map_skb(adapter->pdev_dev, skb, addr) < 0)) { + /* + * We need to map the skb into PCI DMA space (because it can't + * be in-lined directly into the Work Request) and the mapping + * operation failed. Record the error and drop the packet. + */ + txq->mapping_err++; + goto out_free; + } + + wr_mid = FW_WR_LEN16(DIV_ROUND_UP(flits, 2)); + if (unlikely(credits < ETHTXQ_STOP_THRES)) { + /* + * After we're done injecting the Work Request for this + * packet, we'll be below our "stop threshold" so stop the TX + * Queue now and schedule a request for an SGE Egress Queue + * Update message. The queue will get started later on when + * the firmware processes this Work Request and sends us an + * Egress Queue Status Update message indicating that space + * has opened up. + */ + txq_stop(txq); + wr_mid |= FW_WR_EQUEQ | FW_WR_EQUIQ; + } + + /* + * Start filling in our Work Request. Note that we do _not_ handle + * the WR Header wrapping around the TX Descriptor Ring. If our + * maximum header size ever exceeds one TX Descriptor, we'll need to + * do something else here. + */ + BUG_ON(DIV_ROUND_UP(ETHTXQ_MAX_HDR, TXD_PER_EQ_UNIT) > 1); + wr = (void *)&txq->q.desc[txq->q.pidx]; + wr->equiq_to_len16 = cpu_to_be32(wr_mid); + wr->r3[0] = cpu_to_be64(0); + wr->r3[1] = cpu_to_be64(0); + skb_copy_from_linear_data(skb, (void *)wr->ethmacdst, fw_hdr_copy_len); + end = (u64 *)wr + flits; + + /* + * If this is a Large Send Offload packet we'll put in an LSO CPL + * message with an encapsulated TX Packet CPL message. Otherwise we + * just use a TX Packet CPL message. + */ + ssi = skb_shinfo(skb); + if (ssi->gso_size) { + struct cpl_tx_pkt_lso_core *lso = (void *)(wr + 1); + bool v6 = (ssi->gso_type & SKB_GSO_TCPV6) != 0; + int l3hdr_len = skb_network_header_len(skb); + int eth_xtra_len = skb_network_offset(skb) - ETH_HLEN; + + wr->op_immdlen = + cpu_to_be32(FW_WR_OP(FW_ETH_TX_PKT_VM_WR) | + FW_WR_IMMDLEN(sizeof(*lso) + + sizeof(*cpl))); + /* + * Fill in the LSO CPL message. + */ + lso->lso_ctrl = + cpu_to_be32(LSO_OPCODE(CPL_TX_PKT_LSO) | + LSO_FIRST_SLICE | + LSO_LAST_SLICE | + LSO_IPV6(v6) | + LSO_ETHHDR_LEN(eth_xtra_len/4) | + LSO_IPHDR_LEN(l3hdr_len/4) | + LSO_TCPHDR_LEN(tcp_hdr(skb)->doff)); + lso->ipid_ofst = cpu_to_be16(0); + lso->mss = cpu_to_be16(ssi->gso_size); + lso->seqno_offset = cpu_to_be32(0); + lso->len = cpu_to_be32(skb->len); + + /* + * Set up TX Packet CPL pointer, control word and perform + * accounting. + */ + cpl = (void *)(lso + 1); + cntrl = (TXPKT_CSUM_TYPE(v6 ? TX_CSUM_TCPIP6 : TX_CSUM_TCPIP) | + TXPKT_IPHDR_LEN(l3hdr_len) | + TXPKT_ETHHDR_LEN(eth_xtra_len)); + txq->tso++; + txq->tx_cso += ssi->gso_segs; + } else { + int len; + + len = is_eth_imm(skb) ? skb->len + sizeof(*cpl) : sizeof(*cpl); + wr->op_immdlen = + cpu_to_be32(FW_WR_OP(FW_ETH_TX_PKT_VM_WR) | + FW_WR_IMMDLEN(len)); + + /* + * Set up TX Packet CPL pointer, control word and perform + * accounting. + */ + cpl = (void *)(wr + 1); + if (skb->ip_summed == CHECKSUM_PARTIAL) { + cntrl = hwcsum(skb) | TXPKT_IPCSUM_DIS; + txq->tx_cso++; + } else + cntrl = TXPKT_L4CSUM_DIS | TXPKT_IPCSUM_DIS; + } + + /* + * If there's a VLAN tag present, add that to the list of things to + * do in this Work Request. + */ + if (vlan_tx_tag_present(skb)) { + txq->vlan_ins++; + cntrl |= TXPKT_VLAN_VLD | TXPKT_VLAN(vlan_tx_tag_get(skb)); + } + + /* + * Fill in the TX Packet CPL message header. + */ + cpl->ctrl0 = cpu_to_be32(TXPKT_OPCODE(CPL_TX_PKT_XT) | + TXPKT_INTF(pi->port_id) | + TXPKT_PF(0)); + cpl->pack = cpu_to_be16(0); + cpl->len = cpu_to_be16(skb->len); + cpl->ctrl1 = cpu_to_be64(cntrl); + +#ifdef T4_TRACE + T4_TRACE5(adapter->tb[txq->q.cntxt_id & 7], + "eth_xmit: ndesc %u, credits %u, pidx %u, len %u, frags %u", + ndesc, credits, txq->q.pidx, skb->len, ssi->nr_frags); +#endif + + /* + * Fill in the body of the TX Packet CPL message with either in-lined + * data or a Scatter/Gather List. + */ + if (is_eth_imm(skb)) { + /* + * In-line the packet's data and free the skb since we don't + * need it any longer. + */ + inline_tx_skb(skb, &txq->q, cpl + 1); + dev_kfree_skb(skb); + } else { + /* + * Write the skb's Scatter/Gather list into the TX Packet CPL + * message and retain a pointer to the skb so we can free it + * later when its DMA completes. (We store the skb pointer + * in the Software Descriptor corresponding to the last TX + * Descriptor used by the Work Request.) + * + * The retained skb will be freed when the corresponding TX + * Descriptors are reclaimed after their DMAs complete. + * However, this could take quite a while since, in general, + * the hardware is set up to be lazy about sending DMA + * completion notifications to us and we mostly perform TX + * reclaims in the transmit routine. + * + * This is good for performamce but means that we rely on new + * TX packets arriving to run the destructors of completed + * packets, which open up space in their sockets' send queues. + * Sometimes we do not get such new packets causing TX to + * stall. A single UDP transmitter is a good example of this + * situation. We have a clean up timer that periodically + * reclaims completed packets but it doesn't run often enough + * (nor do we want it to) to prevent lengthy stalls. A + * solution to this problem is to run the destructor early, + * after the packet is queued but before it's DMAd. A con is + * that we lie to socket memory accounting, but the amount of + * extra memory is reasonable (limited by the number of TX + * descriptors), the packets do actually get freed quickly by + * new packets almost always, and for protocols like TCP that + * wait for acks to really free up the data the extra memory + * is even less. On the positive side we run the destructors + * on the sending CPU rather than on a potentially different + * completing CPU, usually a good thing. + * + * Run the destructor before telling the DMA engine about the + * packet to make sure it doesn't complete and get freed + * prematurely. + */ + struct ulptx_sgl *sgl = (struct ulptx_sgl *)(cpl + 1); + struct sge_txq *tq = &txq->q; + int last_desc; + + /* + * If the Work Request header was an exact multiple of our TX + * Descriptor length, then it's possible that the starting SGL + * pointer lines up exactly with the end of our TX Descriptor + * ring. If that's the case, wrap around to the beginning + * here ... + */ + if (unlikely((void *)sgl == (void *)tq->stat)) { + sgl = (void *)tq->desc; + end = (void *)((void *)tq->desc + + ((void *)end - (void *)tq->stat)); + } + + write_sgl(skb, tq, sgl, end, 0, addr); + skb_orphan(skb); + + last_desc = tq->pidx + ndesc - 1; + if (last_desc >= tq->size) + last_desc -= tq->size; + tq->sdesc[last_desc].skb = skb; + tq->sdesc[last_desc].sgl = sgl; + } + + /* + * Advance our internal TX Queue state, tell the hardware about + * the new TX descriptors and return success. + */ + txq_advance(&txq->q, ndesc); + dev->trans_start = jiffies; + ring_tx_db(adapter, &txq->q, ndesc); + return NETDEV_TX_OK; + +out_free: + /* + * An error of some sort happened. Free the TX skb and tell the + * OS that we've "dealt" with the packet ... + */ + dev_kfree_skb(skb); + return NETDEV_TX_OK; +} + +/** + * t4vf_pktgl_to_skb - build an sk_buff from a packet gather list + * @gl: the gather list + * @skb_len: size of sk_buff main body if it carries fragments + * @pull_len: amount of data to move to the sk_buff's main body + * + * Builds an sk_buff from the given packet gather list. Returns the + * sk_buff or %NULL if sk_buff allocation failed. + */ +struct sk_buff *t4vf_pktgl_to_skb(const struct pkt_gl *gl, + unsigned int skb_len, unsigned int pull_len) +{ + struct sk_buff *skb; + struct skb_shared_info *ssi; + + /* + * If the ingress packet is small enough, allocate an skb large enough + * for all of the data and copy it inline. Otherwise, allocate an skb + * with enough room to pull in the header and reference the rest of + * the data via the skb fragment list. + * + * Below we rely on RX_COPY_THRES being less than the smallest Rx + * buff! size, which is expected since buffers are at least + * PAGE_SIZEd. In this case packets up to RX_COPY_THRES have only one + * fragment. + */ + if (gl->tot_len <= RX_COPY_THRES) { + /* small packets have only one fragment */ + skb = alloc_skb(gl->tot_len, GFP_ATOMIC); + if (unlikely(!skb)) + goto out; + __skb_put(skb, gl->tot_len); + skb_copy_to_linear_data(skb, gl->va, gl->tot_len); + } else { + skb = alloc_skb(skb_len, GFP_ATOMIC); + if (unlikely(!skb)) + goto out; + __skb_put(skb, pull_len); + skb_copy_to_linear_data(skb, gl->va, pull_len); + + ssi = skb_shinfo(skb); + ssi->frags[0].page = gl->frags[0].page; + ssi->frags[0].page_offset = gl->frags[0].page_offset + pull_len; + ssi->frags[0].size = gl->frags[0].size - pull_len; + if (gl->nfrags > 1) + memcpy(&ssi->frags[1], &gl->frags[1], + (gl->nfrags-1) * sizeof(skb_frag_t)); + ssi->nr_frags = gl->nfrags; + + skb->len = gl->tot_len; + skb->data_len = skb->len - pull_len; + skb->truesize += skb->data_len; + + /* Get a reference for the last page, we don't own it */ + get_page(gl->frags[gl->nfrags - 1].page); + } + +out: + return skb; +} + +/** + * t4vf_pktgl_free - free a packet gather list + * @gl: the gather list + * + * Releases the pages of a packet gather list. We do not own the last + * page on the list and do not free it. + */ +void t4vf_pktgl_free(const struct pkt_gl *gl) +{ + int frag; + + frag = gl->nfrags - 1; + while (frag--) + put_page(gl->frags[frag].page); +} + +/** + * copy_frags - copy fragments from gather list into skb_shared_info + * @si: destination skb shared info structure + * @gl: source internal packet gather list + * @offset: packet start offset in first page + * + * Copy an internal packet gather list into a Linux skb_shared_info + * structure. + */ +static inline void copy_frags(struct skb_shared_info *si, + const struct pkt_gl *gl, + unsigned int offset) +{ + unsigned int n; + + /* usually there's just one frag */ + si->frags[0].page = gl->frags[0].page; + si->frags[0].page_offset = gl->frags[0].page_offset + offset; + si->frags[0].size = gl->frags[0].size - offset; + si->nr_frags = gl->nfrags; + + n = gl->nfrags - 1; + if (n) + memcpy(&si->frags[1], &gl->frags[1], n * sizeof(skb_frag_t)); + + /* get a reference to the last page, we don't own it */ + get_page(gl->frags[n].page); +} + +/** + * do_gro - perform Generic Receive Offload ingress packet processing + * @rxq: ingress RX Ethernet Queue + * @gl: gather list for ingress packet + * @pkt: CPL header for last packet fragment + * + * Perform Generic Receive Offload (GRO) ingress packet processing. + * We use the standard Linux GRO interfaces for this. + */ +static void do_gro(struct sge_eth_rxq *rxq, const struct pkt_gl *gl, + const struct cpl_rx_pkt *pkt) +{ + int ret; + struct sk_buff *skb; + + skb = napi_get_frags(&rxq->rspq.napi); + if (unlikely(!skb)) { + t4vf_pktgl_free(gl); + rxq->stats.rx_drops++; + return; + } + + copy_frags(skb_shinfo(skb), gl, PKTSHIFT); + skb->len = gl->tot_len - PKTSHIFT; + skb->data_len = skb->len; + skb->truesize += skb->data_len; + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb_record_rx_queue(skb, rxq->rspq.idx); + + if (pkt->vlan_ex) + __vlan_hwaccel_put_tag(skb, be16_to_cpu(pkt->vlan)); + ret = napi_gro_frags(&rxq->rspq.napi); + + if (ret == GRO_HELD) + rxq->stats.lro_pkts++; + else if (ret == GRO_MERGED || ret == GRO_MERGED_FREE) + rxq->stats.lro_merged++; + rxq->stats.pkts++; + rxq->stats.rx_cso++; +} + +/** + * t4vf_ethrx_handler - process an ingress ethernet packet + * @rspq: the response queue that received the packet + * @rsp: the response queue descriptor holding the RX_PKT message + * @gl: the gather list of packet fragments + * + * Process an ingress ethernet packet and deliver it to the stack. + */ +int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp, + const struct pkt_gl *gl) +{ + struct sk_buff *skb; + const struct cpl_rx_pkt *pkt = (void *)&rsp[1]; + bool csum_ok = pkt->csum_calc && !pkt->err_vec; + struct sge_eth_rxq *rxq = container_of(rspq, struct sge_eth_rxq, rspq); + + /* + * If this is a good TCP packet and we have Generic Receive Offload + * enabled, handle the packet in the GRO path. + */ + if ((pkt->l2info & cpu_to_be32(RXF_TCP)) && + (rspq->netdev->features & NETIF_F_GRO) && csum_ok && + !pkt->ip_frag) { + do_gro(rxq, gl, pkt); + return 0; + } + + /* + * Convert the Packet Gather List into an skb. + */ + skb = t4vf_pktgl_to_skb(gl, RX_SKB_LEN, RX_PULL_LEN); + if (unlikely(!skb)) { + t4vf_pktgl_free(gl); + rxq->stats.rx_drops++; + return 0; + } + __skb_pull(skb, PKTSHIFT); + skb->protocol = eth_type_trans(skb, rspq->netdev); + skb_record_rx_queue(skb, rspq->idx); + rxq->stats.pkts++; + + if (csum_ok && (rspq->netdev->features & NETIF_F_RXCSUM) && + !pkt->err_vec && (be32_to_cpu(pkt->l2info) & (RXF_UDP|RXF_TCP))) { + if (!pkt->ip_frag) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else { + __sum16 c = (__force __sum16)pkt->csum; + skb->csum = csum_unfold(c); + skb->ip_summed = CHECKSUM_COMPLETE; + } + rxq->stats.rx_cso++; + } else + skb_checksum_none_assert(skb); + + if (pkt->vlan_ex) { + rxq->stats.vlan_ex++; + __vlan_hwaccel_put_tag(skb, be16_to_cpu(pkt->vlan)); + } + + netif_receive_skb(skb); + + return 0; +} + +/** + * is_new_response - check if a response is newly written + * @rc: the response control descriptor + * @rspq: the response queue + * + * Returns true if a response descriptor contains a yet unprocessed + * response. + */ +static inline bool is_new_response(const struct rsp_ctrl *rc, + const struct sge_rspq *rspq) +{ + return RSPD_GEN(rc->type_gen) == rspq->gen; +} + +/** + * restore_rx_bufs - put back a packet's RX buffers + * @gl: the packet gather list + * @fl: the SGE Free List + * @nfrags: how many fragments in @si + * + * Called when we find out that the current packet, @si, can't be + * processed right away for some reason. This is a very rare event and + * there's no effort to make this suspension/resumption process + * particularly efficient. + * + * We implement the suspension by putting all of the RX buffers associated + * with the current packet back on the original Free List. The buffers + * have already been unmapped and are left unmapped, we mark them as + * unmapped in order to prevent further unmapping attempts. (Effectively + * this function undoes the series of @unmap_rx_buf calls which were done + * to create the current packet's gather list.) This leaves us ready to + * restart processing of the packet the next time we start processing the + * RX Queue ... + */ +static void restore_rx_bufs(const struct pkt_gl *gl, struct sge_fl *fl, + int frags) +{ + struct rx_sw_desc *sdesc; + + while (frags--) { + if (fl->cidx == 0) + fl->cidx = fl->size - 1; + else + fl->cidx--; + sdesc = &fl->sdesc[fl->cidx]; + sdesc->page = gl->frags[frags].page; + sdesc->dma_addr |= RX_UNMAPPED_BUF; + fl->avail++; + } +} + +/** + * rspq_next - advance to the next entry in a response queue + * @rspq: the queue + * + * Updates the state of a response queue to advance it to the next entry. + */ +static inline void rspq_next(struct sge_rspq *rspq) +{ + rspq->cur_desc = (void *)rspq->cur_desc + rspq->iqe_len; + if (unlikely(++rspq->cidx == rspq->size)) { + rspq->cidx = 0; + rspq->gen ^= 1; + rspq->cur_desc = rspq->desc; + } +} + +/** + * process_responses - process responses from an SGE response queue + * @rspq: the ingress response queue to process + * @budget: how many responses can be processed in this round + * + * Process responses from a Scatter Gather Engine response queue up to + * the supplied budget. Responses include received packets as well as + * control messages from firmware or hardware. + * + * Additionally choose the interrupt holdoff time for the next interrupt + * on this queue. If the system is under memory shortage use a fairly + * long delay to help recovery. + */ +int process_responses(struct sge_rspq *rspq, int budget) +{ + struct sge_eth_rxq *rxq = container_of(rspq, struct sge_eth_rxq, rspq); + int budget_left = budget; + + while (likely(budget_left)) { + int ret, rsp_type; + const struct rsp_ctrl *rc; + + rc = (void *)rspq->cur_desc + (rspq->iqe_len - sizeof(*rc)); + if (!is_new_response(rc, rspq)) + break; + + /* + * Figure out what kind of response we've received from the + * SGE. + */ + rmb(); + rsp_type = RSPD_TYPE(rc->type_gen); + if (likely(rsp_type == RSP_TYPE_FLBUF)) { + skb_frag_t *fp; + struct pkt_gl gl; + const struct rx_sw_desc *sdesc; + u32 bufsz, frag; + u32 len = be32_to_cpu(rc->pldbuflen_qid); + + /* + * If we get a "new buffer" message from the SGE we + * need to move on to the next Free List buffer. + */ + if (len & RSPD_NEWBUF) { + /* + * We get one "new buffer" message when we + * first start up a queue so we need to ignore + * it when our offset into the buffer is 0. + */ + if (likely(rspq->offset > 0)) { + free_rx_bufs(rspq->adapter, &rxq->fl, + 1); + rspq->offset = 0; + } + len = RSPD_LEN(len); + } + gl.tot_len = len; + + /* + * Gather packet fragments. + */ + for (frag = 0, fp = gl.frags; /**/; frag++, fp++) { + BUG_ON(frag >= MAX_SKB_FRAGS); + BUG_ON(rxq->fl.avail == 0); + sdesc = &rxq->fl.sdesc[rxq->fl.cidx]; + bufsz = get_buf_size(sdesc); + fp->page = sdesc->page; + fp->page_offset = rspq->offset; + fp->size = min(bufsz, len); + len -= fp->size; + if (!len) + break; + unmap_rx_buf(rspq->adapter, &rxq->fl); + } + gl.nfrags = frag+1; + + /* + * Last buffer remains mapped so explicitly make it + * coherent for CPU access and start preloading first + * cache line ... + */ + dma_sync_single_for_cpu(rspq->adapter->pdev_dev, + get_buf_addr(sdesc), + fp->size, DMA_FROM_DEVICE); + gl.va = (page_address(gl.frags[0].page) + + gl.frags[0].page_offset); + prefetch(gl.va); + + /* + * Hand the new ingress packet to the handler for + * this Response Queue. + */ + ret = rspq->handler(rspq, rspq->cur_desc, &gl); + if (likely(ret == 0)) + rspq->offset += ALIGN(fp->size, FL_ALIGN); + else + restore_rx_bufs(&gl, &rxq->fl, frag); + } else if (likely(rsp_type == RSP_TYPE_CPL)) { + ret = rspq->handler(rspq, rspq->cur_desc, NULL); + } else { + WARN_ON(rsp_type > RSP_TYPE_CPL); + ret = 0; + } + + if (unlikely(ret)) { + /* + * Couldn't process descriptor, back off for recovery. + * We use the SGE's last timer which has the longest + * interrupt coalescing value ... + */ + const int NOMEM_TIMER_IDX = SGE_NTIMERS-1; + rspq->next_intr_params = + QINTR_TIMER_IDX(NOMEM_TIMER_IDX); + break; + } + + rspq_next(rspq); + budget_left--; + } + + /* + * If this is a Response Queue with an associated Free List and + * at least two Egress Queue units available in the Free List + * for new buffer pointers, refill the Free List. + */ + if (rspq->offset >= 0 && + rxq->fl.size - rxq->fl.avail >= 2*FL_PER_EQ_UNIT) + __refill_fl(rspq->adapter, &rxq->fl); + return budget - budget_left; +} + +/** + * napi_rx_handler - the NAPI handler for RX processing + * @napi: the napi instance + * @budget: how many packets we can process in this round + * + * Handler for new data events when using NAPI. This does not need any + * locking or protection from interrupts as data interrupts are off at + * this point and other adapter interrupts do not interfere (the latter + * in not a concern at all with MSI-X as non-data interrupts then have + * a separate handler). + */ +static int napi_rx_handler(struct napi_struct *napi, int budget) +{ + unsigned int intr_params; + struct sge_rspq *rspq = container_of(napi, struct sge_rspq, napi); + int work_done = process_responses(rspq, budget); + + if (likely(work_done < budget)) { + napi_complete(napi); + intr_params = rspq->next_intr_params; + rspq->next_intr_params = rspq->intr_params; + } else + intr_params = QINTR_TIMER_IDX(SGE_TIMER_UPD_CIDX); + + if (unlikely(work_done == 0)) + rspq->unhandled_irqs++; + + t4_write_reg(rspq->adapter, + T4VF_SGE_BASE_ADDR + SGE_VF_GTS, + CIDXINC(work_done) | + INGRESSQID((u32)rspq->cntxt_id) | + SEINTARM(intr_params)); + return work_done; +} + +/* + * The MSI-X interrupt handler for an SGE response queue for the NAPI case + * (i.e., response queue serviced by NAPI polling). + */ +irqreturn_t t4vf_sge_intr_msix(int irq, void *cookie) +{ + struct sge_rspq *rspq = cookie; + + napi_schedule(&rspq->napi); + return IRQ_HANDLED; +} + +/* + * Process the indirect interrupt entries in the interrupt queue and kick off + * NAPI for each queue that has generated an entry. + */ +static unsigned int process_intrq(struct adapter *adapter) +{ + struct sge *s = &adapter->sge; + struct sge_rspq *intrq = &s->intrq; + unsigned int work_done; + + spin_lock(&adapter->sge.intrq_lock); + for (work_done = 0; ; work_done++) { + const struct rsp_ctrl *rc; + unsigned int qid, iq_idx; + struct sge_rspq *rspq; + + /* + * Grab the next response from the interrupt queue and bail + * out if it's not a new response. + */ + rc = (void *)intrq->cur_desc + (intrq->iqe_len - sizeof(*rc)); + if (!is_new_response(rc, intrq)) + break; + + /* + * If the response isn't a forwarded interrupt message issue a + * error and go on to the next response message. This should + * never happen ... + */ + rmb(); + if (unlikely(RSPD_TYPE(rc->type_gen) != RSP_TYPE_INTR)) { + dev_err(adapter->pdev_dev, + "Unexpected INTRQ response type %d\n", + RSPD_TYPE(rc->type_gen)); + continue; + } + + /* + * Extract the Queue ID from the interrupt message and perform + * sanity checking to make sure it really refers to one of our + * Ingress Queues which is active and matches the queue's ID. + * None of these error conditions should ever happen so we may + * want to either make them fatal and/or conditionalized under + * DEBUG. + */ + qid = RSPD_QID(be32_to_cpu(rc->pldbuflen_qid)); + iq_idx = IQ_IDX(s, qid); + if (unlikely(iq_idx >= MAX_INGQ)) { + dev_err(adapter->pdev_dev, + "Ingress QID %d out of range\n", qid); + continue; + } + rspq = s->ingr_map[iq_idx]; + if (unlikely(rspq == NULL)) { + dev_err(adapter->pdev_dev, + "Ingress QID %d RSPQ=NULL\n", qid); + continue; + } + if (unlikely(rspq->abs_id != qid)) { + dev_err(adapter->pdev_dev, + "Ingress QID %d refers to RSPQ %d\n", + qid, rspq->abs_id); + continue; + } + + /* + * Schedule NAPI processing on the indicated Response Queue + * and move on to the next entry in the Forwarded Interrupt + * Queue. + */ + napi_schedule(&rspq->napi); + rspq_next(intrq); + } + + t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS, + CIDXINC(work_done) | + INGRESSQID(intrq->cntxt_id) | + SEINTARM(intrq->intr_params)); + + spin_unlock(&adapter->sge.intrq_lock); + + return work_done; +} + +/* + * The MSI interrupt handler handles data events from SGE response queues as + * well as error and other async events as they all use the same MSI vector. + */ +irqreturn_t t4vf_intr_msi(int irq, void *cookie) +{ + struct adapter *adapter = cookie; + + process_intrq(adapter); + return IRQ_HANDLED; +} + +/** + * t4vf_intr_handler - select the top-level interrupt handler + * @adapter: the adapter + * + * Selects the top-level interrupt handler based on the type of interrupts + * (MSI-X or MSI). + */ +irq_handler_t t4vf_intr_handler(struct adapter *adapter) +{ + BUG_ON((adapter->flags & (USING_MSIX|USING_MSI)) == 0); + if (adapter->flags & USING_MSIX) + return t4vf_sge_intr_msix; + else + return t4vf_intr_msi; +} + +/** + * sge_rx_timer_cb - perform periodic maintenance of SGE RX queues + * @data: the adapter + * + * Runs periodically from a timer to perform maintenance of SGE RX queues. + * + * a) 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 schedule NAPI to do + * the actual refill. + */ +static void sge_rx_timer_cb(unsigned long data) +{ + struct adapter *adapter = (struct adapter *)data; + struct sge *s = &adapter->sge; + unsigned int i; + + /* + * Scan the "Starving Free Lists" flag array looking for any Free + * Lists in need of more free buffers. If we find one and it's not + * being actively polled, then bump its "starving" counter and attempt + * to refill it. If we're successful in adding enough buffers to push + * the Free List over the starving threshold, then we can clear its + * "starving" status. + */ + for (i = 0; i < ARRAY_SIZE(s->starving_fl); i++) { + unsigned long m; + + for (m = s->starving_fl[i]; m; m &= m - 1) { + unsigned int id = __ffs(m) + i * BITS_PER_LONG; + struct sge_fl *fl = s->egr_map[id]; + + clear_bit(id, s->starving_fl); + smp_mb__after_clear_bit(); + + /* + * Since we are accessing fl without a lock there's a + * small probability of a false positive where we + * schedule napi but the FL is no longer starving. + * No biggie. + */ + if (fl_starving(fl)) { + struct sge_eth_rxq *rxq; + + rxq = container_of(fl, struct sge_eth_rxq, fl); + if (napi_reschedule(&rxq->rspq.napi)) + fl->starving++; + else + set_bit(id, s->starving_fl); + } + } + } + + /* + * Reschedule the next scan for starving Free Lists ... + */ + mod_timer(&s->rx_timer, jiffies + RX_QCHECK_PERIOD); +} + +/** + * sge_tx_timer_cb - perform periodic maintenance of SGE Tx queues + * @data: the adapter + * + * Runs periodically from a timer to perform maintenance of SGE TX queues. + * + * b) Reclaims completed Tx packets for the Ethernet queues. Normally + * packets are cleaned up by new Tx packets, this timer cleans up packets + * when no new packets are being submitted. This is essential for pktgen, + * at least. + */ +static void sge_tx_timer_cb(unsigned long data) +{ + struct adapter *adapter = (struct adapter *)data; + struct sge *s = &adapter->sge; + unsigned int i, budget; + + budget = MAX_TIMER_TX_RECLAIM; + i = s->ethtxq_rover; + do { + struct sge_eth_txq *txq = &s->ethtxq[i]; + + if (reclaimable(&txq->q) && __netif_tx_trylock(txq->txq)) { + int avail = reclaimable(&txq->q); + + if (avail > budget) + avail = budget; + + free_tx_desc(adapter, &txq->q, avail, true); + txq->q.in_use -= avail; + __netif_tx_unlock(txq->txq); + + budget -= avail; + if (!budget) + break; + } + + i++; + if (i >= s->ethqsets) + i = 0; + } while (i != s->ethtxq_rover); + s->ethtxq_rover = i; + + /* + * If we found too many reclaimable packets schedule a timer in the + * near future to continue where we left off. Otherwise the next timer + * will be at its normal interval. + */ + mod_timer(&s->tx_timer, jiffies + (budget ? TX_QCHECK_PERIOD : 2)); +} + +/** + * t4vf_sge_alloc_rxq - allocate an SGE RX Queue + * @adapter: the adapter + * @rspq: pointer to to the new rxq's Response Queue to be filled in + * @iqasynch: if 0, a normal rspq; if 1, an asynchronous event queue + * @dev: the network device associated with the new rspq + * @intr_dest: MSI-X vector index (overriden in MSI mode) + * @fl: pointer to the new rxq's Free List to be filled in + * @hnd: the interrupt handler to invoke for the rspq + */ +int t4vf_sge_alloc_rxq(struct adapter *adapter, struct sge_rspq *rspq, + bool iqasynch, struct net_device *dev, + int intr_dest, + struct sge_fl *fl, rspq_handler_t hnd) +{ + struct port_info *pi = netdev_priv(dev); + struct fw_iq_cmd cmd, rpl; + int ret, iqandst, flsz = 0; + + /* + * If we're using MSI interrupts and we're not initializing the + * Forwarded Interrupt Queue itself, then set up this queue for + * indirect interrupts to the Forwarded Interrupt Queue. Obviously + * the Forwarded Interrupt Queue must be set up before any other + * ingress queue ... + */ + if ((adapter->flags & USING_MSI) && rspq != &adapter->sge.intrq) { + iqandst = SGE_INTRDST_IQ; + intr_dest = adapter->sge.intrq.abs_id; + } else + iqandst = SGE_INTRDST_PCI; + + /* + * Allocate the hardware ring for the Response Queue. The size needs + * to be a multiple of 16 which includes the mandatory status entry + * (regardless of whether the Status Page capabilities are enabled or + * not). + */ + rspq->size = roundup(rspq->size, 16); + rspq->desc = alloc_ring(adapter->pdev_dev, rspq->size, rspq->iqe_len, + 0, &rspq->phys_addr, NULL, 0); + if (!rspq->desc) + return -ENOMEM; + + /* + * Fill in the Ingress Queue Command. Note: Ideally this code would + * be in t4vf_hw.c but there are so many parameters and dependencies + * on our Linux SGE state that we would end up having to pass tons of + * parameters. We'll have to think about how this might be migrated + * into OS-independent common code ... + */ + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_IQ_CMD) | + FW_CMD_REQUEST | + FW_CMD_WRITE | + FW_CMD_EXEC); + cmd.alloc_to_len16 = cpu_to_be32(FW_IQ_CMD_ALLOC | + FW_IQ_CMD_IQSTART(1) | + FW_LEN16(cmd)); + cmd.type_to_iqandstindex = + cpu_to_be32(FW_IQ_CMD_TYPE(FW_IQ_TYPE_FL_INT_CAP) | + FW_IQ_CMD_IQASYNCH(iqasynch) | + FW_IQ_CMD_VIID(pi->viid) | + FW_IQ_CMD_IQANDST(iqandst) | + FW_IQ_CMD_IQANUS(1) | + FW_IQ_CMD_IQANUD(SGE_UPDATEDEL_INTR) | + FW_IQ_CMD_IQANDSTINDEX(intr_dest)); + cmd.iqdroprss_to_iqesize = + cpu_to_be16(FW_IQ_CMD_IQPCIECH(pi->port_id) | + FW_IQ_CMD_IQGTSMODE | + FW_IQ_CMD_IQINTCNTTHRESH(rspq->pktcnt_idx) | + FW_IQ_CMD_IQESIZE(ilog2(rspq->iqe_len) - 4)); + cmd.iqsize = cpu_to_be16(rspq->size); + cmd.iqaddr = cpu_to_be64(rspq->phys_addr); + + if (fl) { + /* + * Allocate the ring for the hardware free list (with space + * for its status page) along with the associated software + * descriptor ring. The free list size needs to be a multiple + * of the Egress Queue Unit. + */ + fl->size = roundup(fl->size, FL_PER_EQ_UNIT); + fl->desc = alloc_ring(adapter->pdev_dev, fl->size, + sizeof(__be64), sizeof(struct rx_sw_desc), + &fl->addr, &fl->sdesc, STAT_LEN); + if (!fl->desc) { + ret = -ENOMEM; + goto err; + } + + /* + * Calculate the size of the hardware free list ring plus + * Status Page (which the SGE will place after the end of the + * free list ring) in Egress Queue Units. + */ + flsz = (fl->size / FL_PER_EQ_UNIT + + STAT_LEN / EQ_UNIT); + + /* + * Fill in all the relevant firmware Ingress Queue Command + * fields for the free list. + */ + cmd.iqns_to_fl0congen = + cpu_to_be32( + FW_IQ_CMD_FL0HOSTFCMODE(SGE_HOSTFCMODE_NONE) | + FW_IQ_CMD_FL0PACKEN | + FW_IQ_CMD_FL0PADEN); + cmd.fl0dcaen_to_fl0cidxfthresh = + cpu_to_be16( + FW_IQ_CMD_FL0FBMIN(SGE_FETCHBURSTMIN_64B) | + FW_IQ_CMD_FL0FBMAX(SGE_FETCHBURSTMAX_512B)); + cmd.fl0size = cpu_to_be16(flsz); + cmd.fl0addr = cpu_to_be64(fl->addr); + } + + /* + * Issue the firmware Ingress Queue Command and extract the results if + * it completes successfully. + */ + ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); + if (ret) + goto err; + + netif_napi_add(dev, &rspq->napi, napi_rx_handler, 64); + rspq->cur_desc = rspq->desc; + rspq->cidx = 0; + rspq->gen = 1; + rspq->next_intr_params = rspq->intr_params; + rspq->cntxt_id = be16_to_cpu(rpl.iqid); + rspq->abs_id = be16_to_cpu(rpl.physiqid); + rspq->size--; /* subtract status entry */ + rspq->adapter = adapter; + rspq->netdev = dev; + rspq->handler = hnd; + + /* set offset to -1 to distinguish ingress queues without FL */ + rspq->offset = fl ? 0 : -1; + + if (fl) { + fl->cntxt_id = be16_to_cpu(rpl.fl0id); + fl->avail = 0; + fl->pend_cred = 0; + fl->pidx = 0; + fl->cidx = 0; + fl->alloc_failed = 0; + fl->large_alloc_failed = 0; + fl->starving = 0; + refill_fl(adapter, fl, fl_cap(fl), GFP_KERNEL); + } + + return 0; + +err: + /* + * An error occurred. Clean up our partial allocation state and + * return the error. + */ + if (rspq->desc) { + dma_free_coherent(adapter->pdev_dev, rspq->size * rspq->iqe_len, + rspq->desc, rspq->phys_addr); + rspq->desc = NULL; + } + if (fl && fl->desc) { + kfree(fl->sdesc); + fl->sdesc = NULL; + dma_free_coherent(adapter->pdev_dev, flsz * EQ_UNIT, + fl->desc, fl->addr); + fl->desc = NULL; + } + return ret; +} + +/** + * t4vf_sge_alloc_eth_txq - allocate an SGE Ethernet TX Queue + * @adapter: the adapter + * @txq: pointer to the new txq to be filled in + * @devq: the network TX queue associated with the new txq + * @iqid: the relative ingress queue ID to which events relating to + * the new txq should be directed + */ +int t4vf_sge_alloc_eth_txq(struct adapter *adapter, struct sge_eth_txq *txq, + struct net_device *dev, struct netdev_queue *devq, + unsigned int iqid) +{ + int ret, nentries; + struct fw_eq_eth_cmd cmd, rpl; + struct port_info *pi = netdev_priv(dev); + + /* + * Calculate the size of the hardware TX Queue (including the Status + * Page on the end of the TX Queue) in units of TX Descriptors. + */ + nentries = txq->q.size + STAT_LEN / sizeof(struct tx_desc); + + /* + * Allocate the hardware ring for the TX ring (with space for its + * status page) along with the associated software descriptor ring. + */ + txq->q.desc = alloc_ring(adapter->pdev_dev, txq->q.size, + sizeof(struct tx_desc), + sizeof(struct tx_sw_desc), + &txq->q.phys_addr, &txq->q.sdesc, STAT_LEN); + if (!txq->q.desc) + return -ENOMEM; + + /* + * Fill in the Egress Queue Command. Note: As with the direct use of + * the firmware Ingress Queue COmmand above in our RXQ allocation + * routine, ideally, this code would be in t4vf_hw.c. Again, we'll + * have to see if there's some reasonable way to parameterize it + * into the common code ... + */ + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_EQ_ETH_CMD) | + FW_CMD_REQUEST | + FW_CMD_WRITE | + FW_CMD_EXEC); + cmd.alloc_to_len16 = cpu_to_be32(FW_EQ_ETH_CMD_ALLOC | + FW_EQ_ETH_CMD_EQSTART | + FW_LEN16(cmd)); + cmd.viid_pkd = cpu_to_be32(FW_EQ_ETH_CMD_VIID(pi->viid)); + cmd.fetchszm_to_iqid = + cpu_to_be32(FW_EQ_ETH_CMD_HOSTFCMODE(SGE_HOSTFCMODE_STPG) | + FW_EQ_ETH_CMD_PCIECHN(pi->port_id) | + FW_EQ_ETH_CMD_IQID(iqid)); + cmd.dcaen_to_eqsize = + cpu_to_be32(FW_EQ_ETH_CMD_FBMIN(SGE_FETCHBURSTMIN_64B) | + FW_EQ_ETH_CMD_FBMAX(SGE_FETCHBURSTMAX_512B) | + FW_EQ_ETH_CMD_CIDXFTHRESH(SGE_CIDXFLUSHTHRESH_32) | + FW_EQ_ETH_CMD_EQSIZE(nentries)); + cmd.eqaddr = cpu_to_be64(txq->q.phys_addr); + + /* + * Issue the firmware Egress Queue Command and extract the results if + * it completes successfully. + */ + ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); + if (ret) { + /* + * The girmware Ingress Queue Command failed for some reason. + * Free up our partial allocation state and return the error. + */ + kfree(txq->q.sdesc); + txq->q.sdesc = NULL; + dma_free_coherent(adapter->pdev_dev, + nentries * sizeof(struct tx_desc), + txq->q.desc, txq->q.phys_addr); + txq->q.desc = NULL; + return ret; + } + + txq->q.in_use = 0; + txq->q.cidx = 0; + txq->q.pidx = 0; + txq->q.stat = (void *)&txq->q.desc[txq->q.size]; + txq->q.cntxt_id = FW_EQ_ETH_CMD_EQID_GET(be32_to_cpu(rpl.eqid_pkd)); + txq->q.abs_id = + FW_EQ_ETH_CMD_PHYSEQID_GET(be32_to_cpu(rpl.physeqid_pkd)); + txq->txq = devq; + txq->tso = 0; + txq->tx_cso = 0; + txq->vlan_ins = 0; + txq->q.stops = 0; + txq->q.restarts = 0; + txq->mapping_err = 0; + return 0; +} + +/* + * Free the DMA map resources associated with a TX queue. + */ +static void free_txq(struct adapter *adapter, struct sge_txq *tq) +{ + dma_free_coherent(adapter->pdev_dev, + tq->size * sizeof(*tq->desc) + STAT_LEN, + tq->desc, tq->phys_addr); + tq->cntxt_id = 0; + tq->sdesc = NULL; + tq->desc = NULL; +} + +/* + * Free the resources associated with a response queue (possibly including a + * free list). + */ +static void free_rspq_fl(struct adapter *adapter, struct sge_rspq *rspq, + struct sge_fl *fl) +{ + unsigned int flid = fl ? fl->cntxt_id : 0xffff; + + t4vf_iq_free(adapter, FW_IQ_TYPE_FL_INT_CAP, + rspq->cntxt_id, flid, 0xffff); + dma_free_coherent(adapter->pdev_dev, (rspq->size + 1) * rspq->iqe_len, + rspq->desc, rspq->phys_addr); + netif_napi_del(&rspq->napi); + rspq->netdev = NULL; + rspq->cntxt_id = 0; + rspq->abs_id = 0; + rspq->desc = NULL; + + if (fl) { + free_rx_bufs(adapter, fl, fl->avail); + dma_free_coherent(adapter->pdev_dev, + fl->size * sizeof(*fl->desc) + STAT_LEN, + fl->desc, fl->addr); + kfree(fl->sdesc); + fl->sdesc = NULL; + fl->cntxt_id = 0; + fl->desc = NULL; + } +} + +/** + * t4vf_free_sge_resources - free SGE resources + * @adapter: the adapter + * + * Frees resources used by the SGE queue sets. + */ +void t4vf_free_sge_resources(struct adapter *adapter) +{ + struct sge *s = &adapter->sge; + struct sge_eth_rxq *rxq = s->ethrxq; + struct sge_eth_txq *txq = s->ethtxq; + struct sge_rspq *evtq = &s->fw_evtq; + struct sge_rspq *intrq = &s->intrq; + int qs; + + for (qs = 0; qs < adapter->sge.ethqsets; qs++, rxq++, txq++) { + if (rxq->rspq.desc) + free_rspq_fl(adapter, &rxq->rspq, &rxq->fl); + if (txq->q.desc) { + t4vf_eth_eq_free(adapter, txq->q.cntxt_id); + free_tx_desc(adapter, &txq->q, txq->q.in_use, true); + kfree(txq->q.sdesc); + free_txq(adapter, &txq->q); + } + } + if (evtq->desc) + free_rspq_fl(adapter, evtq, NULL); + if (intrq->desc) + free_rspq_fl(adapter, intrq, NULL); +} + +/** + * t4vf_sge_start - enable SGE operation + * @adapter: the adapter + * + * Start tasklets and timers associated with the DMA engine. + */ +void t4vf_sge_start(struct adapter *adapter) +{ + adapter->sge.ethtxq_rover = 0; + mod_timer(&adapter->sge.rx_timer, jiffies + RX_QCHECK_PERIOD); + mod_timer(&adapter->sge.tx_timer, jiffies + TX_QCHECK_PERIOD); +} + +/** + * t4vf_sge_stop - disable SGE operation + * @adapter: the adapter + * + * Stop tasklets and timers associated with the DMA engine. Note that + * this is effective only if measures have been taken to disable any HW + * events that may restart them. + */ +void t4vf_sge_stop(struct adapter *adapter) +{ + struct sge *s = &adapter->sge; + + if (s->rx_timer.function) + del_timer_sync(&s->rx_timer); + if (s->tx_timer.function) + del_timer_sync(&s->tx_timer); +} + +/** + * t4vf_sge_init - initialize SGE + * @adapter: the adapter + * + * Performs SGE initialization needed every time after a chip reset. + * We do not initialize any of the queue sets here, instead the driver + * top-level must request those individually. We also do not enable DMA + * here, that should be done after the queues have been set up. + */ +int t4vf_sge_init(struct adapter *adapter) +{ + struct sge_params *sge_params = &adapter->params.sge; + u32 fl0 = sge_params->sge_fl_buffer_size[0]; + u32 fl1 = sge_params->sge_fl_buffer_size[1]; + struct sge *s = &adapter->sge; + + /* + * Start by vetting the basic SGE parameters which have been set up by + * the Physical Function Driver. Ideally we should be able to deal + * with _any_ configuration. Practice is different ... + */ + if (fl0 != PAGE_SIZE || (fl1 != 0 && fl1 <= fl0)) { + dev_err(adapter->pdev_dev, "bad SGE FL buffer sizes [%d, %d]\n", + fl0, fl1); + return -EINVAL; + } + if ((sge_params->sge_control & RXPKTCPLMODE) == 0) { + dev_err(adapter->pdev_dev, "bad SGE CPL MODE\n"); + return -EINVAL; + } + + /* + * Now translate the adapter parameters into our internal forms. + */ + if (fl1) + FL_PG_ORDER = ilog2(fl1) - PAGE_SHIFT; + STAT_LEN = ((sge_params->sge_control & EGRSTATUSPAGESIZE) ? 128 : 64); + PKTSHIFT = PKTSHIFT_GET(sge_params->sge_control); + FL_ALIGN = 1 << (INGPADBOUNDARY_GET(sge_params->sge_control) + + SGE_INGPADBOUNDARY_SHIFT); + + /* + * Set up tasklet timers. + */ + setup_timer(&s->rx_timer, sge_rx_timer_cb, (unsigned long)adapter); + setup_timer(&s->tx_timer, sge_tx_timer_cb, (unsigned long)adapter); + + /* + * Initialize Forwarded Interrupt Queue lock. + */ + spin_lock_init(&s->intrq_lock); + + return 0; +} diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h new file mode 100644 index 000000000000..a65c80aed1f2 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h @@ -0,0 +1,274 @@ +/* + * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet + * driver for Linux. + * + * Copyright (c) 2009-2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __T4VF_COMMON_H__ +#define __T4VF_COMMON_H__ + +#include "../cxgb4/t4fw_api.h" + +/* + * The "len16" field of a Firmware Command Structure ... + */ +#define FW_LEN16(fw_struct) FW_CMD_LEN16(sizeof(fw_struct) / 16) + +/* + * Per-VF statistics. + */ +struct t4vf_port_stats { + /* + * TX statistics. + */ + u64 tx_bcast_bytes; /* broadcast */ + u64 tx_bcast_frames; + u64 tx_mcast_bytes; /* multicast */ + u64 tx_mcast_frames; + u64 tx_ucast_bytes; /* unicast */ + u64 tx_ucast_frames; + u64 tx_drop_frames; /* TX dropped frames */ + u64 tx_offload_bytes; /* offload */ + u64 tx_offload_frames; + + /* + * RX statistics. + */ + u64 rx_bcast_bytes; /* broadcast */ + u64 rx_bcast_frames; + u64 rx_mcast_bytes; /* multicast */ + u64 rx_mcast_frames; + u64 rx_ucast_bytes; + u64 rx_ucast_frames; /* unicast */ + + u64 rx_err_frames; /* RX error frames */ +}; + +/* + * Per-"port" (Virtual Interface) link configuration ... + */ +struct link_config { + unsigned int supported; /* link capabilities */ + unsigned int advertising; /* advertised capabilities */ + unsigned short requested_speed; /* speed user has requested */ + unsigned short speed; /* actual link speed */ + unsigned char requested_fc; /* flow control user has requested */ + unsigned char fc; /* actual link flow control */ + unsigned char autoneg; /* autonegotiating? */ + unsigned char link_ok; /* link up? */ +}; + +enum { + PAUSE_RX = 1 << 0, + PAUSE_TX = 1 << 1, + PAUSE_AUTONEG = 1 << 2 +}; + +/* + * General device parameters ... + */ +struct dev_params { + u32 fwrev; /* firmware version */ + u32 tprev; /* TP Microcode Version */ +}; + +/* + * Scatter Gather Engine parameters. These are almost all determined by the + * Physical Function Driver. We just need to grab them to see within which + * environment we're playing ... + */ +struct sge_params { + u32 sge_control; /* padding, boundaries, lengths, etc. */ + u32 sge_host_page_size; /* RDMA page sizes */ + u32 sge_queues_per_page; /* RDMA queues/page */ + u32 sge_user_mode_limits; /* limits for BAR2 user mode accesses */ + u32 sge_fl_buffer_size[16]; /* free list buffer sizes */ + u32 sge_ingress_rx_threshold; /* RX counter interrupt threshold[4] */ + u32 sge_timer_value_0_and_1; /* interrupt coalescing timer values */ + u32 sge_timer_value_2_and_3; + u32 sge_timer_value_4_and_5; +}; + +/* + * Vital Product Data parameters. + */ +struct vpd_params { + u32 cclk; /* Core Clock (KHz) */ +}; + +/* + * Global Receive Side Scaling (RSS) parameters in host-native format. + */ +struct rss_params { + unsigned int mode; /* RSS mode */ + union { + struct { + unsigned int synmapen:1; /* SYN Map Enable */ + unsigned int syn4tupenipv6:1; /* enable hashing 4-tuple IPv6 SYNs */ + unsigned int syn2tupenipv6:1; /* enable hashing 2-tuple IPv6 SYNs */ + unsigned int syn4tupenipv4:1; /* enable hashing 4-tuple IPv4 SYNs */ + unsigned int syn2tupenipv4:1; /* enable hashing 2-tuple IPv4 SYNs */ + unsigned int ofdmapen:1; /* Offload Map Enable */ + unsigned int tnlmapen:1; /* Tunnel Map Enable */ + unsigned int tnlalllookup:1; /* Tunnel All Lookup */ + unsigned int hashtoeplitz:1; /* use Toeplitz hash */ + } basicvirtual; + } u; +}; + +/* + * Virtual Interface RSS Configuration in host-native format. + */ +union rss_vi_config { + struct { + u16 defaultq; /* Ingress Queue ID for !tnlalllookup */ + unsigned int ip6fourtupen:1; /* hash 4-tuple IPv6 ingress packets */ + unsigned int ip6twotupen:1; /* hash 2-tuple IPv6 ingress packets */ + unsigned int ip4fourtupen:1; /* hash 4-tuple IPv4 ingress packets */ + unsigned int ip4twotupen:1; /* hash 2-tuple IPv4 ingress packets */ + int udpen; /* hash 4-tuple UDP ingress packets */ + } basicvirtual; +}; + +/* + * Maximum resources provisioned for a PCI VF. + */ +struct vf_resources { + unsigned int nvi; /* N virtual interfaces */ + unsigned int neq; /* N egress Qs */ + unsigned int nethctrl; /* N egress ETH or CTRL Qs */ + unsigned int niqflint; /* N ingress Qs/w free list(s) & intr */ + unsigned int niq; /* N ingress Qs */ + unsigned int tc; /* PCI-E traffic class */ + unsigned int pmask; /* port access rights mask */ + unsigned int nexactf; /* N exact MPS filters */ + unsigned int r_caps; /* read capabilities */ + unsigned int wx_caps; /* write/execute capabilities */ +}; + +/* + * Per-"adapter" (Virtual Function) parameters. + */ +struct adapter_params { + struct dev_params dev; /* general device parameters */ + struct sge_params sge; /* Scatter Gather Engine */ + struct vpd_params vpd; /* Vital Product Data */ + struct rss_params rss; /* Receive Side Scaling */ + struct vf_resources vfres; /* Virtual Function Resource limits */ + u8 nports; /* # of Ethernet "ports" */ +}; + +#include "adapter.h" + +#ifndef PCI_VENDOR_ID_CHELSIO +# define PCI_VENDOR_ID_CHELSIO 0x1425 +#endif + +#define for_each_port(adapter, iter) \ + for (iter = 0; iter < (adapter)->params.nports; iter++) + +static inline bool is_10g_port(const struct link_config *lc) +{ + return (lc->supported & SUPPORTED_10000baseT_Full) != 0; +} + +static inline unsigned int core_ticks_per_usec(const struct adapter *adapter) +{ + return adapter->params.vpd.cclk / 1000; +} + +static inline unsigned int us_to_core_ticks(const struct adapter *adapter, + unsigned int us) +{ + return (us * adapter->params.vpd.cclk) / 1000; +} + +static inline unsigned int core_ticks_to_us(const struct adapter *adapter, + unsigned int ticks) +{ + return (ticks * 1000) / adapter->params.vpd.cclk; +} + +int t4vf_wr_mbox_core(struct adapter *, const void *, int, void *, bool); + +static inline int t4vf_wr_mbox(struct adapter *adapter, const void *cmd, + int size, void *rpl) +{ + return t4vf_wr_mbox_core(adapter, cmd, size, rpl, true); +} + +static inline int t4vf_wr_mbox_ns(struct adapter *adapter, const void *cmd, + int size, void *rpl) +{ + return t4vf_wr_mbox_core(adapter, cmd, size, rpl, false); +} + +int __devinit t4vf_wait_dev_ready(struct adapter *); +int __devinit t4vf_port_init(struct adapter *, int); + +int t4vf_fw_reset(struct adapter *); +int t4vf_query_params(struct adapter *, unsigned int, const u32 *, u32 *); +int t4vf_set_params(struct adapter *, unsigned int, const u32 *, const u32 *); + +int t4vf_get_sge_params(struct adapter *); +int t4vf_get_vpd_params(struct adapter *); +int t4vf_get_dev_params(struct adapter *); +int t4vf_get_rss_glb_config(struct adapter *); +int t4vf_get_vfres(struct adapter *); + +int t4vf_read_rss_vi_config(struct adapter *, unsigned int, + union rss_vi_config *); +int t4vf_write_rss_vi_config(struct adapter *, unsigned int, + union rss_vi_config *); +int t4vf_config_rss_range(struct adapter *, unsigned int, int, int, + const u16 *, int); + +int t4vf_alloc_vi(struct adapter *, int); +int t4vf_free_vi(struct adapter *, int); +int t4vf_enable_vi(struct adapter *, unsigned int, bool, bool); +int t4vf_identify_port(struct adapter *, unsigned int, unsigned int); + +int t4vf_set_rxmode(struct adapter *, unsigned int, int, int, int, int, int, + bool); +int t4vf_alloc_mac_filt(struct adapter *, unsigned int, bool, unsigned int, + const u8 **, u16 *, u64 *, bool); +int t4vf_change_mac(struct adapter *, unsigned int, int, const u8 *, bool); +int t4vf_set_addr_hash(struct adapter *, unsigned int, bool, u64, bool); +int t4vf_get_port_stats(struct adapter *, int, struct t4vf_port_stats *); + +int t4vf_iq_free(struct adapter *, unsigned int, unsigned int, unsigned int, + unsigned int); +int t4vf_eth_eq_free(struct adapter *, unsigned int); + +int t4vf_handle_fw_rpl(struct adapter *, const __be64 *); + +#endif /* __T4VF_COMMON_H__ */ diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_defs.h b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_defs.h new file mode 100644 index 000000000000..c7b127d93767 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_defs.h @@ -0,0 +1,121 @@ +/* + * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet + * driver for Linux. + * + * Copyright (c) 2009-2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __T4VF_DEFS_H__ +#define __T4VF_DEFS_H__ + +#include "../cxgb4/t4_regs.h" + +/* + * The VF Register Map. + * + * The Scatter Gather Engine (SGE), Multiport Support module (MPS), PIO Local + * bus module (PL) and CPU Interface Module (CIM) components are mapped via + * the Slice to Module Map Table (see below) in the Physical Function Register + * Map. The Mail Box Data (MBDATA) range is mapped via the PCI-E Mailbox Base + * and Offset registers in the PF Register Map. The MBDATA base address is + * quite constrained as it determines the Mailbox Data addresses for both PFs + * and VFs, and therefore must fit in both the VF and PF Register Maps without + * overlapping other registers. + */ +#define T4VF_SGE_BASE_ADDR 0x0000 +#define T4VF_MPS_BASE_ADDR 0x0100 +#define T4VF_PL_BASE_ADDR 0x0200 +#define T4VF_MBDATA_BASE_ADDR 0x0240 +#define T4VF_CIM_BASE_ADDR 0x0300 + +#define T4VF_REGMAP_START 0x0000 +#define T4VF_REGMAP_SIZE 0x0400 + +/* + * There's no hardware limitation which requires that the addresses of the + * Mailbox Data in the fixed CIM PF map and the programmable VF map must + * match. However, it's a useful convention ... + */ +#if T4VF_MBDATA_BASE_ADDR != CIM_PF_MAILBOX_DATA +#error T4VF_MBDATA_BASE_ADDR must match CIM_PF_MAILBOX_DATA! +#endif + +/* + * Virtual Function "Slice to Module Map Table" definitions. + * + * This table allows us to map subsets of the various module register sets + * into the T4VF Register Map. Each table entry identifies the index of the + * module whose registers are being mapped, the offset within the module's + * register set that the mapping should start at, the limit of the mapping, + * and the offset within the T4VF Register Map to which the module's registers + * are being mapped. All addresses and qualtities are in terms of 32-bit + * words. The "limit" value is also in terms of 32-bit words and is equal to + * the last address mapped in the T4VF Register Map 1 (i.e. it's a "<=" + * relation rather than a "<"). + */ +#define T4VF_MOD_MAP(module, index, first, last) \ + T4VF_MOD_MAP_##module##_INDEX = (index), \ + T4VF_MOD_MAP_##module##_FIRST = (first), \ + T4VF_MOD_MAP_##module##_LAST = (last), \ + T4VF_MOD_MAP_##module##_OFFSET = ((first)/4), \ + T4VF_MOD_MAP_##module##_BASE = \ + (T4VF_##module##_BASE_ADDR/4 + (first)/4), \ + T4VF_MOD_MAP_##module##_LIMIT = \ + (T4VF_##module##_BASE_ADDR/4 + (last)/4), + +#define SGE_VF_KDOORBELL 0x0 +#define SGE_VF_GTS 0x4 +#define MPS_VF_CTL 0x0 +#define MPS_VF_STAT_RX_VF_ERR_FRAMES_H 0xfc +#define PL_VF_WHOAMI 0x0 +#define CIM_VF_EXT_MAILBOX_CTRL 0x0 +#define CIM_VF_EXT_MAILBOX_STATUS 0x4 + +enum { + T4VF_MOD_MAP(SGE, 2, SGE_VF_KDOORBELL, SGE_VF_GTS) + T4VF_MOD_MAP(MPS, 0, MPS_VF_CTL, MPS_VF_STAT_RX_VF_ERR_FRAMES_H) + T4VF_MOD_MAP(PL, 3, PL_VF_WHOAMI, PL_VF_WHOAMI) + T4VF_MOD_MAP(CIM, 1, CIM_VF_EXT_MAILBOX_CTRL, CIM_VF_EXT_MAILBOX_STATUS) +}; + +/* + * There isn't a Slice to Module Map Table entry for the Mailbox Data + * registers, but it's convenient to use similar names as above. There are 8 + * little-endian 64-bit Mailbox Data registers. Note that the "instances" + * value below is in terms of 32-bit words which matches the "word" addressing + * space we use above for the Slice to Module Map Space. + */ +#define NUM_CIM_VF_MAILBOX_DATA_INSTANCES 16 + +#define T4VF_MBDATA_FIRST 0 +#define T4VF_MBDATA_LAST ((NUM_CIM_VF_MAILBOX_DATA_INSTANCES-1)*4) + +#endif /* __T4T4VF_DEFS_H__ */ diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c new file mode 100644 index 000000000000..fe3fd3dad6f7 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c @@ -0,0 +1,1387 @@ +/* + * This file is part of the Chelsio T4 PCI-E SR-IOV Virtual Function Ethernet + * driver for Linux. + * + * Copyright (c) 2009-2010 Chelsio Communications, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - 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. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include "t4vf_common.h" +#include "t4vf_defs.h" + +#include "../cxgb4/t4_regs.h" +#include "../cxgb4/t4fw_api.h" + +/* + * Wait for the device to become ready (signified by our "who am I" register + * returning a value other than all 1's). Return an error if it doesn't + * become ready ... + */ +int __devinit t4vf_wait_dev_ready(struct adapter *adapter) +{ + const u32 whoami = T4VF_PL_BASE_ADDR + PL_VF_WHOAMI; + const u32 notready1 = 0xffffffff; + const u32 notready2 = 0xeeeeeeee; + u32 val; + + val = t4_read_reg(adapter, whoami); + if (val != notready1 && val != notready2) + return 0; + msleep(500); + val = t4_read_reg(adapter, whoami); + if (val != notready1 && val != notready2) + return 0; + else + return -EIO; +} + +/* + * Get the reply to a mailbox command and store it in @rpl in big-endian order + * (since the firmware data structures are specified in a big-endian layout). + */ +static void get_mbox_rpl(struct adapter *adapter, __be64 *rpl, int size, + u32 mbox_data) +{ + for ( ; size; size -= 8, mbox_data += 8) + *rpl++ = cpu_to_be64(t4_read_reg64(adapter, mbox_data)); +} + +/* + * Dump contents of mailbox with a leading tag. + */ +static void dump_mbox(struct adapter *adapter, const char *tag, u32 mbox_data) +{ + dev_err(adapter->pdev_dev, + "mbox %s: %llx %llx %llx %llx %llx %llx %llx %llx\n", tag, + (unsigned long long)t4_read_reg64(adapter, mbox_data + 0), + (unsigned long long)t4_read_reg64(adapter, mbox_data + 8), + (unsigned long long)t4_read_reg64(adapter, mbox_data + 16), + (unsigned long long)t4_read_reg64(adapter, mbox_data + 24), + (unsigned long long)t4_read_reg64(adapter, mbox_data + 32), + (unsigned long long)t4_read_reg64(adapter, mbox_data + 40), + (unsigned long long)t4_read_reg64(adapter, mbox_data + 48), + (unsigned long long)t4_read_reg64(adapter, mbox_data + 56)); +} + +/** + * t4vf_wr_mbox_core - send a command to FW through the mailbox + * @adapter: the adapter + * @cmd: the command to write + * @size: command length in bytes + * @rpl: where to optionally store the reply + * @sleep_ok: if true we may sleep while awaiting command completion + * + * Sends the given command to FW through the mailbox and waits for the + * FW to execute the command. If @rpl is not %NULL it is used to store + * the FW's reply to the command. The command and its optional reply + * are of the same length. FW can take up to 500 ms to respond. + * @sleep_ok determines whether we may sleep while awaiting the response. + * If sleeping is allowed we use progressive backoff otherwise we spin. + * + * The return value is 0 on success or a negative errno on failure. A + * failure can happen either because we are not able to execute the + * command or FW executes it but signals an error. In the latter case + * the return value is the error code indicated by FW (negated). + */ +int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size, + void *rpl, bool sleep_ok) +{ + static const int delay[] = { + 1, 1, 3, 5, 10, 10, 20, 50, 100 + }; + + u32 v; + int i, ms, delay_idx; + const __be64 *p; + u32 mbox_data = T4VF_MBDATA_BASE_ADDR; + u32 mbox_ctl = T4VF_CIM_BASE_ADDR + CIM_VF_EXT_MAILBOX_CTRL; + + /* + * Commands must be multiples of 16 bytes in length and may not be + * larger than the size of the Mailbox Data register array. + */ + if ((size % 16) != 0 || + size > NUM_CIM_VF_MAILBOX_DATA_INSTANCES * 4) + return -EINVAL; + + /* + * Loop trying to get ownership of the mailbox. Return an error + * if we can't gain ownership. + */ + v = MBOWNER_GET(t4_read_reg(adapter, mbox_ctl)); + for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++) + v = MBOWNER_GET(t4_read_reg(adapter, mbox_ctl)); + if (v != MBOX_OWNER_DRV) + return v == MBOX_OWNER_FW ? -EBUSY : -ETIMEDOUT; + + /* + * Write the command array into the Mailbox Data register array and + * transfer ownership of the mailbox to the firmware. + * + * For the VFs, the Mailbox Data "registers" are actually backed by + * T4's "MA" interface rather than PL Registers (as is the case for + * the PFs). Because these are in different coherency domains, the + * write to the VF's PL-register-backed Mailbox Control can race in + * front of the writes to the MA-backed VF Mailbox Data "registers". + * So we need to do a read-back on at least one byte of the VF Mailbox + * Data registers before doing the write to the VF Mailbox Control + * register. + */ + for (i = 0, p = cmd; i < size; i += 8) + t4_write_reg64(adapter, mbox_data + i, be64_to_cpu(*p++)); + t4_read_reg(adapter, mbox_data); /* flush write */ + + t4_write_reg(adapter, mbox_ctl, + MBMSGVALID | MBOWNER(MBOX_OWNER_FW)); + t4_read_reg(adapter, mbox_ctl); /* flush write */ + + /* + * Spin waiting for firmware to acknowledge processing our command. + */ + delay_idx = 0; + ms = delay[0]; + + for (i = 0; i < FW_CMD_MAX_TIMEOUT; i += ms) { + if (sleep_ok) { + ms = delay[delay_idx]; + if (delay_idx < ARRAY_SIZE(delay) - 1) + delay_idx++; + msleep(ms); + } else + mdelay(ms); + + /* + * If we're the owner, see if this is the reply we wanted. + */ + v = t4_read_reg(adapter, mbox_ctl); + if (MBOWNER_GET(v) == MBOX_OWNER_DRV) { + /* + * If the Message Valid bit isn't on, revoke ownership + * of the mailbox and continue waiting for our reply. + */ + if ((v & MBMSGVALID) == 0) { + t4_write_reg(adapter, mbox_ctl, + MBOWNER(MBOX_OWNER_NONE)); + continue; + } + + /* + * We now have our reply. Extract the command return + * value, copy the reply back to our caller's buffer + * (if specified) and revoke ownership of the mailbox. + * We return the (negated) firmware command return + * code (this depends on FW_SUCCESS == 0). + */ + + /* return value in low-order little-endian word */ + v = t4_read_reg(adapter, mbox_data); + if (FW_CMD_RETVAL_GET(v)) + dump_mbox(adapter, "FW Error", mbox_data); + + if (rpl) { + /* request bit in high-order BE word */ + WARN_ON((be32_to_cpu(*(const u32 *)cmd) + & FW_CMD_REQUEST) == 0); + get_mbox_rpl(adapter, rpl, size, mbox_data); + WARN_ON((be32_to_cpu(*(u32 *)rpl) + & FW_CMD_REQUEST) != 0); + } + t4_write_reg(adapter, mbox_ctl, + MBOWNER(MBOX_OWNER_NONE)); + return -FW_CMD_RETVAL_GET(v); + } + } + + /* + * We timed out. Return the error ... + */ + dump_mbox(adapter, "FW Timeout", mbox_data); + return -ETIMEDOUT; +} + +/** + * hash_mac_addr - return the hash value of a MAC address + * @addr: the 48-bit Ethernet MAC address + * + * Hashes a MAC address according to the hash function used by hardware + * inexact (hash) address matching. + */ +static int hash_mac_addr(const u8 *addr) +{ + u32 a = ((u32)addr[0] << 16) | ((u32)addr[1] << 8) | addr[2]; + u32 b = ((u32)addr[3] << 16) | ((u32)addr[4] << 8) | addr[5]; + a ^= b; + a ^= (a >> 12); + a ^= (a >> 6); + return a & 0x3f; +} + +/** + * init_link_config - initialize a link's SW state + * @lc: structure holding the link state + * @caps: link capabilities + * + * Initializes the SW state maintained for each link, including the link's + * capabilities and default speed/flow-control/autonegotiation settings. + */ +static void __devinit init_link_config(struct link_config *lc, + unsigned int caps) +{ + lc->supported = caps; + lc->requested_speed = 0; + lc->speed = 0; + lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX; + if (lc->supported & SUPPORTED_Autoneg) { + lc->advertising = lc->supported; + lc->autoneg = AUTONEG_ENABLE; + lc->requested_fc |= PAUSE_AUTONEG; + } else { + lc->advertising = 0; + lc->autoneg = AUTONEG_DISABLE; + } +} + +/** + * t4vf_port_init - initialize port hardware/software state + * @adapter: the adapter + * @pidx: the adapter port index + */ +int __devinit t4vf_port_init(struct adapter *adapter, int pidx) +{ + struct port_info *pi = adap2pinfo(adapter, pidx); + struct fw_vi_cmd vi_cmd, vi_rpl; + struct fw_port_cmd port_cmd, port_rpl; + int v; + u32 word; + + /* + * Execute a VI Read command to get our Virtual Interface information + * like MAC address, etc. + */ + memset(&vi_cmd, 0, sizeof(vi_cmd)); + vi_cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_VI_CMD) | + FW_CMD_REQUEST | + FW_CMD_READ); + vi_cmd.alloc_to_len16 = cpu_to_be32(FW_LEN16(vi_cmd)); + vi_cmd.type_viid = cpu_to_be16(FW_VI_CMD_VIID(pi->viid)); + v = t4vf_wr_mbox(adapter, &vi_cmd, sizeof(vi_cmd), &vi_rpl); + if (v) + return v; + + BUG_ON(pi->port_id != FW_VI_CMD_PORTID_GET(vi_rpl.portid_pkd)); + pi->rss_size = FW_VI_CMD_RSSSIZE_GET(be16_to_cpu(vi_rpl.rsssize_pkd)); + t4_os_set_hw_addr(adapter, pidx, vi_rpl.mac); + + /* + * If we don't have read access to our port information, we're done + * now. Otherwise, execute a PORT Read command to get it ... + */ + if (!(adapter->params.vfres.r_caps & FW_CMD_CAP_PORT)) + return 0; + + memset(&port_cmd, 0, sizeof(port_cmd)); + port_cmd.op_to_portid = cpu_to_be32(FW_CMD_OP(FW_PORT_CMD) | + FW_CMD_REQUEST | + FW_CMD_READ | + FW_PORT_CMD_PORTID(pi->port_id)); + port_cmd.action_to_len16 = + cpu_to_be32(FW_PORT_CMD_ACTION(FW_PORT_ACTION_GET_PORT_INFO) | + FW_LEN16(port_cmd)); + v = t4vf_wr_mbox(adapter, &port_cmd, sizeof(port_cmd), &port_rpl); + if (v) + return v; + + v = 0; + word = be16_to_cpu(port_rpl.u.info.pcap); + if (word & FW_PORT_CAP_SPEED_100M) + v |= SUPPORTED_100baseT_Full; + if (word & FW_PORT_CAP_SPEED_1G) + v |= SUPPORTED_1000baseT_Full; + if (word & FW_PORT_CAP_SPEED_10G) + v |= SUPPORTED_10000baseT_Full; + if (word & FW_PORT_CAP_ANEG) + v |= SUPPORTED_Autoneg; + init_link_config(&pi->link_cfg, v); + + return 0; +} + +/** + * t4vf_fw_reset - issue a reset to FW + * @adapter: the adapter + * + * Issues a reset command to FW. For a Physical Function this would + * result in the Firmware reseting all of its state. For a Virtual + * Function this just resets the state associated with the VF. + */ +int t4vf_fw_reset(struct adapter *adapter) +{ + struct fw_reset_cmd cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_write = cpu_to_be32(FW_CMD_OP(FW_RESET_CMD) | + FW_CMD_WRITE); + cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); + return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL); +} + +/** + * t4vf_query_params - query FW or device parameters + * @adapter: the adapter + * @nparams: the number of parameters + * @params: the parameter names + * @vals: the parameter values + * + * Reads the values of firmware or device parameters. Up to 7 parameters + * can be queried at once. + */ +int t4vf_query_params(struct adapter *adapter, unsigned int nparams, + const u32 *params, u32 *vals) +{ + int i, ret; + struct fw_params_cmd cmd, rpl; + struct fw_params_param *p; + size_t len16; + + if (nparams > 7) + return -EINVAL; + + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_PARAMS_CMD) | + FW_CMD_REQUEST | + FW_CMD_READ); + len16 = DIV_ROUND_UP(offsetof(struct fw_params_cmd, + param[nparams].mnem), 16); + cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16(len16)); + for (i = 0, p = &cmd.param[0]; i < nparams; i++, p++) + p->mnem = htonl(*params++); + + ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); + if (ret == 0) + for (i = 0, p = &rpl.param[0]; i < nparams; i++, p++) + *vals++ = be32_to_cpu(p->val); + return ret; +} + +/** + * t4vf_set_params - sets FW or device parameters + * @adapter: the adapter + * @nparams: the number of parameters + * @params: the parameter names + * @vals: the parameter values + * + * Sets the values of firmware or device parameters. Up to 7 parameters + * can be specified at once. + */ +int t4vf_set_params(struct adapter *adapter, unsigned int nparams, + const u32 *params, const u32 *vals) +{ + int i; + struct fw_params_cmd cmd; + struct fw_params_param *p; + size_t len16; + + if (nparams > 7) + return -EINVAL; + + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_PARAMS_CMD) | + FW_CMD_REQUEST | + FW_CMD_WRITE); + len16 = DIV_ROUND_UP(offsetof(struct fw_params_cmd, + param[nparams]), 16); + cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16(len16)); + for (i = 0, p = &cmd.param[0]; i < nparams; i++, p++) { + p->mnem = cpu_to_be32(*params++); + p->val = cpu_to_be32(*vals++); + } + + return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL); +} + +/** + * t4vf_get_sge_params - retrieve adapter Scatter gather Engine parameters + * @adapter: the adapter + * + * Retrieves various core SGE parameters in the form of hardware SGE + * register values. The caller is responsible for decoding these as + * needed. The SGE parameters are stored in @adapter->params.sge. + */ +int t4vf_get_sge_params(struct adapter *adapter) +{ + struct sge_params *sge_params = &adapter->params.sge; + u32 params[7], vals[7]; + int v; + + params[0] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) | + FW_PARAMS_PARAM_XYZ(SGE_CONTROL)); + params[1] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) | + FW_PARAMS_PARAM_XYZ(SGE_HOST_PAGE_SIZE)); + params[2] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) | + FW_PARAMS_PARAM_XYZ(SGE_FL_BUFFER_SIZE0)); + params[3] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) | + FW_PARAMS_PARAM_XYZ(SGE_FL_BUFFER_SIZE1)); + params[4] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) | + FW_PARAMS_PARAM_XYZ(SGE_TIMER_VALUE_0_AND_1)); + params[5] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) | + FW_PARAMS_PARAM_XYZ(SGE_TIMER_VALUE_2_AND_3)); + params[6] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) | + FW_PARAMS_PARAM_XYZ(SGE_TIMER_VALUE_4_AND_5)); + v = t4vf_query_params(adapter, 7, params, vals); + if (v) + return v; + sge_params->sge_control = vals[0]; + sge_params->sge_host_page_size = vals[1]; + sge_params->sge_fl_buffer_size[0] = vals[2]; + sge_params->sge_fl_buffer_size[1] = vals[3]; + sge_params->sge_timer_value_0_and_1 = vals[4]; + sge_params->sge_timer_value_2_and_3 = vals[5]; + sge_params->sge_timer_value_4_and_5 = vals[6]; + + params[0] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_REG) | + FW_PARAMS_PARAM_XYZ(SGE_INGRESS_RX_THRESHOLD)); + v = t4vf_query_params(adapter, 1, params, vals); + if (v) + return v; + sge_params->sge_ingress_rx_threshold = vals[0]; + + return 0; +} + +/** + * t4vf_get_vpd_params - retrieve device VPD paremeters + * @adapter: the adapter + * + * Retrives various device Vital Product Data parameters. The parameters + * are stored in @adapter->params.vpd. + */ +int t4vf_get_vpd_params(struct adapter *adapter) +{ + struct vpd_params *vpd_params = &adapter->params.vpd; + u32 params[7], vals[7]; + int v; + + params[0] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | + FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_CCLK)); + v = t4vf_query_params(adapter, 1, params, vals); + if (v) + return v; + vpd_params->cclk = vals[0]; + + return 0; +} + +/** + * t4vf_get_dev_params - retrieve device paremeters + * @adapter: the adapter + * + * Retrives various device parameters. The parameters are stored in + * @adapter->params.dev. + */ +int t4vf_get_dev_params(struct adapter *adapter) +{ + struct dev_params *dev_params = &adapter->params.dev; + u32 params[7], vals[7]; + int v; + + params[0] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | + FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_FWREV)); + params[1] = (FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | + FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_TPREV)); + v = t4vf_query_params(adapter, 2, params, vals); + if (v) + return v; + dev_params->fwrev = vals[0]; + dev_params->tprev = vals[1]; + + return 0; +} + +/** + * t4vf_get_rss_glb_config - retrieve adapter RSS Global Configuration + * @adapter: the adapter + * + * Retrieves global RSS mode and parameters with which we have to live + * and stores them in the @adapter's RSS parameters. + */ +int t4vf_get_rss_glb_config(struct adapter *adapter) +{ + struct rss_params *rss = &adapter->params.rss; + struct fw_rss_glb_config_cmd cmd, rpl; + int v; + + /* + * Execute an RSS Global Configuration read command to retrieve + * our RSS configuration. + */ + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_write = cpu_to_be32(FW_CMD_OP(FW_RSS_GLB_CONFIG_CMD) | + FW_CMD_REQUEST | + FW_CMD_READ); + cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); + v = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); + if (v) + return v; + + /* + * Transate the big-endian RSS Global Configuration into our + * cpu-endian format based on the RSS mode. We also do first level + * filtering at this point to weed out modes which don't support + * VF Drivers ... + */ + rss->mode = FW_RSS_GLB_CONFIG_CMD_MODE_GET( + be32_to_cpu(rpl.u.manual.mode_pkd)); + switch (rss->mode) { + case FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL: { + u32 word = be32_to_cpu( + rpl.u.basicvirtual.synmapen_to_hashtoeplitz); + + rss->u.basicvirtual.synmapen = + ((word & FW_RSS_GLB_CONFIG_CMD_SYNMAPEN) != 0); + rss->u.basicvirtual.syn4tupenipv6 = + ((word & FW_RSS_GLB_CONFIG_CMD_SYN4TUPENIPV6) != 0); + rss->u.basicvirtual.syn2tupenipv6 = + ((word & FW_RSS_GLB_CONFIG_CMD_SYN2TUPENIPV6) != 0); + rss->u.basicvirtual.syn4tupenipv4 = + ((word & FW_RSS_GLB_CONFIG_CMD_SYN4TUPENIPV4) != 0); + rss->u.basicvirtual.syn2tupenipv4 = + ((word & FW_RSS_GLB_CONFIG_CMD_SYN2TUPENIPV4) != 0); + + rss->u.basicvirtual.ofdmapen = + ((word & FW_RSS_GLB_CONFIG_CMD_OFDMAPEN) != 0); + + rss->u.basicvirtual.tnlmapen = + ((word & FW_RSS_GLB_CONFIG_CMD_TNLMAPEN) != 0); + rss->u.basicvirtual.tnlalllookup = + ((word & FW_RSS_GLB_CONFIG_CMD_TNLALLLKP) != 0); + + rss->u.basicvirtual.hashtoeplitz = + ((word & FW_RSS_GLB_CONFIG_CMD_HASHTOEPLITZ) != 0); + + /* we need at least Tunnel Map Enable to be set */ + if (!rss->u.basicvirtual.tnlmapen) + return -EINVAL; + break; + } + + default: + /* all unknown/unsupported RSS modes result in an error */ + return -EINVAL; + } + + return 0; +} + +/** + * t4vf_get_vfres - retrieve VF resource limits + * @adapter: the adapter + * + * Retrieves configured resource limits and capabilities for a virtual + * function. The results are stored in @adapter->vfres. + */ +int t4vf_get_vfres(struct adapter *adapter) +{ + struct vf_resources *vfres = &adapter->params.vfres; + struct fw_pfvf_cmd cmd, rpl; + int v; + u32 word; + + /* + * Execute PFVF Read command to get VF resource limits; bail out early + * with error on command failure. + */ + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_PFVF_CMD) | + FW_CMD_REQUEST | + FW_CMD_READ); + cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); + v = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); + if (v) + return v; + + /* + * Extract VF resource limits and return success. + */ + word = be32_to_cpu(rpl.niqflint_niq); + vfres->niqflint = FW_PFVF_CMD_NIQFLINT_GET(word); + vfres->niq = FW_PFVF_CMD_NIQ_GET(word); + + word = be32_to_cpu(rpl.type_to_neq); + vfres->neq = FW_PFVF_CMD_NEQ_GET(word); + vfres->pmask = FW_PFVF_CMD_PMASK_GET(word); + + word = be32_to_cpu(rpl.tc_to_nexactf); + vfres->tc = FW_PFVF_CMD_TC_GET(word); + vfres->nvi = FW_PFVF_CMD_NVI_GET(word); + vfres->nexactf = FW_PFVF_CMD_NEXACTF_GET(word); + + word = be32_to_cpu(rpl.r_caps_to_nethctrl); + vfres->r_caps = FW_PFVF_CMD_R_CAPS_GET(word); + vfres->wx_caps = FW_PFVF_CMD_WX_CAPS_GET(word); + vfres->nethctrl = FW_PFVF_CMD_NETHCTRL_GET(word); + + return 0; +} + +/** + * t4vf_read_rss_vi_config - read a VI's RSS configuration + * @adapter: the adapter + * @viid: Virtual Interface ID + * @config: pointer to host-native VI RSS Configuration buffer + * + * Reads the Virtual Interface's RSS configuration information and + * translates it into CPU-native format. + */ +int t4vf_read_rss_vi_config(struct adapter *adapter, unsigned int viid, + union rss_vi_config *config) +{ + struct fw_rss_vi_config_cmd cmd, rpl; + int v; + + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_RSS_VI_CONFIG_CMD) | + FW_CMD_REQUEST | + FW_CMD_READ | + FW_RSS_VI_CONFIG_CMD_VIID(viid)); + cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); + v = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); + if (v) + return v; + + switch (adapter->params.rss.mode) { + case FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL: { + u32 word = be32_to_cpu(rpl.u.basicvirtual.defaultq_to_udpen); + + config->basicvirtual.ip6fourtupen = + ((word & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN) != 0); + config->basicvirtual.ip6twotupen = + ((word & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN) != 0); + config->basicvirtual.ip4fourtupen = + ((word & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN) != 0); + config->basicvirtual.ip4twotupen = + ((word & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN) != 0); + config->basicvirtual.udpen = + ((word & FW_RSS_VI_CONFIG_CMD_UDPEN) != 0); + config->basicvirtual.defaultq = + FW_RSS_VI_CONFIG_CMD_DEFAULTQ_GET(word); + break; + } + + default: + return -EINVAL; + } + + return 0; +} + +/** + * t4vf_write_rss_vi_config - write a VI's RSS configuration + * @adapter: the adapter + * @viid: Virtual Interface ID + * @config: pointer to host-native VI RSS Configuration buffer + * + * Write the Virtual Interface's RSS configuration information + * (translating it into firmware-native format before writing). + */ +int t4vf_write_rss_vi_config(struct adapter *adapter, unsigned int viid, + union rss_vi_config *config) +{ + struct fw_rss_vi_config_cmd cmd, rpl; + + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_RSS_VI_CONFIG_CMD) | + FW_CMD_REQUEST | + FW_CMD_WRITE | + FW_RSS_VI_CONFIG_CMD_VIID(viid)); + cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); + switch (adapter->params.rss.mode) { + case FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL: { + u32 word = 0; + + if (config->basicvirtual.ip6fourtupen) + word |= FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN; + if (config->basicvirtual.ip6twotupen) + word |= FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN; + if (config->basicvirtual.ip4fourtupen) + word |= FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN; + if (config->basicvirtual.ip4twotupen) + word |= FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN; + if (config->basicvirtual.udpen) + word |= FW_RSS_VI_CONFIG_CMD_UDPEN; + word |= FW_RSS_VI_CONFIG_CMD_DEFAULTQ( + config->basicvirtual.defaultq); + cmd.u.basicvirtual.defaultq_to_udpen = cpu_to_be32(word); + break; + } + + default: + return -EINVAL; + } + + return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); +} + +/** + * t4vf_config_rss_range - configure a portion of the RSS mapping table + * @adapter: the adapter + * @viid: Virtual Interface of RSS Table Slice + * @start: starting entry in the table to write + * @n: how many table entries to write + * @rspq: values for the "Response Queue" (Ingress Queue) lookup table + * @nrspq: number of values in @rspq + * + * Programs the selected part of the VI's RSS mapping table with the + * provided values. If @nrspq < @n the supplied values are used repeatedly + * until the full table range is populated. + * + * The caller must ensure the values in @rspq are in the range 0..1023. + */ +int t4vf_config_rss_range(struct adapter *adapter, unsigned int viid, + int start, int n, const u16 *rspq, int nrspq) +{ + const u16 *rsp = rspq; + const u16 *rsp_end = rspq+nrspq; + struct fw_rss_ind_tbl_cmd cmd; + + /* + * Initialize firmware command template to write the RSS table. + */ + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_RSS_IND_TBL_CMD) | + FW_CMD_REQUEST | + FW_CMD_WRITE | + FW_RSS_IND_TBL_CMD_VIID(viid)); + cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); + + /* + * Each firmware RSS command can accommodate up to 32 RSS Ingress + * Queue Identifiers. These Ingress Queue IDs are packed three to + * a 32-bit word as 10-bit values with the upper remaining 2 bits + * reserved. + */ + while (n > 0) { + __be32 *qp = &cmd.iq0_to_iq2; + int nq = min(n, 32); + int ret; + + /* + * Set up the firmware RSS command header to send the next + * "nq" Ingress Queue IDs to the firmware. + */ + cmd.niqid = cpu_to_be16(nq); + cmd.startidx = cpu_to_be16(start); + + /* + * "nq" more done for the start of the next loop. + */ + start += nq; + n -= nq; + + /* + * While there are still Ingress Queue IDs to stuff into the + * current firmware RSS command, retrieve them from the + * Ingress Queue ID array and insert them into the command. + */ + while (nq > 0) { + /* + * Grab up to the next 3 Ingress Queue IDs (wrapping + * around the Ingress Queue ID array if necessary) and + * insert them into the firmware RSS command at the + * current 3-tuple position within the commad. + */ + u16 qbuf[3]; + u16 *qbp = qbuf; + int nqbuf = min(3, nq); + + nq -= nqbuf; + qbuf[0] = qbuf[1] = qbuf[2] = 0; + while (nqbuf) { + nqbuf--; + *qbp++ = *rsp++; + if (rsp >= rsp_end) + rsp = rspq; + } + *qp++ = cpu_to_be32(FW_RSS_IND_TBL_CMD_IQ0(qbuf[0]) | + FW_RSS_IND_TBL_CMD_IQ1(qbuf[1]) | + FW_RSS_IND_TBL_CMD_IQ2(qbuf[2])); + } + + /* + * Send this portion of the RRS table update to the firmware; + * bail out on any errors. + */ + ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL); + if (ret) + return ret; + } + return 0; +} + +/** + * t4vf_alloc_vi - allocate a virtual interface on a port + * @adapter: the adapter + * @port_id: physical port associated with the VI + * + * Allocate a new Virtual Interface and bind it to the indicated + * physical port. Return the new Virtual Interface Identifier on + * success, or a [negative] error number on failure. + */ +int t4vf_alloc_vi(struct adapter *adapter, int port_id) +{ + struct fw_vi_cmd cmd, rpl; + int v; + + /* + * Execute a VI command to allocate Virtual Interface and return its + * VIID. + */ + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_VI_CMD) | + FW_CMD_REQUEST | + FW_CMD_WRITE | + FW_CMD_EXEC); + cmd.alloc_to_len16 = cpu_to_be32(FW_LEN16(cmd) | + FW_VI_CMD_ALLOC); + cmd.portid_pkd = FW_VI_CMD_PORTID(port_id); + v = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); + if (v) + return v; + + return FW_VI_CMD_VIID_GET(be16_to_cpu(rpl.type_viid)); +} + +/** + * t4vf_free_vi -- free a virtual interface + * @adapter: the adapter + * @viid: the virtual interface identifier + * + * Free a previously allocated Virtual Interface. Return an error on + * failure. + */ +int t4vf_free_vi(struct adapter *adapter, int viid) +{ + struct fw_vi_cmd cmd; + + /* + * Execute a VI command to free the Virtual Interface. + */ + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_VI_CMD) | + FW_CMD_REQUEST | + FW_CMD_EXEC); + cmd.alloc_to_len16 = cpu_to_be32(FW_LEN16(cmd) | + FW_VI_CMD_FREE); + cmd.type_viid = cpu_to_be16(FW_VI_CMD_VIID(viid)); + return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL); +} + +/** + * t4vf_enable_vi - enable/disable a virtual interface + * @adapter: the adapter + * @viid: the Virtual Interface ID + * @rx_en: 1=enable Rx, 0=disable Rx + * @tx_en: 1=enable Tx, 0=disable Tx + * + * Enables/disables a virtual interface. + */ +int t4vf_enable_vi(struct adapter *adapter, unsigned int viid, + bool rx_en, bool tx_en) +{ + struct fw_vi_enable_cmd cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_ENABLE_CMD) | + FW_CMD_REQUEST | + FW_CMD_EXEC | + FW_VI_ENABLE_CMD_VIID(viid)); + cmd.ien_to_len16 = cpu_to_be32(FW_VI_ENABLE_CMD_IEN(rx_en) | + FW_VI_ENABLE_CMD_EEN(tx_en) | + FW_LEN16(cmd)); + return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL); +} + +/** + * t4vf_identify_port - identify a VI's port by blinking its LED + * @adapter: the adapter + * @viid: the Virtual Interface ID + * @nblinks: how many times to blink LED at 2.5 Hz + * + * Identifies a VI's port by blinking its LED. + */ +int t4vf_identify_port(struct adapter *adapter, unsigned int viid, + unsigned int nblinks) +{ + struct fw_vi_enable_cmd cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_ENABLE_CMD) | + FW_CMD_REQUEST | + FW_CMD_EXEC | + FW_VI_ENABLE_CMD_VIID(viid)); + cmd.ien_to_len16 = cpu_to_be32(FW_VI_ENABLE_CMD_LED | + FW_LEN16(cmd)); + cmd.blinkdur = cpu_to_be16(nblinks); + return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL); +} + +/** + * t4vf_set_rxmode - set Rx properties of a virtual interface + * @adapter: the adapter + * @viid: the VI id + * @mtu: the new MTU or -1 for no change + * @promisc: 1 to enable promiscuous mode, 0 to disable it, -1 no change + * @all_multi: 1 to enable all-multi mode, 0 to disable it, -1 no change + * @bcast: 1 to enable broadcast Rx, 0 to disable it, -1 no change + * @vlanex: 1 to enable hardware VLAN Tag extraction, 0 to disable it, + * -1 no change + * + * Sets Rx properties of a virtual interface. + */ +int t4vf_set_rxmode(struct adapter *adapter, unsigned int viid, + int mtu, int promisc, int all_multi, int bcast, int vlanex, + bool sleep_ok) +{ + struct fw_vi_rxmode_cmd cmd; + + /* convert to FW values */ + if (mtu < 0) + mtu = FW_VI_RXMODE_CMD_MTU_MASK; + if (promisc < 0) + promisc = FW_VI_RXMODE_CMD_PROMISCEN_MASK; + if (all_multi < 0) + all_multi = FW_VI_RXMODE_CMD_ALLMULTIEN_MASK; + if (bcast < 0) + bcast = FW_VI_RXMODE_CMD_BROADCASTEN_MASK; + if (vlanex < 0) + vlanex = FW_VI_RXMODE_CMD_VLANEXEN_MASK; + + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_RXMODE_CMD) | + FW_CMD_REQUEST | + FW_CMD_WRITE | + FW_VI_RXMODE_CMD_VIID(viid)); + cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd)); + cmd.mtu_to_vlanexen = + cpu_to_be32(FW_VI_RXMODE_CMD_MTU(mtu) | + FW_VI_RXMODE_CMD_PROMISCEN(promisc) | + FW_VI_RXMODE_CMD_ALLMULTIEN(all_multi) | + FW_VI_RXMODE_CMD_BROADCASTEN(bcast) | + FW_VI_RXMODE_CMD_VLANEXEN(vlanex)); + return t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), NULL, sleep_ok); +} + +/** + * t4vf_alloc_mac_filt - allocates exact-match filters for MAC addresses + * @adapter: the adapter + * @viid: the Virtual Interface Identifier + * @free: if true any existing filters for this VI id are first removed + * @naddr: the number of MAC addresses to allocate filters for (up to 7) + * @addr: the MAC address(es) + * @idx: where to store the index of each allocated filter + * @hash: pointer to hash address filter bitmap + * @sleep_ok: call is allowed to sleep + * + * Allocates an exact-match filter for each of the supplied addresses and + * sets it to the corresponding address. If @idx is not %NULL it should + * have at least @naddr entries, each of which will be set to the index of + * the filter allocated for the corresponding MAC address. If a filter + * could not be allocated for an address its index is set to 0xffff. + * If @hash is not %NULL addresses that fail to allocate an exact filter + * are hashed and update the hash filter bitmap pointed at by @hash. + * + * Returns a negative error number or the number of filters allocated. + */ +int t4vf_alloc_mac_filt(struct adapter *adapter, unsigned int viid, bool free, + unsigned int naddr, const u8 **addr, u16 *idx, + u64 *hash, bool sleep_ok) +{ + int offset, ret = 0; + unsigned nfilters = 0; + unsigned int rem = naddr; + struct fw_vi_mac_cmd cmd, rpl; + + if (naddr > FW_CLS_TCAM_NUM_ENTRIES) + return -EINVAL; + + for (offset = 0; offset < naddr; /**/) { + unsigned int fw_naddr = (rem < ARRAY_SIZE(cmd.u.exact) + ? rem + : ARRAY_SIZE(cmd.u.exact)); + size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd, + u.exact[fw_naddr]), 16); + struct fw_vi_mac_exact *p; + int i; + + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) | + FW_CMD_REQUEST | + FW_CMD_WRITE | + (free ? FW_CMD_EXEC : 0) | + FW_VI_MAC_CMD_VIID(viid)); + cmd.freemacs_to_len16 = + cpu_to_be32(FW_VI_MAC_CMD_FREEMACS(free) | + FW_CMD_LEN16(len16)); + + for (i = 0, p = cmd.u.exact; i < fw_naddr; i++, p++) { + p->valid_to_idx = cpu_to_be16( + FW_VI_MAC_CMD_VALID | + FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC)); + memcpy(p->macaddr, addr[offset+i], sizeof(p->macaddr)); + } + + + ret = t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), &rpl, + sleep_ok); + if (ret && ret != -ENOMEM) + break; + + for (i = 0, p = rpl.u.exact; i < fw_naddr; i++, p++) { + u16 index = FW_VI_MAC_CMD_IDX_GET( + be16_to_cpu(p->valid_to_idx)); + + if (idx) + idx[offset+i] = + (index >= FW_CLS_TCAM_NUM_ENTRIES + ? 0xffff + : index); + if (index < FW_CLS_TCAM_NUM_ENTRIES) + nfilters++; + else if (hash) + *hash |= (1ULL << hash_mac_addr(addr[offset+i])); + } + + free = false; + offset += fw_naddr; + rem -= fw_naddr; + } + + /* + * If there were no errors or we merely ran out of room in our MAC + * address arena, return the number of filters actually written. + */ + if (ret == 0 || ret == -ENOMEM) + ret = nfilters; + return ret; +} + +/** + * t4vf_change_mac - modifies the exact-match filter for a MAC address + * @adapter: the adapter + * @viid: the Virtual Interface ID + * @idx: index of existing filter for old value of MAC address, or -1 + * @addr: the new MAC address value + * @persist: if idx < 0, the new MAC allocation should be persistent + * + * Modifies an exact-match filter and sets it to the new MAC address. + * Note that in general it is not possible to modify the value of a given + * filter so the generic way to modify an address filter is to free the + * one being used by the old address value and allocate a new filter for + * the new address value. @idx can be -1 if the address is a new + * addition. + * + * Returns a negative error number or the index of the filter with the new + * MAC value. + */ +int t4vf_change_mac(struct adapter *adapter, unsigned int viid, + int idx, const u8 *addr, bool persist) +{ + int ret; + struct fw_vi_mac_cmd cmd, rpl; + struct fw_vi_mac_exact *p = &cmd.u.exact[0]; + size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd, + u.exact[1]), 16); + + /* + * If this is a new allocation, determine whether it should be + * persistent (across a "freemacs" operation) or not. + */ + if (idx < 0) + idx = persist ? FW_VI_MAC_ADD_PERSIST_MAC : FW_VI_MAC_ADD_MAC; + + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) | + FW_CMD_REQUEST | + FW_CMD_WRITE | + FW_VI_MAC_CMD_VIID(viid)); + cmd.freemacs_to_len16 = cpu_to_be32(FW_CMD_LEN16(len16)); + p->valid_to_idx = cpu_to_be16(FW_VI_MAC_CMD_VALID | + FW_VI_MAC_CMD_IDX(idx)); + memcpy(p->macaddr, addr, sizeof(p->macaddr)); + + ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); + if (ret == 0) { + p = &rpl.u.exact[0]; + ret = FW_VI_MAC_CMD_IDX_GET(be16_to_cpu(p->valid_to_idx)); + if (ret >= FW_CLS_TCAM_NUM_ENTRIES) + ret = -ENOMEM; + } + return ret; +} + +/** + * t4vf_set_addr_hash - program the MAC inexact-match hash filter + * @adapter: the adapter + * @viid: the Virtual Interface Identifier + * @ucast: whether the hash filter should also match unicast addresses + * @vec: the value to be written to the hash filter + * @sleep_ok: call is allowed to sleep + * + * Sets the 64-bit inexact-match hash filter for a virtual interface. + */ +int t4vf_set_addr_hash(struct adapter *adapter, unsigned int viid, + bool ucast, u64 vec, bool sleep_ok) +{ + struct fw_vi_mac_cmd cmd; + size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd, + u.exact[0]), 16); + + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) | + FW_CMD_REQUEST | + FW_CMD_WRITE | + FW_VI_ENABLE_CMD_VIID(viid)); + cmd.freemacs_to_len16 = cpu_to_be32(FW_VI_MAC_CMD_HASHVECEN | + FW_VI_MAC_CMD_HASHUNIEN(ucast) | + FW_CMD_LEN16(len16)); + cmd.u.hash.hashvec = cpu_to_be64(vec); + return t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), NULL, sleep_ok); +} + +/** + * t4vf_get_port_stats - collect "port" statistics + * @adapter: the adapter + * @pidx: the port index + * @s: the stats structure to fill + * + * Collect statistics for the "port"'s Virtual Interface. + */ +int t4vf_get_port_stats(struct adapter *adapter, int pidx, + struct t4vf_port_stats *s) +{ + struct port_info *pi = adap2pinfo(adapter, pidx); + struct fw_vi_stats_vf fwstats; + unsigned int rem = VI_VF_NUM_STATS; + __be64 *fwsp = (__be64 *)&fwstats; + + /* + * Grab the Virtual Interface statistics a chunk at a time via mailbox + * commands. We could use a Work Request and get all of them at once + * but that's an asynchronous interface which is awkward to use. + */ + while (rem) { + unsigned int ix = VI_VF_NUM_STATS - rem; + unsigned int nstats = min(6U, rem); + struct fw_vi_stats_cmd cmd, rpl; + size_t len = (offsetof(struct fw_vi_stats_cmd, u) + + sizeof(struct fw_vi_stats_ctl)); + size_t len16 = DIV_ROUND_UP(len, 16); + int ret; + + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_STATS_CMD) | + FW_VI_STATS_CMD_VIID(pi->viid) | + FW_CMD_REQUEST | + FW_CMD_READ); + cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16(len16)); + cmd.u.ctl.nstats_ix = + cpu_to_be16(FW_VI_STATS_CMD_IX(ix) | + FW_VI_STATS_CMD_NSTATS(nstats)); + ret = t4vf_wr_mbox_ns(adapter, &cmd, len, &rpl); + if (ret) + return ret; + + memcpy(fwsp, &rpl.u.ctl.stat0, sizeof(__be64) * nstats); + + rem -= nstats; + fwsp += nstats; + } + + /* + * Translate firmware statistics into host native statistics. + */ + s->tx_bcast_bytes = be64_to_cpu(fwstats.tx_bcast_bytes); + s->tx_bcast_frames = be64_to_cpu(fwstats.tx_bcast_frames); + s->tx_mcast_bytes = be64_to_cpu(fwstats.tx_mcast_bytes); + s->tx_mcast_frames = be64_to_cpu(fwstats.tx_mcast_frames); + s->tx_ucast_bytes = be64_to_cpu(fwstats.tx_ucast_bytes); + s->tx_ucast_frames = be64_to_cpu(fwstats.tx_ucast_frames); + s->tx_drop_frames = be64_to_cpu(fwstats.tx_drop_frames); + s->tx_offload_bytes = be64_to_cpu(fwstats.tx_offload_bytes); + s->tx_offload_frames = be64_to_cpu(fwstats.tx_offload_frames); + + s->rx_bcast_bytes = be64_to_cpu(fwstats.rx_bcast_bytes); + s->rx_bcast_frames = be64_to_cpu(fwstats.rx_bcast_frames); + s->rx_mcast_bytes = be64_to_cpu(fwstats.rx_mcast_bytes); + s->rx_mcast_frames = be64_to_cpu(fwstats.rx_mcast_frames); + s->rx_ucast_bytes = be64_to_cpu(fwstats.rx_ucast_bytes); + s->rx_ucast_frames = be64_to_cpu(fwstats.rx_ucast_frames); + + s->rx_err_frames = be64_to_cpu(fwstats.rx_err_frames); + + return 0; +} + +/** + * t4vf_iq_free - free an ingress queue and its free lists + * @adapter: the adapter + * @iqtype: the ingress queue type (FW_IQ_TYPE_FL_INT_CAP, etc.) + * @iqid: ingress queue ID + * @fl0id: FL0 queue ID or 0xffff if no attached FL0 + * @fl1id: FL1 queue ID or 0xffff if no attached FL1 + * + * Frees an ingress queue and its associated free lists, if any. + */ +int t4vf_iq_free(struct adapter *adapter, unsigned int iqtype, + unsigned int iqid, unsigned int fl0id, unsigned int fl1id) +{ + struct fw_iq_cmd cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_IQ_CMD) | + FW_CMD_REQUEST | + FW_CMD_EXEC); + cmd.alloc_to_len16 = cpu_to_be32(FW_IQ_CMD_FREE | + FW_LEN16(cmd)); + cmd.type_to_iqandstindex = + cpu_to_be32(FW_IQ_CMD_TYPE(iqtype)); + + cmd.iqid = cpu_to_be16(iqid); + cmd.fl0id = cpu_to_be16(fl0id); + cmd.fl1id = cpu_to_be16(fl1id); + return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL); +} + +/** + * t4vf_eth_eq_free - free an Ethernet egress queue + * @adapter: the adapter + * @eqid: egress queue ID + * + * Frees an Ethernet egress queue. + */ +int t4vf_eth_eq_free(struct adapter *adapter, unsigned int eqid) +{ + struct fw_eq_eth_cmd cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_EQ_ETH_CMD) | + FW_CMD_REQUEST | + FW_CMD_EXEC); + cmd.alloc_to_len16 = cpu_to_be32(FW_EQ_ETH_CMD_FREE | + FW_LEN16(cmd)); + cmd.eqid_pkd = cpu_to_be32(FW_EQ_ETH_CMD_EQID(eqid)); + return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL); +} + +/** + * t4vf_handle_fw_rpl - process a firmware reply message + * @adapter: the adapter + * @rpl: start of the firmware message + * + * Processes a firmware message, such as link state change messages. + */ +int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl) +{ + const struct fw_cmd_hdr *cmd_hdr = (const struct fw_cmd_hdr *)rpl; + u8 opcode = FW_CMD_OP_GET(be32_to_cpu(cmd_hdr->hi)); + + switch (opcode) { + case FW_PORT_CMD: { + /* + * Link/module state change message. + */ + const struct fw_port_cmd *port_cmd = + (const struct fw_port_cmd *)rpl; + u32 word; + int action, port_id, link_ok, speed, fc, pidx; + + /* + * Extract various fields from port status change message. + */ + action = FW_PORT_CMD_ACTION_GET( + be32_to_cpu(port_cmd->action_to_len16)); + if (action != FW_PORT_ACTION_GET_PORT_INFO) { + dev_err(adapter->pdev_dev, + "Unknown firmware PORT reply action %x\n", + action); + break; + } + + port_id = FW_PORT_CMD_PORTID_GET( + be32_to_cpu(port_cmd->op_to_portid)); + + word = be32_to_cpu(port_cmd->u.info.lstatus_to_modtype); + link_ok = (word & FW_PORT_CMD_LSTATUS) != 0; + speed = 0; + fc = 0; + if (word & FW_PORT_CMD_RXPAUSE) + fc |= PAUSE_RX; + if (word & FW_PORT_CMD_TXPAUSE) + fc |= PAUSE_TX; + if (word & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100M)) + speed = SPEED_100; + else if (word & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_1G)) + speed = SPEED_1000; + else if (word & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_10G)) + speed = SPEED_10000; + + /* + * Scan all of our "ports" (Virtual Interfaces) looking for + * those bound to the physical port which has changed. If + * our recorded state doesn't match the current state, + * signal that change to the OS code. + */ + for_each_port(adapter, pidx) { + struct port_info *pi = adap2pinfo(adapter, pidx); + struct link_config *lc; + + if (pi->port_id != port_id) + continue; + + lc = &pi->link_cfg; + if (link_ok != lc->link_ok || speed != lc->speed || + fc != lc->fc) { + /* something changed */ + lc->link_ok = link_ok; + lc->speed = speed; + lc->fc = fc; + t4vf_os_link_changed(adapter, pidx, link_ok); + } + } + break; + } + + default: + dev_err(adapter->pdev_dev, "Unknown firmware reply %X\n", + opcode); + } + return 0; +} diff --git a/drivers/scsi/cxgbi/cxgb3i/Kbuild b/drivers/scsi/cxgbi/cxgb3i/Kbuild index 09dbf9efc8ea..6f095e28a974 100644 --- a/drivers/scsi/cxgbi/cxgb3i/Kbuild +++ b/drivers/scsi/cxgbi/cxgb3i/Kbuild @@ -1,3 +1,3 @@ -EXTRA_CFLAGS += -I$(srctree)/drivers/net/cxgb3 +EXTRA_CFLAGS += -I$(srctree)/drivers/net/ethernet/chelsio/cxgb3 obj-$(CONFIG_SCSI_CXGB3_ISCSI) += cxgb3i.o diff --git a/drivers/scsi/cxgbi/cxgb4i/Kbuild b/drivers/scsi/cxgbi/cxgb4i/Kbuild index b9f4af7454b7..8290cdaa4652 100644 --- a/drivers/scsi/cxgbi/cxgb4i/Kbuild +++ b/drivers/scsi/cxgbi/cxgb4i/Kbuild @@ -1,3 +1,3 @@ -EXTRA_CFLAGS += -I$(srctree)/drivers/net/cxgb4 +EXTRA_CFLAGS += -I$(srctree)/drivers/net/ethernet/chelsio/cxgb4 obj-$(CONFIG_SCSI_CXGB4_ISCSI) += cxgb4i.o -- cgit v1.2.3-59-g8ed1b