bnx2x, cnic: support DRV_INFO upon FW request
authorBarak Witkowski <barak@broadcom.com>
Mon, 5 Dec 2011 22:41:50 +0000 (22:41 +0000)
committerDavid S. Miller <davem@davemloft.net>
Tue, 6 Dec 2011 18:06:05 +0000 (13:06 -0500)
Add support to send driver capabilities, settings and statistics to
management firmware.

[ Redone using many local variables, removed many unnecessary inlines,
  and put #defines at the left margin suggested by Joe Perches ]

Signed-off-by: Barak Witkowski <barak@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
Signed-off-by: Eddie Wai <eddie.wai@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
drivers/net/ethernet/broadcom/cnic.c
drivers/net/ethernet/broadcom/cnic_if.h

index 40cfce0..8c73d34 100644 (file)
@@ -887,6 +887,8 @@ struct bnx2x_common {
 #define CHIP_PORT_MODE_NONE                    0x2
 #define CHIP_MODE(bp)                  (bp->common.chip_port_mode)
 #define CHIP_MODE_IS_4_PORT(bp) (CHIP_MODE(bp) == CHIP_4_PORT_MODE)
+
+       u32                     boot_mode;
 };
 
 /* IGU MSIX STATISTICS on 57712: 64 for VFs; 4 for PFs; 4 for Attentions */
@@ -1048,6 +1050,8 @@ struct bnx2x_slowpath {
 
        u32                             wb_comp;
        u32                             wb_data[4];
+
+       union drv_info_to_mcp           drv_info_to_mcp;
 };
 
 #define bnx2x_sp(bp, var)              (&bp->slowpath->var)
index d9f07cb..3e30c86 100644 (file)
@@ -1253,6 +1253,8 @@ struct drv_func_mb {
        #define DRV_MSG_CODE_DCBX_PMF_DRV_OK            0xb2000000
 
        #define DRV_MSG_CODE_VF_DISABLED_DONE           0xc0000000
+       #define DRV_MSG_CODE_DRV_INFO_ACK               0xd8000000
+       #define DRV_MSG_CODE_DRV_INFO_NACK              0xd9000000
 
        #define DRV_MSG_CODE_SET_MF_BW                  0xe0000000
        #define REQ_BC_VER_4_SET_MF_BW                  0x00060202
@@ -1305,6 +1307,8 @@ struct drv_func_mb {
        #define FW_MSG_CODE_VRFY_OPT_MDL_INVLD_IMG      0xa0200000
        #define FW_MSG_CODE_VRFY_OPT_MDL_UNAPPROVED     0xa0300000
        #define FW_MSG_CODE_VF_DISABLED_DONE            0xb0000000
+       #define FW_MSG_CODE_DRV_INFO_ACK                0xd8100000
+       #define FW_MSG_CODE_DRV_INFO_NACK               0xd9100000
 
        #define FW_MSG_CODE_SET_MF_BW_SENT              0xe0000000
        #define FW_MSG_CODE_SET_MF_BW_DONE              0xe1000000
@@ -1361,6 +1365,7 @@ struct drv_func_mb {
 
        #define DRV_STATUS_DCBX_EVENT_MASK              0x000f0000
        #define DRV_STATUS_DCBX_NEGOTIATION_RESULTS     0x00010000
+       #define DRV_STATUS_DRV_INFO_REQ                 0x04000000
 
        u32 virt_mac_upper;
        #define VIRT_MAC_SIGN_MASK                      0xffff0000
@@ -1965,9 +1970,38 @@ struct shmem2_region {
        u32 extended_dev_info_shared_addr;
        u32 ncsi_oem_data_addr;
 
-       u32 ocsd_host_addr;
-       u32 ocbb_host_addr;
-       u32 ocsd_req_update_interval;
+       u32 ocsd_host_addr; /* initialized by option ROM */
+       u32 ocbb_host_addr; /* initialized by option ROM */
+       u32 ocsd_req_update_interval; /* initialized by option ROM */
+       u32 temperature_in_half_celsius;
+       u32 glob_struct_in_host;
+
+       u32 dcbx_neg_res_ext_offset;
+#define SHMEM_DCBX_NEG_RES_EXT_NONE                    0x00000000
+
+       u32 drv_capabilities_flag[E2_FUNC_MAX];
+#define DRV_FLAGS_CAPABILITIES_LOADED_SUPPORTED 0x00000001
+#define DRV_FLAGS_CAPABILITIES_LOADED_L2        0x00000002
+#define DRV_FLAGS_CAPABILITIES_LOADED_FCOE      0x00000004
+#define DRV_FLAGS_CAPABILITIES_LOADED_ISCSI     0x00000008
+
+       u32 extended_dev_info_shared_cfg_size;
+
+       u32 dcbx_en[PORT_MAX];
+
+       /* The offset points to the multi threaded meta structure */
+       u32 multi_thread_data_offset;
+
+       /* address of DMAable host address holding values from the drivers */
+       u32 drv_info_host_addr_lo;
+       u32 drv_info_host_addr_hi;
+
+       /* general values written by the MFW (such as current version) */
+       u32 drv_info_control;
+#define DRV_INFO_CONTROL_VER_MASK          0x000000ff
+#define DRV_INFO_CONTROL_VER_SHIFT         0
+#define DRV_INFO_CONTROL_OP_CODE_MASK      0x0000ff00
+#define DRV_INFO_CONTROL_OP_CODE_SHIFT     8
 };
 
 
@@ -2553,6 +2587,118 @@ struct host_func_stats {
 /* VIC definitions */
 #define VICSTATST_UIF_INDEX 2
 
+/* current drv_info version */
+#define DRV_INFO_CUR_VER 1
+
+/* drv_info op codes supported */
+enum drv_info_opcode {
+       ETH_STATS_OPCODE,
+       FCOE_STATS_OPCODE,
+       ISCSI_STATS_OPCODE
+};
+
+#define ETH_STAT_INFO_VERSION_LEN      12
+/*  Per PCI Function Ethernet Statistics required from the driver */
+struct eth_stats_info {
+       /* Function's Driver Version. padded to 12 */
+       u8 version[ETH_STAT_INFO_VERSION_LEN];
+       /* Locally Admin Addr. BigEndian EIU48. Actual size is 6 bytes */
+       u8 mac_local[8];
+       u8 mac_add1[8];         /* Additional Programmed MAC Addr 1. */
+       u8 mac_add2[8];         /* Additional Programmed MAC Addr 2. */
+       u32 mtu_size;           /* MTU Size. Note   : Negotiated MTU */
+       u32 feature_flags;      /* Feature_Flags. */
+#define FEATURE_ETH_CHKSUM_OFFLOAD_MASK                0x01
+#define FEATURE_ETH_LSO_MASK                   0x02
+#define FEATURE_ETH_BOOTMODE_MASK              0x1C
+#define FEATURE_ETH_BOOTMODE_SHIFT             2
+#define FEATURE_ETH_BOOTMODE_NONE              (0x0 << 2)
+#define FEATURE_ETH_BOOTMODE_PXE               (0x1 << 2)
+#define FEATURE_ETH_BOOTMODE_ISCSI             (0x2 << 2)
+#define FEATURE_ETH_BOOTMODE_FCOE              (0x3 << 2)
+#define FEATURE_ETH_TOE_MASK                   0x20
+       u32 lso_max_size;       /* LSO MaxOffloadSize. */
+       u32 lso_min_seg_cnt;    /* LSO MinSegmentCount. */
+       /* Num Offloaded Connections TCP_IPv4. */
+       u32 ipv4_ofld_cnt;
+       /* Num Offloaded Connections TCP_IPv6. */
+       u32 ipv6_ofld_cnt;
+       u32 promiscuous_mode;   /* Promiscuous Mode. non-zero true */
+       u32 txq_size;           /* TX Descriptors Queue Size */
+       u32 rxq_size;           /* RX Descriptors Queue Size */
+       /* TX Descriptor Queue Avg Depth. % Avg Queue Depth since last poll */
+       u32 txq_avg_depth;
+       /* RX Descriptors Queue Avg Depth. % Avg Queue Depth since last poll */
+       u32 rxq_avg_depth;
+       /* IOV_Offload. 0=none; 1=MultiQueue, 2=VEB 3= VEPA*/
+       u32 iov_offload;
+       /* Number of NetQueue/VMQ Config'd. */
+       u32 netq_cnt;
+       u32 vf_cnt;             /* Num VF assigned to this PF. */
+};
+
+/*  Per PCI Function FCOE Statistics required from the driver */
+struct fcoe_stats_info {
+       u8 version[12];         /* Function's Driver Version. */
+       u8 mac_local[8];        /* Locally Admin Addr. */
+       u8 mac_add1[8];         /* Additional Programmed MAC Addr 1. */
+       u8 mac_add2[8];         /* Additional Programmed MAC Addr 2. */
+       /* QoS Priority (per 802.1p). 0-7255 */
+       u32 qos_priority;
+       u32 txq_size;           /* FCoE TX Descriptors Queue Size. */
+       u32 rxq_size;           /* FCoE RX Descriptors Queue Size. */
+       /* FCoE TX Descriptor Queue Avg Depth. */
+       u32 txq_avg_depth;
+       /* FCoE RX Descriptors Queue Avg Depth. */
+       u32 rxq_avg_depth;
+       u32 rx_frames_lo;       /* FCoE RX Frames received. */
+       u32 rx_frames_hi;       /* FCoE RX Frames received. */
+       u32 rx_bytes_lo;        /* FCoE RX Bytes received. */
+       u32 rx_bytes_hi;        /* FCoE RX Bytes received. */
+       u32 tx_frames_lo;       /* FCoE TX Frames sent. */
+       u32 tx_frames_hi;       /* FCoE TX Frames sent. */
+       u32 tx_bytes_lo;        /* FCoE TX Bytes sent. */
+       u32 tx_bytes_hi;        /* FCoE TX Bytes sent. */
+};
+
+/* Per PCI  Function iSCSI Statistics required from the driver*/
+struct iscsi_stats_info {
+       u8 version[12];         /* Function's Driver Version. */
+       u8 mac_local[8];        /* Locally Admin iSCSI MAC Addr. */
+       u8 mac_add1[8];         /* Additional Programmed MAC Addr 1. */
+       /* QoS Priority (per 802.1p). 0-7255 */
+       u32 qos_priority;
+       u8 initiator_name[64];  /* iSCSI Boot Initiator Node name. */
+       u8 ww_port_name[64];    /* iSCSI World wide port name */
+       u8 boot_target_name[64];/* iSCSI Boot Target Name. */
+       u8 boot_target_ip[16];  /* iSCSI Boot Target IP. */
+       u32 boot_target_portal; /* iSCSI Boot Target Portal. */
+       u8 boot_init_ip[16];    /* iSCSI Boot Initiator IP Address. */
+       u32 max_frame_size;     /* Max Frame Size. bytes */
+       u32 txq_size;           /* PDU TX Descriptors Queue Size. */
+       u32 rxq_size;           /* PDU RX Descriptors Queue Size. */
+       u32 txq_avg_depth;      /* PDU TX Descriptor Queue Avg Depth. */
+       u32 rxq_avg_depth;      /* PDU RX Descriptors Queue Avg Depth. */
+       u32 rx_pdus_lo;         /* iSCSI PDUs received. */
+       u32 rx_pdus_hi;         /* iSCSI PDUs received. */
+       u32 rx_bytes_lo;        /* iSCSI RX Bytes received. */
+       u32 rx_bytes_hi;        /* iSCSI RX Bytes received. */
+       u32 tx_pdus_lo;         /* iSCSI PDUs sent. */
+       u32 tx_pdus_hi;         /* iSCSI PDUs sent. */
+       u32 tx_bytes_lo;        /* iSCSI PDU TX Bytes sent. */
+       u32 tx_bytes_hi;        /* iSCSI PDU TX Bytes sent. */
+       u32 pcp_prior_map_tbl;  /* C-PCP to S-PCP Priority MapTable.
+                                * 9 nibbles, the position of each nibble
+                                * represents the C-PCP value, the value
+                                * of the nibble = S-PCP value.
+                                */
+};
+
+union drv_info_to_mcp {
+       struct eth_stats_info   ether_stat;
+       struct fcoe_stats_info  fcoe_stat;
+       struct iscsi_stats_info iscsi_stat;
+};
 #define BCM_5710_FW_MAJOR_VERSION                      7
 #define BCM_5710_FW_MINOR_VERSION                      0
 #define BCM_5710_FW_REVISION_VERSION           29
index 552c564..86d36f8 100644 (file)
@@ -2912,6 +2912,143 @@ static void bnx2x_e1h_enable(struct bnx2x *bp)
         */
 }
 
+#define DRV_INFO_ETH_STAT_NUM_MACS_REQUIRED 3
+
+static void bnx2x_drv_info_ether_stat(struct bnx2x *bp)
+{
+       struct eth_stats_info *ether_stat =
+               &bp->slowpath->drv_info_to_mcp.ether_stat;
+
+       /* leave last char as NULL */
+       memcpy(ether_stat->version, DRV_MODULE_VERSION,
+              ETH_STAT_INFO_VERSION_LEN - 1);
+
+       bp->fp[0].mac_obj.get_n_elements(bp, &bp->fp[0].mac_obj,
+                                        DRV_INFO_ETH_STAT_NUM_MACS_REQUIRED,
+                                        ether_stat->mac_local);
+
+       ether_stat->mtu_size = bp->dev->mtu;
+
+       if (bp->dev->features & NETIF_F_RXCSUM)
+               ether_stat->feature_flags |= FEATURE_ETH_CHKSUM_OFFLOAD_MASK;
+       if (bp->dev->features & NETIF_F_TSO)
+               ether_stat->feature_flags |= FEATURE_ETH_LSO_MASK;
+       ether_stat->feature_flags |= bp->common.boot_mode;
+
+       ether_stat->promiscuous_mode = (bp->dev->flags & IFF_PROMISC) ? 1 : 0;
+
+       ether_stat->txq_size = bp->tx_ring_size;
+       ether_stat->rxq_size = bp->rx_ring_size;
+}
+
+static void bnx2x_drv_info_fcoe_stat(struct bnx2x *bp)
+{
+       struct bnx2x_dcbx_app_params *app = &bp->dcbx_port_params.app;
+       struct fcoe_stats_info *fcoe_stat =
+               &bp->slowpath->drv_info_to_mcp.fcoe_stat;
+
+       memcpy(fcoe_stat->mac_local, bp->fip_mac, ETH_ALEN);
+
+       fcoe_stat->qos_priority =
+               app->traffic_type_priority[LLFC_TRAFFIC_TYPE_FCOE];
+
+       /* insert FCoE stats from ramrod response */
+       if (!NO_FCOE(bp)) {
+               struct tstorm_per_queue_stats *fcoe_q_tstorm_stats =
+                       &bp->fw_stats_data->queue_stats[FCOE_IDX].
+                       tstorm_queue_statistics;
+
+               struct xstorm_per_queue_stats *fcoe_q_xstorm_stats =
+                       &bp->fw_stats_data->queue_stats[FCOE_IDX].
+                       xstorm_queue_statistics;
+
+               struct fcoe_statistics_params *fw_fcoe_stat =
+                       &bp->fw_stats_data->fcoe;
+
+               ADD_64(fcoe_stat->rx_bytes_hi, 0, fcoe_stat->rx_bytes_lo,
+                      fw_fcoe_stat->rx_stat0.fcoe_rx_byte_cnt);
+
+               ADD_64(fcoe_stat->rx_bytes_hi,
+                      fcoe_q_tstorm_stats->rcv_ucast_bytes.hi,
+                      fcoe_stat->rx_bytes_lo,
+                      fcoe_q_tstorm_stats->rcv_ucast_bytes.lo);
+
+               ADD_64(fcoe_stat->rx_bytes_hi,
+                      fcoe_q_tstorm_stats->rcv_bcast_bytes.hi,
+                      fcoe_stat->rx_bytes_lo,
+                      fcoe_q_tstorm_stats->rcv_bcast_bytes.lo);
+
+               ADD_64(fcoe_stat->rx_bytes_hi,
+                      fcoe_q_tstorm_stats->rcv_mcast_bytes.hi,
+                      fcoe_stat->rx_bytes_lo,
+                      fcoe_q_tstorm_stats->rcv_mcast_bytes.lo);
+
+               ADD_64(fcoe_stat->rx_frames_hi, 0, fcoe_stat->rx_frames_lo,
+                      fw_fcoe_stat->rx_stat0.fcoe_rx_pkt_cnt);
+
+               ADD_64(fcoe_stat->rx_frames_hi, 0, fcoe_stat->rx_frames_lo,
+                      fcoe_q_tstorm_stats->rcv_ucast_pkts);
+
+               ADD_64(fcoe_stat->rx_frames_hi, 0, fcoe_stat->rx_frames_lo,
+                      fcoe_q_tstorm_stats->rcv_bcast_pkts);
+
+               ADD_64(fcoe_stat->rx_frames_hi, 0, fcoe_stat->rx_frames_lo,
+                      fcoe_q_tstorm_stats->rcv_ucast_pkts);
+
+               ADD_64(fcoe_stat->tx_bytes_hi, 0, fcoe_stat->tx_bytes_lo,
+                      fw_fcoe_stat->tx_stat.fcoe_tx_byte_cnt);
+
+               ADD_64(fcoe_stat->tx_bytes_hi,
+                      fcoe_q_xstorm_stats->ucast_bytes_sent.hi,
+                      fcoe_stat->tx_bytes_lo,
+                      fcoe_q_xstorm_stats->ucast_bytes_sent.lo);
+
+               ADD_64(fcoe_stat->tx_bytes_hi,
+                      fcoe_q_xstorm_stats->bcast_bytes_sent.hi,
+                      fcoe_stat->tx_bytes_lo,
+                      fcoe_q_xstorm_stats->bcast_bytes_sent.lo);
+
+               ADD_64(fcoe_stat->tx_bytes_hi,
+                      fcoe_q_xstorm_stats->mcast_bytes_sent.hi,
+                      fcoe_stat->tx_bytes_lo,
+                      fcoe_q_xstorm_stats->mcast_bytes_sent.lo);
+
+               ADD_64(fcoe_stat->tx_frames_hi, 0, fcoe_stat->tx_frames_lo,
+                      fw_fcoe_stat->tx_stat.fcoe_tx_pkt_cnt);
+
+               ADD_64(fcoe_stat->tx_frames_hi, 0, fcoe_stat->tx_frames_lo,
+                      fcoe_q_xstorm_stats->ucast_pkts_sent);
+
+               ADD_64(fcoe_stat->tx_frames_hi, 0, fcoe_stat->tx_frames_lo,
+                      fcoe_q_xstorm_stats->bcast_pkts_sent);
+
+               ADD_64(fcoe_stat->tx_frames_hi, 0, fcoe_stat->tx_frames_lo,
+                      fcoe_q_xstorm_stats->mcast_pkts_sent);
+       }
+
+#ifdef BCM_CNIC
+       /* ask L5 driver to add data to the struct */
+       bnx2x_cnic_notify(bp, CNIC_CTL_FCOE_STATS_GET_CMD);
+#endif
+}
+
+static void bnx2x_drv_info_iscsi_stat(struct bnx2x *bp)
+{
+       struct bnx2x_dcbx_app_params *app = &bp->dcbx_port_params.app;
+       struct iscsi_stats_info *iscsi_stat =
+               &bp->slowpath->drv_info_to_mcp.iscsi_stat;
+
+       memcpy(iscsi_stat->mac_local, bp->cnic_eth_dev.iscsi_mac, ETH_ALEN);
+
+       iscsi_stat->qos_priority =
+               app->traffic_type_priority[LLFC_TRAFFIC_TYPE_ISCSI];
+
+#ifdef BCM_CNIC
+       /* ask L5 driver to add data to the struct */
+       bnx2x_cnic_notify(bp, CNIC_CTL_ISCSI_STATS_GET_CMD);
+#endif
+}
+
 /* called due to MCP event (on pmf):
  *     reread new bandwidth configuration
  *     configure FW
@@ -2932,6 +3069,50 @@ static inline void bnx2x_set_mf_bw(struct bnx2x *bp)
        bnx2x_fw_command(bp, DRV_MSG_CODE_SET_MF_BW_ACK, 0);
 }
 
+static void bnx2x_handle_drv_info_req(struct bnx2x *bp)
+{
+       enum drv_info_opcode op_code;
+       u32 drv_info_ctl = SHMEM2_RD(bp, drv_info_control);
+
+       /* if drv_info version supported by MFW doesn't match - send NACK */
+       if ((drv_info_ctl & DRV_INFO_CONTROL_VER_MASK) != DRV_INFO_CUR_VER) {
+               bnx2x_fw_command(bp, DRV_MSG_CODE_DRV_INFO_NACK, 0);
+               return;
+       }
+
+       op_code = (drv_info_ctl & DRV_INFO_CONTROL_OP_CODE_MASK) >>
+                 DRV_INFO_CONTROL_OP_CODE_SHIFT;
+
+       memset(&bp->slowpath->drv_info_to_mcp, 0,
+              sizeof(union drv_info_to_mcp));
+
+       switch (op_code) {
+       case ETH_STATS_OPCODE:
+               bnx2x_drv_info_ether_stat(bp);
+               break;
+       case FCOE_STATS_OPCODE:
+               bnx2x_drv_info_fcoe_stat(bp);
+               break;
+       case ISCSI_STATS_OPCODE:
+               bnx2x_drv_info_iscsi_stat(bp);
+               break;
+       default:
+               /* if op code isn't supported - send NACK */
+               bnx2x_fw_command(bp, DRV_MSG_CODE_DRV_INFO_NACK, 0);
+               return;
+       }
+
+       /* if we got drv_info attn from MFW then these fields are defined in
+        * shmem2 for sure
+        */
+       SHMEM2_WR(bp, drv_info_host_addr_lo,
+               U64_LO(bnx2x_sp_mapping(bp, drv_info_to_mcp)));
+       SHMEM2_WR(bp, drv_info_host_addr_hi,
+               U64_HI(bnx2x_sp_mapping(bp, drv_info_to_mcp)));
+
+       bnx2x_fw_command(bp, DRV_MSG_CODE_DRV_INFO_ACK, 0);
+}
+
 static void bnx2x_dcc_event(struct bnx2x *bp, u32 dcc_event)
 {
        DP(BNX2X_MSG_MCP, "dcc_event 0x%x\n", dcc_event);
@@ -3439,6 +3620,8 @@ static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
                        if (val & DRV_STATUS_SET_MF_BW)
                                bnx2x_set_mf_bw(bp);
 
+                       if (val & DRV_STATUS_DRV_INFO_REQ)
+                               bnx2x_handle_drv_info_req(bp);
                        if ((bp->port.pmf == 0) && (val & DRV_STATUS_PMF))
                                bnx2x_pmf_update(bp);
 
@@ -8716,7 +8899,7 @@ static void __devinit bnx2x_undi_unload(struct bnx2x *bp)
 
 static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
 {
-       u32 val, val2, val3, val4, id;
+       u32 val, val2, val3, val4, id, boot_mode;
        u16 pmc;
 
        /* Get the chip revision id and number. */
@@ -8828,6 +9011,24 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
        bp->flags |= (val >= REQ_BC_VER_4_PFC_STATS_SUPPORTED) ?
                        BC_SUPPORTS_PFC_STATS : 0;
 
+       boot_mode = SHMEM_RD(bp,
+                       dev_info.port_feature_config[BP_PORT(bp)].mba_config) &
+                       PORT_FEATURE_MBA_BOOT_AGENT_TYPE_MASK;
+       switch (boot_mode) {
+       case PORT_FEATURE_MBA_BOOT_AGENT_TYPE_PXE:
+               bp->common.boot_mode = FEATURE_ETH_BOOTMODE_PXE;
+               break;
+       case PORT_FEATURE_MBA_BOOT_AGENT_TYPE_ISCSIB:
+               bp->common.boot_mode = FEATURE_ETH_BOOTMODE_ISCSI;
+               break;
+       case PORT_FEATURE_MBA_BOOT_AGENT_TYPE_FCOE_BOOT:
+               bp->common.boot_mode = FEATURE_ETH_BOOTMODE_FCOE;
+               break;
+       case PORT_FEATURE_MBA_BOOT_AGENT_TYPE_NONE:
+               bp->common.boot_mode = FEATURE_ETH_BOOTMODE_NONE;
+               break;
+       }
+
        pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_PMC, &pmc);
        bp->flags |= (pmc & PCI_PM_CAP_PME_D3cold) ? 0 : NO_WOL_FLAG;
 
@@ -11550,6 +11751,38 @@ static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl)
                smp_mb__after_atomic_inc();
                break;
        }
+       case DRV_CTL_ULP_REGISTER_CMD: {
+               int ulp_type = ctl->data.ulp_type;
+
+               if (CHIP_IS_E3(bp)) {
+                       int idx = BP_FW_MB_IDX(bp);
+                       u32 cap;
+
+                       cap = SHMEM2_RD(bp, drv_capabilities_flag[idx]);
+                       if (ulp_type == CNIC_ULP_ISCSI)
+                               cap |= DRV_FLAGS_CAPABILITIES_LOADED_ISCSI;
+                       else if (ulp_type == CNIC_ULP_FCOE)
+                               cap |= DRV_FLAGS_CAPABILITIES_LOADED_FCOE;
+                       SHMEM2_WR(bp, drv_capabilities_flag[idx], cap);
+               }
+               break;
+       }
+       case DRV_CTL_ULP_UNREGISTER_CMD: {
+               int ulp_type = ctl->data.ulp_type;
+
+               if (CHIP_IS_E3(bp)) {
+                       int idx = BP_FW_MB_IDX(bp);
+                       u32 cap;
+
+                       cap = SHMEM2_RD(bp, drv_capabilities_flag[idx]);
+                       if (ulp_type == CNIC_ULP_ISCSI)
+                               cap &= ~DRV_FLAGS_CAPABILITIES_LOADED_ISCSI;
+                       else if (ulp_type == CNIC_ULP_FCOE)
+                               cap &= ~DRV_FLAGS_CAPABILITIES_LOADED_FCOE;
+                       SHMEM2_WR(bp, drv_capabilities_flag[idx], cap);
+               }
+               break;
+       }
 
        default:
                BNX2X_ERR("unknown command %x\n", ctl->cmd);
index 41a33ce..bc0121a 100644 (file)
@@ -39,6 +39,17 @@ static inline long bnx2x_hilo(u32 *hiref)
 #endif
 }
 
+static u16 bnx2x_get_port_stats_dma_len(struct bnx2x *bp)
+{
+       u16 res = sizeof(struct host_port_stats) >> 2;
+
+       /* if PFC stats are not supported by the MFW, don't DMA them */
+       if (!(bp->flags &  BC_SUPPORTS_PFC_STATS))
+               res -= (sizeof(u32)*4) >> 2;
+
+       return res;
+}
+
 /*
  * Init service functions
  */
@@ -178,7 +189,8 @@ static void bnx2x_stats_pmf_update(struct bnx2x *bp)
                                   DMAE_LEN32_RD_MAX * 4);
        dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats) +
                                   DMAE_LEN32_RD_MAX * 4);
-       dmae->len = (sizeof(struct host_port_stats) >> 2) - DMAE_LEN32_RD_MAX;
+       dmae->len = bnx2x_get_port_stats_dma_len(bp) - DMAE_LEN32_RD_MAX;
+
        dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
        dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
        dmae->comp_val = DMAE_COMP_VAL;
@@ -217,7 +229,7 @@ static void bnx2x_port_stats_init(struct bnx2x *bp)
                dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats));
                dmae->dst_addr_lo = bp->port.port_stx >> 2;
                dmae->dst_addr_hi = 0;
-               dmae->len = sizeof(struct host_port_stats) >> 2;
+               dmae->len = bnx2x_get_port_stats_dma_len(bp);
                dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
                dmae->comp_addr_hi = 0;
                dmae->comp_val = 1;
@@ -1307,7 +1319,7 @@ static void bnx2x_port_stats_stop(struct bnx2x *bp)
                dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats));
                dmae->dst_addr_lo = bp->port.port_stx >> 2;
                dmae->dst_addr_hi = 0;
-               dmae->len = sizeof(struct host_port_stats) >> 2;
+               dmae->len = bnx2x_get_port_stats_dma_len(bp);
                if (bp->func_stx) {
                        dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
                        dmae->comp_addr_hi = 0;
@@ -1424,7 +1436,7 @@ static void bnx2x_port_stats_base_init(struct bnx2x *bp)
        dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats));
        dmae->dst_addr_lo = bp->port.port_stx >> 2;
        dmae->dst_addr_hi = 0;
-       dmae->len = sizeof(struct host_port_stats) >> 2;
+       dmae->len = bnx2x_get_port_stats_dma_len(bp);
        dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp));
        dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp));
        dmae->comp_val = DMAE_COMP_VAL;
index b336e55..4bcb67e 100644 (file)
@@ -250,6 +250,21 @@ static u32 cnic_reg_rd_ind(struct cnic_dev *dev, u32 off)
        return io->data;
 }
 
+static void cnic_ulp_ctl(struct cnic_dev *dev, int ulp_type, bool reg)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       struct cnic_eth_dev *ethdev = cp->ethdev;
+       struct drv_ctl_info info;
+
+       if (reg)
+               info.cmd = DRV_CTL_ULP_REGISTER_CMD;
+       else
+               info.cmd = DRV_CTL_ULP_UNREGISTER_CMD;
+
+       info.data.ulp_type = ulp_type;
+       ethdev->drv_ctl(dev->netdev, &info);
+}
+
 static int cnic_in_use(struct cnic_sock *csk)
 {
        return test_bit(SK_F_INUSE, &csk->flags);
@@ -563,6 +578,8 @@ static int cnic_register_device(struct cnic_dev *dev, int ulp_type,
 
        mutex_unlock(&cnic_lock);
 
+       cnic_ulp_ctl(dev, ulp_type, true);
+
        return 0;
 
 }
@@ -602,6 +619,8 @@ static int cnic_unregister_device(struct cnic_dev *dev, int ulp_type)
        if (test_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[ulp_type]))
                netdev_warn(dev->netdev, "Failed waiting for ULP up call to complete\n");
 
+       cnic_ulp_ctl(dev, ulp_type, false);
+
        return 0;
 }
 EXPORT_SYMBOL(cnic_unregister_driver);
@@ -3052,9 +3071,26 @@ static void cnic_ulp_start(struct cnic_dev *dev)
        }
 }
 
+static int cnic_copy_ulp_stats(struct cnic_dev *dev, int ulp_type)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       struct cnic_ulp_ops *ulp_ops;
+       int rc;
+
+       mutex_lock(&cnic_lock);
+       ulp_ops = cnic_ulp_tbl_prot(ulp_type);
+       if (ulp_ops && ulp_ops->cnic_get_stats)
+               rc = ulp_ops->cnic_get_stats(cp->ulp_handle[ulp_type]);
+       else
+               rc = -ENODEV;
+       mutex_unlock(&cnic_lock);
+       return rc;
+}
+
 static int cnic_ctl(void *data, struct cnic_ctl_info *info)
 {
        struct cnic_dev *dev = data;
+       int ulp_type = CNIC_ULP_ISCSI;
 
        switch (info->cmd) {
        case CNIC_CTL_STOP_CMD:
@@ -3100,6 +3136,15 @@ static int cnic_ctl(void *data, struct cnic_ctl_info *info)
                }
                break;
        }
+       case CNIC_CTL_FCOE_STATS_GET_CMD:
+               ulp_type = CNIC_ULP_FCOE;
+               /* fall through */
+       case CNIC_CTL_ISCSI_STATS_GET_CMD:
+               cnic_hold(dev);
+               cnic_copy_ulp_stats(dev, ulp_type);
+               cnic_put(dev);
+               break;
+
        default:
                return -EINVAL;
        }
@@ -5288,6 +5333,8 @@ static struct cnic_dev *init_bnx2x_cnic(struct net_device *dev)
        cdev->pcidev = pdev;
        cp->chip_id = ethdev->chip_id;
 
+       cdev->stats_addr = ethdev->addr_drv_info_to_mcp;
+
        if (!(ethdev->drv_state & CNIC_DRV_STATE_NO_ISCSI))
                cdev->max_iscsi_conn = ethdev->max_iscsi_conn;
        if (BNX2X_CHIP_IS_E2_PLUS(cp->chip_id) &&
index 79443e0..d1f6456 100644 (file)
@@ -86,6 +86,8 @@ struct kcqe {
 #define CNIC_CTL_START_CMD             2
 #define CNIC_CTL_COMPLETION_CMD                3
 #define CNIC_CTL_STOP_ISCSI_CMD                4
+#define CNIC_CTL_FCOE_STATS_GET_CMD    5
+#define CNIC_CTL_ISCSI_STATS_GET_CMD   6
 
 #define DRV_CTL_IO_WR_CMD              0x101
 #define DRV_CTL_IO_RD_CMD              0x102
@@ -96,6 +98,8 @@ struct kcqe {
 #define DRV_CTL_STOP_L2_CMD            0x107
 #define DRV_CTL_RET_L2_SPQ_CREDIT_CMD  0x10c
 #define DRV_CTL_ISCSI_STOPPED_CMD      0x10d
+#define DRV_CTL_ULP_REGISTER_CMD       0x10e
+#define DRV_CTL_ULP_UNREGISTER_CMD     0x10f
 
 struct cnic_ctl_completion {
        u32     cid;
@@ -133,6 +137,7 @@ struct drv_ctl_info {
                struct drv_ctl_spq_credit credit;
                struct drv_ctl_io io;
                struct drv_ctl_l2_ring ring;
+               int ulp_type;
                char bytes[MAX_DRV_CTL_DATA];
        } data;
 };
@@ -201,6 +206,7 @@ struct cnic_eth_dev {
                                               struct kwqe_16 *[], u32);
        int             (*drv_ctl)(struct net_device *, struct drv_ctl_info *);
        unsigned long   reserved1[2];
+       union drv_info_to_mcp   *addr_drv_info_to_mcp;
 };
 
 struct cnic_sockaddr {
@@ -297,6 +303,8 @@ struct cnic_dev {
        int             max_fcoe_conn;
        int             max_rdma_conn;
 
+       union drv_info_to_mcp   *stats_addr;
+
        void            *cnic_priv;
 };
 
@@ -326,6 +334,7 @@ struct cnic_ulp_ops {
        void (*cm_remote_abort)(struct cnic_sock *);
        int (*iscsi_nl_send_msg)(void *ulp_ctx, u32 msg_type,
                                  char *data, u16 data_size);
+       int (*cnic_get_stats)(void *ulp_ctx);
        struct module *owner;
        atomic_t ref_count;
 };