Date: Fri, 16 Dec 2011 02:09:52 +0000 (UTC) From: Navdeep Parhar <np@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r228561 - in head: share/man/man4 sys/dev/cxgbe sys/dev/cxgbe/common sys/dev/cxgbe/firmware sys/modules/cxgbe sys/modules/cxgbe/firmware tools/tools/cxgbetool Message-ID: <201112160209.pBG29q5h080761@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: np Date: Fri Dec 16 02:09:51 2011 New Revision: 228561 URL: http://svn.freebsd.org/changeset/base/228561 Log: Many updates to cxgbe(4) - Device configuration via plain text config file. Also able to operate when not attached to the chip as the master driver. - Generic "work request" queue that serves as the base for both ctrl and ofld tx queues. - Generic interrupt handler routine that can process any event on any kind of ingress queue (via a dispatch table). - A couple of new driver ioctls. cxgbetool can now install a firmware to the card ("loadfw" command) and can read the card's memory ("memdump" and "tcb" commands). - Lots of assorted information within dev.t4nex.X.misc.* This is primarily for debugging and won't show up in sysctl -a. - Code to manage the L2 tables on the chip. - Updates to cxgbe(4) man page to go with the tunables that have changed. - Updates to the shared code in common/ - Updates to the driver-firmware interface (now at fw 1.4.16.0) MFC after: 1 month Added: head/sys/dev/cxgbe/firmware/ head/sys/dev/cxgbe/firmware/t4fw_cfg.txt (contents, props changed) head/sys/dev/cxgbe/firmware/t4fw_cfg_uwire.txt (contents, props changed) head/sys/dev/cxgbe/firmware/t4fw_interface.h - copied, changed from r228535, head/sys/dev/cxgbe/common/t4fw_interface.h head/sys/modules/cxgbe/firmware/ head/sys/modules/cxgbe/firmware/Makefile (contents, props changed) Deleted: head/sys/dev/cxgbe/common/t4fw_interface.h Modified: head/share/man/man4/cxgbe.4 head/sys/dev/cxgbe/adapter.h head/sys/dev/cxgbe/common/common.h head/sys/dev/cxgbe/common/t4_hw.c head/sys/dev/cxgbe/common/t4_hw.h head/sys/dev/cxgbe/offload.h head/sys/dev/cxgbe/osdep.h head/sys/dev/cxgbe/t4_ioctl.h head/sys/dev/cxgbe/t4_l2t.c head/sys/dev/cxgbe/t4_l2t.h head/sys/dev/cxgbe/t4_main.c head/sys/dev/cxgbe/t4_sge.c head/sys/modules/cxgbe/Makefile head/tools/tools/cxgbetool/cxgbetool.c Modified: head/share/man/man4/cxgbe.4 ============================================================================== --- head/share/man/man4/cxgbe.4 Fri Dec 16 00:58:41 2011 (r228560) +++ head/share/man/man4/cxgbe.4 Fri Dec 16 02:09:51 2011 (r228561) @@ -99,18 +99,29 @@ Tunables can be set at the prompt before booting the kernel or stored in .Xr loader.conf 5 . .Bl -tag -width indent -.It Va hw.cxgbe.max_ntxq_10G_port -The maximum number of tx queues to use for a 10Gb port. -The default value is 8. -.It Va hw.cxgbe.max_nrxq_10G_port -The maximum number of rx queues to use for a 10Gb port. -The default value is 8. -.It Va hw.cxgbe.max_ntxq_1G_port -The maximum number of tx queues to use for a 1Gb port. -The default value is 2. -.It Va hw.cxgbe.max_nrxq_1G_port -The maximum number of rx queues to use for a 1Gb port. -The default value is 2. +.It Va hw.cxgbe.ntxq10g +The number of tx queues to use for a 10Gb port. The default is 16 or the number +of CPU cores in the system, whichever is less. +.It Va hw.cxgbe.nrxq10g +The number of rx queues to use for a 10Gb port. The default is 8 or the number +of CPU cores in the system, whichever is less. +.It Va hw.cxgbe.ntxq1g +The number of tx queues to use for a 1Gb port. The default is 4 or the number +of CPU cores in the system, whichever is less. +.It Va hw.cxgbe.nrxq1g +The number of rx queues to use for a 1Gb port. The default is 2 or the number +of CPU cores in the system, whichever is less. +.It Va hw.cxgbe.nofldtxq10g +The number of TOE tx queues to use for a 10Gb port. The default is 8 or the +number of CPU cores in the system, whichever is less. +.It Va hw.cxgbe.nofldrxq10g +The number of TOE rx queues to use for a 10Gb port. The default is 2 or the +number of CPU cores in the system, whichever is less. +.It Va hw.cxgbe.nofldtxq1g +The number of TOE tx queues to use for a 1Gb port. The default is 2 or the +number of CPU cores in the system, whichever is less. +.It Va hw.cxgbe.nofldrxq1g +The number of TOE rx queues to use for a 1Gb port. The default is 1. .It Va hw.cxgbe.holdoff_timer_idx_10G .It Va hw.cxgbe.holdoff_timer_idx_1G The timer index value to use to delay interrupts. @@ -119,6 +130,8 @@ by default (all values are in microsecon value from this list. The default value is 1 for both 10Gb and 1Gb ports, which means the timer value is 5us. +Different cxgbe interfaces can be assigned different values at any time via the +dev.cxgbe.X.holdoff_tmr_idx sysctl. .It Va hw.cxgbe.holdoff_pktc_idx_10G .It Va hw.cxgbe.holdoff_pktc_idx_1G The packet-count index value to use to delay interrupts. @@ -127,6 +140,11 @@ and the index selects a value from this The default value is 2 for both 10Gb and 1Gb ports, which means 16 packets (or the holdoff timer going off) before an interrupt is generated. +-1 disables packet counting. +Different cxgbe interfaces can be assigned different values via the +dev.cxgbe.X.holdoff_pktc_idx sysctl. +This sysctl works only when the interface has never been marked up (as done by +ifconfig up). .It Va hw.cxgbe.qsize_txq The size, in number of entries, of the descriptor ring used for a tx queue. @@ -134,10 +152,46 @@ A buf_ring of the same size is also allo software queuing. See .Xr ifnet 9 . The default value is 1024. +Different cxgbe interfaces can be assigned different values via the +dev.cxgbe.X.qsize_txq sysctl. +This sysctl works only when the interface has never been marked up (as done by +ifconfig up). .It Va hw.cxgbe.qsize_rxq The size, in number of entries, of the descriptor ring used for an rx queue. The default value is 1024. +Different cxgbe interfaces can be assigned different values via the +dev.cxgbe.X.qsize_rxq sysctl. +This sysctl works only when the interface has never been marked up (as done by +ifconfig up). +.It Va hw.cxgbe.interrupt_types +The interrupt types that the driver is allowed to use. +Bit 0 represents INTx (line interrupts), bit 1 MSI, bit 2 MSI-X. +The default is 7 (all allowed). +The driver will select the best possible type out of the allowed types by +itself. +.It Va hw.cxgbe.config_file +Select a pre-packaged device configuration file. +A configuration file contains a recipe for partitioning and configuring the +hardware resources on the card. +This tunable is for specialized applications only and should not be used in +normal operation. +The configuration profile currently in use is available in the dev.t4nex.X.cf +and dev.t4nex.X.cfcsum sysctls. +.It Va hw.cxgbe.linkcaps_allowed +.It Va hw.cxgbe.niccaps_allowed +.It Va hw.cxgbe.toecaps_allowed +.It Va hw.cxgbe.rdmacaps_allowed +.It Va hw.cxgbe.iscsicaps_allowed +.It Va hw.cxgbe.fcoecaps_allowed +Disallowing capabilities provides a hint to the driver and firmware to not +reserve hardware resources for that feature. +Each of these is a bit field with a bit for each sub-capability within the +capability. +This tunable is for specialized applications only and should not be used in +normal operation. +The capabilities for which hardware resources have been reserved are listed in +dev.t4nex.X.*caps sysctls. .El .Sh SUPPORT For general information and support, Modified: head/sys/dev/cxgbe/adapter.h ============================================================================== --- head/sys/dev/cxgbe/adapter.h Fri Dec 16 00:58:41 2011 (r228560) +++ head/sys/dev/cxgbe/adapter.h Fri Dec 16 02:09:51 2011 (r228561) @@ -31,6 +31,7 @@ #ifndef __T4_ADAPTER_H__ #define __T4_ADAPTER_H__ +#include <sys/kernel.h> #include <sys/bus.h> #include <sys/rman.h> #include <sys/types.h> @@ -46,8 +47,9 @@ #include <netinet/tcp_lro.h> #include "offload.h" -#include "common/t4fw_interface.h" +#include "firmware/t4fw_interface.h" +#define T4_CFGNAME "t4fw_cfg" #define T4_FWNAME "t4fw" MALLOC_DECLARE(M_CXGBE); @@ -110,25 +112,21 @@ enum { FW_IQ_QSIZE = 256, FW_IQ_ESIZE = 64, /* At least 64 mandated by the firmware spec */ - INTR_IQ_QSIZE = 64, - INTR_IQ_ESIZE = 64, /* Handles some CPLs too, do not reduce */ - - CTRL_EQ_QSIZE = 128, - CTRL_EQ_ESIZE = 64, - RX_IQ_QSIZE = 1024, RX_IQ_ESIZE = 64, /* At least 64 so CPL_RX_PKT will fit */ - RX_FL_ESIZE = 64, /* 8 64bit addresses */ + EQ_ESIZE = 64, /* All egress queues use this entry size */ + RX_FL_ESIZE = EQ_ESIZE, /* 8 64bit addresses */ #if MJUMPAGESIZE != MCLBYTES FL_BUF_SIZES = 4, /* cluster, jumbop, jumbo9k, jumbo16k */ #else FL_BUF_SIZES = 3, /* cluster, jumbo9k, jumbo16k */ #endif + CTRL_EQ_QSIZE = 128, + TX_EQ_QSIZE = 1024, - TX_EQ_ESIZE = 64, TX_SGL_SEGS = 36, TX_WR_FLITS = SGE_MAX_WR_LEN / 8 }; @@ -144,13 +142,16 @@ enum { /* adapter flags */ FULL_INIT_DONE = (1 << 0), FW_OK = (1 << 1), - INTR_SHARED = (1 << 2), /* one set of intrq's for all ports */ + INTR_DIRECT = (1 << 2), /* direct interrupts for everything */ + MASTER_PF = (1 << 3), + ADAP_SYSCTL_CTX = (1 << 4), CXGBE_BUSY = (1 << 9), /* port flags */ DOOMED = (1 << 0), - VI_ENABLED = (1 << 1), + PORT_INIT_DONE = (1 << 1), + PORT_SYSCTL_CTX = (1 << 2), }; #define IS_DOOMED(pi) (pi->flags & DOOMED) @@ -186,6 +187,12 @@ struct port_info { int first_txq; /* index of first tx queue */ int nrxq; /* # of rx queues */ int first_rxq; /* index of first rx queue */ +#ifndef TCP_OFFLOAD_DISABLE + int nofldtxq; /* # of offload tx queues */ + int first_ofld_txq; /* index of first offload tx queue */ + int nofldrxq; /* # of offload rx queues */ + int first_ofld_rxq; /* index of first offload rx queue */ +#endif int tmr_idx; int pktc_idx; int qsize_rxq; @@ -194,11 +201,8 @@ struct port_info { struct link_config link_cfg; struct port_stats stats; - struct taskqueue *tq; struct callout tick; - struct sysctl_ctx_list ctx; /* lives from ifconfig up to down */ - struct sysctl_oid *oid_rxq; - struct sysctl_oid *oid_txq; + struct sysctl_ctx_list ctx; /* from ifconfig up to driver detach */ uint8_t hw_addr[ETHER_ADDR_LEN]; /* factory MAC address, won't change */ }; @@ -222,17 +226,26 @@ struct tx_map { bus_dmamap_t map; }; +/* DMA maps used for tx */ +struct tx_maps { + struct tx_map *maps; + uint32_t map_total; /* # of DMA maps */ + uint32_t map_pidx; /* next map to be used */ + uint32_t map_cidx; /* reclaimed up to this index */ + uint32_t map_avail; /* # of available maps */ +}; + struct tx_sdesc { uint8_t desc_used; /* # of hardware descriptors used by the WR */ uint8_t credits; /* NIC txq: # of frames sent out in the WR */ }; -typedef void (iq_intr_handler_t)(void *); - enum { /* iq flags */ - IQ_ALLOCATED = (1 << 1), /* firmware resources allocated */ - IQ_STARTED = (1 << 2), /* started */ + IQ_ALLOCATED = (1 << 0), /* firmware resources allocated */ + IQ_HAS_FL = (1 << 1), /* iq associated with a freelist */ + IQ_INTR = (1 << 2), /* iq takes direct interrupt */ + IQ_LRO_ENABLED = (1 << 3), /* iq is an eth rxq with LRO enabled */ /* iq state */ IQS_DISABLED = 0, @@ -252,26 +265,35 @@ struct sge_iq { uint16_t abs_id; /* absolute SGE id for the iq */ int8_t intr_pktc_idx; /* packet count threshold index */ int8_t pad0; - iq_intr_handler_t *handler; __be64 *desc; /* KVA of descriptor ring */ - volatile uint32_t state; + volatile int state; struct adapter *adapter; const __be64 *cdesc; /* current descriptor */ uint8_t gen; /* generation bit */ uint8_t intr_params; /* interrupt holdoff parameters */ - uint8_t intr_next; /* holdoff for next interrupt */ + uint8_t intr_next; /* XXX: holdoff for next interrupt */ uint8_t esize; /* size (bytes) of each entry in the queue */ uint16_t qsize; /* size (# of entries) of the queue */ uint16_t cidx; /* consumer index */ - uint16_t cntxt_id; /* SGE context id for the iq */ + uint16_t cntxt_id; /* SGE context id for the iq */ + + STAILQ_ENTRY(sge_iq) link; }; enum { + EQ_CTRL = 1, + EQ_ETH = 2, +#ifndef TCP_OFFLOAD_DISABLE + EQ_OFLD = 3, +#endif + /* eq flags */ - EQ_ALLOCATED = (1 << 1), /* firmware resources allocated */ - EQ_STARTED = (1 << 2), /* started */ - EQ_CRFLUSHED = (1 << 3), /* expecting an update from SGE */ + EQ_TYPEMASK = 7, /* 3 lsbits hold the type */ + EQ_ALLOCATED = (1 << 3), /* firmware resources allocated */ + EQ_DOOMED = (1 << 4), /* about to be destroyed */ + EQ_CRFLUSHED = (1 << 5), /* expecting an update from SGE */ + EQ_STALLED = (1 << 6), /* out of hw descriptors or dmamaps */ }; /* @@ -281,10 +303,11 @@ enum { * consumes them) but it's special enough to have its own struct (see sge_fl). */ struct sge_eq { + unsigned int flags; /* MUST be first */ + unsigned int cntxt_id; /* SGE context id for the eq */ bus_dma_tag_t desc_tag; bus_dmamap_t desc_map; char lockname[16]; - unsigned int flags; struct mtx eq_lock; struct tx_desc *desc; /* KVA of descriptor ring */ @@ -297,9 +320,24 @@ struct sge_eq { uint16_t pidx; /* producer idx (desc idx) */ uint16_t pending; /* # of descriptors used since last doorbell */ uint16_t iqid; /* iq that gets egr_update for the eq */ - unsigned int cntxt_id; /* SGE context id for the eq */ + uint8_t tx_chan; /* tx channel used by the eq */ + struct task tx_task; + struct callout tx_callout; + + /* stats */ + + uint32_t egr_update; /* # of SGE_EGR_UPDATE notifications for eq */ + uint32_t unstalled; /* recovered from stall */ +}; + +enum { + FL_STARVING = (1 << 0), /* on the adapter's list of starving fl's */ + FL_DOOMED = (1 << 1), /* about to be destroyed */ }; +#define FL_RUNNING_LOW(fl) (fl->cap - fl->needed <= fl->lowat) +#define FL_NOT_RUNNING_LOW(fl) (fl->cap - fl->needed >= 2 * fl->lowat) + struct sge_fl { bus_dma_tag_t desc_tag; bus_dmamap_t desc_map; @@ -307,6 +345,7 @@ struct sge_fl { uint8_t tag_idx; struct mtx fl_lock; char lockname[16]; + int flags; __be64 *desc; /* KVA of descriptor ring, ptr to addresses */ bus_addr_t ba; /* bus address of descriptor ring */ @@ -317,8 +356,10 @@ struct sge_fl { uint32_t cidx; /* consumer idx (buffer idx, NOT hw desc idx) */ uint32_t pidx; /* producer idx (buffer idx, NOT hw desc idx) */ uint32_t needed; /* # of buffers needed to fill up fl. */ + uint32_t lowat; /* # of buffers <= this means fl needs help */ uint32_t pending; /* # of bufs allocated since last doorbell */ unsigned int dmamap_failed; + TAILQ_ENTRY(sge_fl) link; /* All starving freelists */ }; /* txq: SGE egress queue + what's needed for Ethernet NIC */ @@ -330,14 +371,8 @@ struct sge_txq { struct buf_ring *br; /* tx buffer ring */ struct tx_sdesc *sdesc; /* KVA of software descriptor ring */ struct mbuf *m; /* held up due to temporary resource shortage */ - struct task resume_tx; - /* DMA maps used for tx */ - struct tx_map *maps; - uint32_t map_total; /* # of DMA maps */ - uint32_t map_pidx; /* next map to be used */ - uint32_t map_cidx; /* reclaimed up to this index */ - uint32_t map_avail; /* # of available maps */ + struct tx_maps txmaps; /* stats for common events first */ @@ -354,20 +389,14 @@ struct sge_txq { uint32_t no_dmamap; /* no DMA map to load the mbuf */ uint32_t no_desc; /* out of hardware descriptors */ - uint32_t egr_update; /* # of SGE_EGR_UPDATE notifications for txq */ } __aligned(CACHE_LINE_SIZE); -enum { - RXQ_LRO_ENABLED = (1 << 0) -}; - /* rxq: SGE ingress queue + SGE free list + miscellaneous items */ struct sge_rxq { struct sge_iq iq; /* MUST be first */ - struct sge_fl fl; + struct sge_fl fl; /* MUST follow iq */ struct ifnet *ifp; /* the interface this rxq belongs to */ - unsigned int flags; #ifdef INET struct lro_ctrl lro; /* LRO state */ #endif @@ -381,12 +410,28 @@ struct sge_rxq { } __aligned(CACHE_LINE_SIZE); -/* ctrlq: SGE egress queue + stats for control queue */ -struct sge_ctrlq { +#ifndef TCP_OFFLOAD_DISABLE +/* ofld_rxq: SGE ingress queue + SGE free list + miscellaneous items */ +struct sge_ofld_rxq { + struct sge_iq iq; /* MUST be first */ + struct sge_fl fl; /* MUST follow iq */ +} __aligned(CACHE_LINE_SIZE); +#endif + +/* + * wrq: SGE egress queue that is given prebuilt work requests. Both the control + * and offload tx queues are of this type. + */ +struct sge_wrq { struct sge_eq eq; /* MUST be first */ + struct adapter *adapter; + struct mbuf *head; /* held up due to lack of descriptors */ + struct mbuf *tail; /* valid only if head is valid */ + /* stats for common events first */ + uint64_t tx_wrs; /* # of tx work requests */ /* stats for not-that-common events */ @@ -394,20 +439,28 @@ struct sge_ctrlq { } __aligned(CACHE_LINE_SIZE); struct sge { - uint16_t timer_val[SGE_NTIMERS]; - uint8_t counter_val[SGE_NCOUNTERS]; + int timer_val[SGE_NTIMERS]; + int counter_val[SGE_NCOUNTERS]; int fl_starve_threshold; - int nrxq; /* total rx queues (all ports and the rest) */ - int ntxq; /* total tx queues (all ports and the rest) */ - int niq; /* total ingress queues */ - int neq; /* total egress queues */ + int nrxq; /* total # of Ethernet rx queues */ + int ntxq; /* total # of Ethernet tx tx queues */ +#ifndef TCP_OFFLOAD_DISABLE + int nofldrxq; /* total # of TOE rx queues */ + int nofldtxq; /* total # of TOE tx queues */ +#endif + int niq; /* total # of ingress queues */ + int neq; /* total # of egress queues */ struct sge_iq fwq; /* Firmware event queue */ - struct sge_ctrlq *ctrlq;/* Control queues */ - struct sge_iq *intrq; /* Interrupt queues */ + struct sge_wrq mgmtq; /* Management queue (control queue) */ + struct sge_wrq *ctrlq; /* Control queues */ struct sge_txq *txq; /* NIC tx queues */ struct sge_rxq *rxq; /* NIC rx queues */ +#ifndef TCP_OFFLOAD_DISABLE + struct sge_wrq *ofld_txq; /* TOE tx queues */ + struct sge_ofld_rxq *ofld_rxq; /* TOE rx queues */ +#endif uint16_t iq_start; int eq_start; @@ -415,7 +468,12 @@ struct sge { struct sge_eq **eqmap; /* eq->cntxt_id to eq mapping */ }; +struct rss_header; +typedef int (*cpl_handler_t)(struct sge_iq *, const struct rss_header *, + struct mbuf *); + struct adapter { + SLIST_ENTRY(adapter) link; device_t dev; struct cdev *cdev; @@ -444,27 +502,47 @@ struct adapter { struct sge sge; + struct taskqueue *tq[NCHAN]; /* taskqueues that flush data out */ struct port_info *port[MAX_NPORTS]; uint8_t chan_map[NCHAN]; + uint32_t filter_mode; +#ifndef TCP_OFFLOAD_DISABLE + struct uld_softc tom; + struct tom_tunables tt; +#endif struct l2t_data *l2t; /* L2 table */ struct tid_info tids; - int registered_device_map; int open_device_map; +#ifndef TCP_OFFLOAD_DISABLE + int offload_map; +#endif int flags; char fw_version[32]; + unsigned int cfcsum; struct adapter_params params; struct t4_virt_res vres; - struct sysctl_ctx_list ctx; /* from first_port_up to last_port_down */ - struct sysctl_oid *oid_fwq; - struct sysctl_oid *oid_ctrlq; - struct sysctl_oid *oid_intrq; + uint16_t linkcaps; + uint16_t niccaps; + uint16_t toecaps; + uint16_t rdmacaps; + uint16_t iscsicaps; + uint16_t fcoecaps; + + struct sysctl_ctx_list ctx; /* from adapter_full_init to full_uninit */ struct mtx sc_lock; char lockname[16]; + + /* Starving free lists */ + struct mtx sfl_lock; /* same cache-line as sc_lock? but that's ok */ + TAILQ_HEAD(, sge_fl) sfl; + struct callout sfl_callout; + + cpl_handler_t cpl_handler[256] __aligned(CACHE_LINE_SIZE); }; #define ADAPTER_LOCK(sc) mtx_lock(&(sc)->sc_lock) @@ -506,11 +584,15 @@ struct adapter { #define for_each_rxq(pi, iter, rxq) \ rxq = &pi->adapter->sge.rxq[pi->first_rxq]; \ for (iter = 0; iter < pi->nrxq; ++iter, ++rxq) +#define for_each_ofld_txq(pi, iter, ofld_txq) \ + ofld_txq = &pi->adapter->sge.ofld_txq[pi->first_ofld_txq]; \ + for (iter = 0; iter < pi->nofldtxq; ++iter, ++ofld_txq) +#define for_each_ofld_rxq(pi, iter, ofld_rxq) \ + ofld_rxq = &pi->adapter->sge.ofld_rxq[pi->first_ofld_rxq]; \ + for (iter = 0; iter < pi->nofldrxq; ++iter, ++ofld_rxq) /* One for errors, one for firmware events */ #define T4_EXTRA_INTR 2 -#define NINTRQ(sc) ((sc)->intr_count > T4_EXTRA_INTR ? \ - (sc)->intr_count - T4_EXTRA_INTR : 1) static inline uint32_t t4_read_reg(struct adapter *sc, uint32_t reg) @@ -589,29 +671,52 @@ static inline bool is_10G_port(const str return ((pi->link_cfg.supported & FW_PORT_CAP_SPEED_10G) != 0); } +static inline int tx_resume_threshold(struct sge_eq *eq) +{ + return (eq->qsize / 4); +} + /* t4_main.c */ -void cxgbe_txq_start(void *, int); +void t4_tx_task(void *, int); +void t4_tx_callout(void *); int t4_os_find_pci_capability(struct adapter *, int); int t4_os_pci_save_state(struct adapter *); int t4_os_pci_restore_state(struct adapter *); void t4_os_portmod_changed(const struct adapter *, int); void t4_os_link_changed(struct adapter *, int, int); +void t4_iterate(void (*)(struct adapter *, void *), void *); +int t4_register_cpl_handler(struct adapter *, int, cpl_handler_t); /* t4_sge.c */ void t4_sge_modload(void); -void t4_sge_init(struct adapter *); +int t4_sge_init(struct adapter *); int t4_create_dma_tag(struct adapter *); int t4_destroy_dma_tag(struct adapter *); int t4_setup_adapter_queues(struct adapter *); int t4_teardown_adapter_queues(struct adapter *); -int t4_setup_eth_queues(struct port_info *); -int t4_teardown_eth_queues(struct port_info *); +int t4_setup_port_queues(struct port_info *); +int t4_teardown_port_queues(struct port_info *); +int t4_alloc_tx_maps(struct tx_maps *, bus_dma_tag_t, int, int); +void t4_free_tx_maps(struct tx_maps *, bus_dma_tag_t); void t4_intr_all(void *); void t4_intr(void *); void t4_intr_err(void *); void t4_intr_evt(void *); int t4_mgmt_tx(struct adapter *, struct mbuf *); +int t4_wrq_tx_locked(struct adapter *, struct sge_wrq *, struct mbuf *); int t4_eth_tx(struct ifnet *, struct sge_txq *, struct mbuf *); void t4_update_fl_bufsize(struct ifnet *); +int can_resume_tx(struct sge_eq *); + +static inline int t4_wrq_tx(struct adapter *sc, struct sge_wrq *wrq, struct mbuf *m) +{ + int rc; + + TXQ_LOCK(wrq); + rc = t4_wrq_tx_locked(sc, wrq, m); + TXQ_UNLOCK(wrq); + return (rc); +} + #endif Modified: head/sys/dev/cxgbe/common/common.h ============================================================================== --- head/sys/dev/cxgbe/common/common.h Fri Dec 16 00:58:41 2011 (r228560) +++ head/sys/dev/cxgbe/common/common.h Fri Dec 16 02:09:51 2011 (r228561) @@ -42,6 +42,15 @@ enum { enum { MEM_EDC0, MEM_EDC1, MEM_MC }; +enum { + MEMWIN0_APERTURE = 2048, + MEMWIN0_BASE = 0x1b800, + MEMWIN1_APERTURE = 32768, + MEMWIN1_BASE = 0x28000, + MEMWIN2_APERTURE = 65536, + MEMWIN2_BASE = 0x30000, +}; + enum dev_master { MASTER_CANT, MASTER_MAY, MASTER_MUST }; enum dev_state { DEV_STATE_UNINIT, DEV_STATE_INIT, DEV_STATE_ERR }; @@ -53,8 +62,8 @@ enum { }; #define FW_VERSION_MAJOR 1 -#define FW_VERSION_MINOR 3 -#define FW_VERSION_MICRO 10 +#define FW_VERSION_MINOR 4 +#define FW_VERSION_MICRO 16 struct port_stats { u64 tx_octets; /* total # of octets in good frames */ @@ -190,7 +199,6 @@ struct tp_proxy_stats { struct tp_cpl_stats { u32 req[4]; u32 rsp[4]; - u32 tx_err[4]; }; struct tp_rdma_stats { @@ -214,9 +222,9 @@ struct vpd_params { }; struct pci_params { - unsigned int vpd_cap_addr; - unsigned char speed; - unsigned char width; + unsigned int vpd_cap_addr; + unsigned short speed; + unsigned short width; }; /* @@ -239,20 +247,20 @@ struct adapter_params { 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 int mc_size; /* MC memory size */ - unsigned int nfilters; /* size of filter region */ + unsigned int mc_size; /* MC memory size */ + unsigned int nfilters; /* size of filter region */ unsigned int cim_la_size; - unsigned int nports; /* # of ethernet ports */ + /* Used as int in sysctls, do not reduce size */ + unsigned int nports; /* # of ethernet ports */ unsigned int portvec; - unsigned int rev; /* chip revision */ + unsigned int rev; /* chip revision */ unsigned int offload; unsigned int ofldq_wr_cred; @@ -366,6 +374,9 @@ int t4_seeprom_wp(struct adapter *adapte int t4_read_flash(struct adapter *adapter, unsigned int addr, unsigned int nwords, u32 *data, int byte_oriented); int t4_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size); +int t4_load_boot(struct adapter *adap, const u8 *boot_data, + unsigned int boot_addr, unsigned int size); +unsigned int t4_flash_cfg_addr(struct adapter *adapter); int t4_load_cfg(struct adapter *adapter, const u8 *cfg_data, unsigned int size); int t4_get_fw_version(struct adapter *adapter, u32 *vers); int t4_get_tp_version(struct adapter *adapter, u32 *vers); @@ -460,8 +471,8 @@ int t4_wol_pat_enable(struct adapter *ad 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_fw_initialize(struct adapter *adap, unsigned int mbox); int t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf, unsigned int vf, unsigned int nparams, const u32 *params, u32 *val); Modified: head/sys/dev/cxgbe/common/t4_hw.c ============================================================================== --- head/sys/dev/cxgbe/common/t4_hw.c Fri Dec 16 00:58:41 2011 (r228560) +++ head/sys/dev/cxgbe/common/t4_hw.c Fri Dec 16 02:09:51 2011 (r228561) @@ -30,10 +30,10 @@ __FBSDID("$FreeBSD$"); #include "common.h" #include "t4_regs.h" #include "t4_regs_values.h" -#include "t4fw_interface.h" +#include "firmware/t4fw_interface.h" #undef msleep -#define msleep(x) DELAY((x) * 1000) +#define msleep(x) pause("t4hw", (x) * hz / 1000) /** * t4_wait_op_done_val - wait until an operation is completed @@ -187,7 +187,7 @@ int t4_wr_mbox_meat(struct adapter *adap * off to larger delays to a maximum retry delay. */ static const int delay[] = { - 1, 1, 3, 5, 10, 10, 20, 50, 100, 200 + 1, 1, 3, 5, 10, 10, 20, 50, 100 }; u32 v; @@ -625,17 +625,6 @@ enum { SF_RD_DATA_FAST = 0xb, /* read flash */ SF_RD_ID = 0x9f, /* read ID */ SF_ERASE_SECTOR = 0xd8, /* erase sector */ - - FW_START_SEC = 8, /* first flash sector for FW */ - FW_END_SEC = 15, /* last flash sector for FW */ - FW_IMG_START = FW_START_SEC * SF_SEC_SIZE, - FW_MAX_SIZE = (FW_END_SEC - FW_START_SEC + 1) * SF_SEC_SIZE, - - FLASH_CFG_MAX_SIZE = 0x10000 , /* max size of the flash config file */ - FLASH_CFG_OFFSET = 0x1f0000, - FLASH_CFG_START_SEC = FLASH_CFG_OFFSET / SF_SEC_SIZE, - FPGA_FLASH_CFG_OFFSET = 0xf0000 , /* if FPGA mode, then cfg file is at 1MB - 64KB */ - FPGA_FLASH_CFG_START_SEC = FPGA_FLASH_CFG_OFFSET / SF_SEC_SIZE, }; /** @@ -763,12 +752,15 @@ int t4_read_flash(struct adapter *adapte * @addr: the start address to write * @n: length of data to write in bytes * @data: the data to write + * @byte_oriented: whether to store data as bytes or as words * * 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. + * If @byte_oriented is set the write data is stored as byte stream + * (i.e. matches what on disk), otherwise in big-endian. */ static int t4_write_flash(struct adapter *adapter, unsigned int addr, - unsigned int n, const u8 *data) + unsigned int n, const u8 *data, int byte_oriented) { int ret; u32 buf[SF_PAGE_SIZE / 4]; @@ -788,6 +780,9 @@ static int t4_write_flash(struct adapter for (val = 0, i = 0; i < c; ++i) val = (val << 8) + *data++; + if (!byte_oriented) + val = htonl(val); + ret = sf1_write(adapter, c, c != left, 1, val); if (ret) goto unlock; @@ -799,7 +794,8 @@ static int t4_write_flash(struct adapter t4_write_reg(adapter, A_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); + ret = t4_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf, + byte_oriented); if (ret) return ret; @@ -825,7 +821,7 @@ unlock: int t4_get_fw_version(struct adapter *adapter, u32 *vers) { return t4_read_flash(adapter, - FW_IMG_START + offsetof(struct fw_hdr, fw_ver), 1, + FLASH_FW_START + offsetof(struct fw_hdr, fw_ver), 1, vers, 0); } @@ -838,7 +834,7 @@ int t4_get_fw_version(struct adapter *ad */ int t4_get_tp_version(struct adapter *adapter, u32 *vers) { - return t4_read_flash(adapter, FW_IMG_START + offsetof(struct fw_hdr, + return t4_read_flash(adapter, FLASH_FW_START + offsetof(struct fw_hdr, tp_microcode_ver), 1, vers, 0); } @@ -854,24 +850,17 @@ int t4_get_tp_version(struct adapter *ad */ int t4_check_fw_version(struct adapter *adapter) { - u32 api_vers[2]; int ret, major, minor, micro; ret = t4_get_fw_version(adapter, &adapter->params.fw_vers); if (!ret) ret = t4_get_tp_version(adapter, &adapter->params.tp_vers); - if (!ret) - ret = t4_read_flash(adapter, - FW_IMG_START + offsetof(struct fw_hdr, intfver_nic), - 2, api_vers, 1); if (ret) return ret; major = G_FW_HDR_FW_VER_MAJOR(adapter->params.fw_vers); minor = G_FW_HDR_FW_VER_MINOR(adapter->params.fw_vers); micro = G_FW_HDR_FW_VER_MICRO(adapter->params.fw_vers); - memcpy(adapter->params.api_vers, api_vers, - sizeof(adapter->params.api_vers)); if (major != FW_VERSION_MAJOR) { /* major mismatch - fail */ CH_ERR(adapter, "card FW has major version %u, driver wants " @@ -914,6 +903,21 @@ static int t4_flash_erase_sectors(struct } /** + * t4_flash_cfg_addr - return the address of the flash configuration file + * @adapter: the adapter + * + * Return the address within the flash where the Firmware Configuration + * File is stored. + */ +unsigned int t4_flash_cfg_addr(struct adapter *adapter) +{ + if (adapter->params.sf_size == 0x100000) + return FLASH_FPGA_CFG_START; + else + return FLASH_CFG_START; +} + +/** * t4_load_cfg - download config file * @adap: the adapter * @cfg_data: the cfg text file to write @@ -928,17 +932,8 @@ int t4_load_cfg(struct adapter *adap, co unsigned int flash_cfg_start_sec; unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec; - if (adap->params.sf_size == 0x100000) { - addr = FPGA_FLASH_CFG_OFFSET; - flash_cfg_start_sec = FPGA_FLASH_CFG_START_SEC; - } else { - addr = FLASH_CFG_OFFSET; - flash_cfg_start_sec = FLASH_CFG_START_SEC; - } - if (!size) { - CH_ERR(adap, "cfg file has no data\n"); - return -EINVAL; - } + addr = t4_flash_cfg_addr(adap); + flash_cfg_start_sec = addr / SF_SEC_SIZE; if (size > FLASH_CFG_MAX_SIZE) { CH_ERR(adap, "cfg file too large, max is %u bytes\n", @@ -950,7 +945,11 @@ int t4_load_cfg(struct adapter *adap, co sf_sec_size); ret = t4_flash_erase_sectors(adap, flash_cfg_start_sec, flash_cfg_start_sec + i - 1); - if (ret) + /* + * If size == 0 then we're simply erasing the FLASH sectors associated + * with the on-adapter Firmware Configuration File. + */ + if (ret || size == 0) goto out; /* this will write to the flash up to SF_PAGE_SIZE at a time */ @@ -959,7 +958,7 @@ int t4_load_cfg(struct adapter *adap, co n = size - i; else n = SF_PAGE_SIZE; - ret = t4_write_flash(adap, addr, n, cfg_data); + ret = t4_write_flash(adap, addr, n, cfg_data, 1); if (ret) goto out; @@ -969,7 +968,8 @@ int t4_load_cfg(struct adapter *adap, co out: if (ret) - CH_ERR(adap, "config file download failed %d\n", ret); + CH_ERR(adap, "config file %s failed %d\n", + (size == 0 ? "clear" : "download"), ret); return ret; } @@ -1004,9 +1004,9 @@ int t4_load_fw(struct adapter *adap, con CH_ERR(adap, "FW image size differs from size in FW header\n"); return -EINVAL; } - if (size > FW_MAX_SIZE) { + if (size > FLASH_FW_MAX_SIZE) { CH_ERR(adap, "FW image too large, max is %u bytes\n", - FW_MAX_SIZE); + FLASH_FW_MAX_SIZE); return -EFBIG; } @@ -1020,7 +1020,8 @@ int t4_load_fw(struct adapter *adap, con } 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); + ret = t4_flash_erase_sectors(adap, FLASH_FW_START_SEC, + FLASH_FW_START_SEC + i - 1); if (ret) goto out; @@ -1031,28 +1032,110 @@ int t4_load_fw(struct adapter *adap, con */ 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); + ret = t4_write_flash(adap, FLASH_FW_START, SF_PAGE_SIZE, first_page, 1); if (ret) goto out; - addr = FW_IMG_START; + addr = FLASH_FW_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); + ret = t4_write_flash(adap, addr, SF_PAGE_SIZE, fw_data, 1); 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); + FLASH_FW_START + offsetof(struct fw_hdr, fw_ver), + sizeof(hdr->fw_ver), (const u8 *)&hdr->fw_ver, 1); out: if (ret) CH_ERR(adap, "firmware download failed, error %d\n", ret); return ret; } +/* BIOS boot header */ +typedef struct boot_header_s { + u8 signature[2]; /* signature */ + u8 length; /* image length (include header) */ + u8 offset[4]; /* initialization vector */ + u8 reserved[19]; /* reserved */ + u8 exheader[2]; /* offset to expansion header */ +} boot_header_t; + +enum { + BOOT_FLASH_BOOT_ADDR = 0x0,/* start address of boot image in flash */ + BOOT_SIGNATURE = 0xaa55, /* signature of BIOS boot ROM */ + BOOT_SIZE_INC = 512, /* image size measured in 512B chunks */ + BOOT_MIN_SIZE = sizeof(boot_header_t), /* at least basic header */ + BOOT_MAX_SIZE = 1024*BOOT_SIZE_INC /* 1 byte * length increment */ +}; + +/* + * t4_load_boot - download boot flash + * @adapter: the adapter + * @boot_data: the boot image to write + * @size: image size + * + * Write the supplied boot image to the card's serial flash. + * The boot image has the following sections: a 28-byte header and the + * boot image. + */ +int t4_load_boot(struct adapter *adap, const u8 *boot_data, + unsigned int boot_addr, unsigned int size) +{ + int ret, addr; + unsigned int i; + unsigned int boot_sector = boot_addr * 1024; + unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec; + + /* + * Perform some primitive sanity testing to avoid accidentally + * writing garbage over the boot sectors. We ought to check for + * more but it's not worth it for now ... + */ + if (size < BOOT_MIN_SIZE || size > BOOT_MAX_SIZE) { + CH_ERR(adap, "boot image too small/large\n"); + return -EFBIG; + } + + /* + * Make sure the boot image does not encroach on the firmware region + */ + if ((boot_sector + size) >> 16 > FLASH_FW_START_SEC) { + CH_ERR(adap, "boot image encroaching on firmware region\n"); + return -EFBIG; + } + + i = DIV_ROUND_UP(size, sf_sec_size); /* # of sectors spanned */ + ret = t4_flash_erase_sectors(adap, boot_sector >> 16, + (boot_sector >> 16) + i - 1); + if (ret) + goto out; + + /* + * Skip over the first SF_PAGE_SIZE worth of data and write it after + * we finish copying the rest of the boot image. This will ensure + * that the BIOS boot header will only be written if the boot image + * was written in full. + */ + addr = boot_sector; + for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) { + addr += SF_PAGE_SIZE; *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201112160209.pBG29q5h080761>