/* * Stop device. */ static void cxgbe_dev_close(struct rte_eth_dev *eth_dev) { struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private); struct adapter *adapter = pi->adapter; int i, dev_down = 0; CXGBE_FUNC_TRACE(); if (!(adapter->flags & FULL_INIT_DONE)) return; cxgbe_down(pi); /* * We clear queues only if both tx and rx path of the port * have been disabled */ t4_sge_eth_clear_queues(pi); /* See if all ports are down */ for_each_port(adapter, i) { pi = adap2pinfo(adapter, i); /* * Skip first port of the adapter since it will be closed * by DPDK */ if (i == 0) continue; dev_down += (pi->eth_dev->data->dev_started == 0) ? 1 : 0; }
int t3_vsc8211_fifo_depth(adapter_t *adap, unsigned int mtu, int port) { /* TX FIFO Depth set bits 9:7 to 100 (IEEE mode) */ unsigned int val = 4; unsigned int currentregval; unsigned int regval; int err; /* Retrieve the port info structure from adater_t */ struct port_info *portinfo = adap2pinfo(adap, port); /* What phy is this */ struct cphy *phy = &portinfo->phy; /* Read the current value of the PHY control Register */ err = mdio_read(phy, 0, VSC8211_PHY_CTRL, ¤tregval); if (err) return err; /* IEEE mode supports up to 1518 bytes */ /* mtu does not contain the header + FCS (18 bytes) */ if (mtu > 1500) /* * If using a packet size > 1500 set TX FIFO Depth bits * 9:7 to 011 (Jumbo packet mode) */ val = 3; regval = V_VSC8211_TXFIFODEPTH(val) | V_VSC8211_RXFIFODEPTH(val) | (currentregval & ~V_VSC8211_TXFIFODEPTH(M_VSC8211_TXFIFODEPTH) & ~V_VSC8211_RXFIFODEPTH(M_VSC8211_RXFIFODEPTH)); return mdio_write(phy, 0, VSC8211_PHY_CTRL, regval); }
/** * t4vf_port_init - initialize port hardware/software state * @adapter: the adapter * @pidx: the adapter port index */ int 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_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; }
/** * 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; }
static void cxgbe_dev_info_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *device_info) { struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private); struct adapter *adapter = pi->adapter; int max_queues = adapter->sge.max_ethqsets / adapter->params.nports; static const struct rte_eth_desc_lim cxgbe_desc_lim = { .nb_max = CXGBE_MAX_RING_DESC_SIZE, .nb_min = CXGBE_MIN_RING_DESC_SIZE, .nb_align = 1, }; device_info->min_rx_bufsize = CXGBE_MIN_RX_BUFSIZE; device_info->max_rx_pktlen = CXGBE_MAX_RX_PKTLEN; device_info->max_rx_queues = max_queues; device_info->max_tx_queues = max_queues; device_info->max_mac_addrs = 1; /* XXX: For now we support one MAC/port */ device_info->max_vfs = adapter->params.arch.vfcount; device_info->max_vmdq_pools = 0; /* XXX: For now no support for VMDQ */ device_info->rx_offload_capa = DEV_RX_OFFLOAD_VLAN_STRIP | DEV_RX_OFFLOAD_IPV4_CKSUM | DEV_RX_OFFLOAD_UDP_CKSUM | DEV_RX_OFFLOAD_TCP_CKSUM; device_info->tx_offload_capa = DEV_TX_OFFLOAD_VLAN_INSERT | DEV_TX_OFFLOAD_IPV4_CKSUM | DEV_TX_OFFLOAD_UDP_CKSUM | DEV_TX_OFFLOAD_TCP_CKSUM | DEV_TX_OFFLOAD_TCP_TSO; device_info->reta_size = pi->rss_size; device_info->rx_desc_lim = cxgbe_desc_lim; device_info->tx_desc_lim = cxgbe_desc_lim; } static void cxgbe_dev_promiscuous_enable(struct rte_eth_dev *eth_dev) { struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private); struct adapter *adapter = pi->adapter; t4_set_rxmode(adapter, adapter->mbox, pi->viid, -1, 1, -1, 1, -1, false); } static void cxgbe_dev_promiscuous_disable(struct rte_eth_dev *eth_dev) { struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private); struct adapter *adapter = pi->adapter; t4_set_rxmode(adapter, adapter->mbox, pi->viid, -1, 0, -1, 1, -1, false); } static void cxgbe_dev_allmulticast_enable(struct rte_eth_dev *eth_dev) { struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private); struct adapter *adapter = pi->adapter; /* TODO: address filters ?? */ t4_set_rxmode(adapter, adapter->mbox, pi->viid, -1, -1, 1, 1, -1, false); } static void cxgbe_dev_allmulticast_disable(struct rte_eth_dev *eth_dev) { struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private); struct adapter *adapter = pi->adapter; /* TODO: address filters ?? */ t4_set_rxmode(adapter, adapter->mbox, pi->viid, -1, -1, 0, 1, -1, false); } static int cxgbe_dev_link_update(struct rte_eth_dev *eth_dev, __rte_unused int wait_to_complete) { struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private); struct adapter *adapter = pi->adapter; struct sge *s = &adapter->sge; struct rte_eth_link *old_link = ð_dev->data->dev_link; unsigned int work_done, budget = 4; cxgbe_poll(&s->fw_evtq, NULL, budget, &work_done); if (old_link->link_status == pi->link_cfg.link_ok) return -1; /* link not changed */ eth_dev->data->dev_link.link_status = pi->link_cfg.link_ok; eth_dev->data->dev_link.link_duplex = ETH_LINK_FULL_DUPLEX; eth_dev->data->dev_link.link_speed = pi->link_cfg.speed; /* link has changed */ return 0; } static int cxgbe_dev_mtu_set(struct rte_eth_dev *eth_dev, uint16_t mtu) { struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private); struct adapter *adapter = pi->adapter; struct rte_eth_dev_info dev_info; int err; uint16_t new_mtu = mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; cxgbe_dev_info_get(eth_dev, &dev_info); /* Must accommodate at least ETHER_MIN_MTU */ if ((new_mtu < ETHER_MIN_MTU) || (new_mtu > dev_info.max_rx_pktlen)) return -EINVAL; /* set to jumbo mode if needed */ if (new_mtu > ETHER_MAX_LEN) eth_dev->data->dev_conf.rxmode.jumbo_frame = 1; else eth_dev->data->dev_conf.rxmode.jumbo_frame = 0; err = t4_set_rxmode(adapter, adapter->mbox, pi->viid, new_mtu, -1, -1, -1, -1, true); if (!err) eth_dev->data->dev_conf.rxmode.max_rx_pkt_len = new_mtu; return err; } static int cxgbe_dev_tx_queue_start(struct rte_eth_dev *eth_dev, uint16_t tx_queue_id); static int cxgbe_dev_rx_queue_start(struct rte_eth_dev *eth_dev, uint16_t tx_queue_id); static void cxgbe_dev_tx_queue_release(void *q); static void cxgbe_dev_rx_queue_release(void *q); /* * Stop device. */ static void cxgbe_dev_close(struct rte_eth_dev *eth_dev) { struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private); struct adapter *adapter = pi->adapter; int i, dev_down = 0; CXGBE_FUNC_TRACE(); if (!(adapter->flags & FULL_INIT_DONE)) return; cxgbe_down(pi); /* * We clear queues only if both tx and rx path of the port * have been disabled */ t4_sge_eth_clear_queues(pi); /* See if all ports are down */ for_each_port(adapter, i) { pi = adap2pinfo(adapter, i); /* * Skip first port of the adapter since it will be closed * by DPDK */ if (i == 0) continue; dev_down += (pi->eth_dev->data->dev_started == 0) ? 1 : 0; } /* If rest of the ports are stopped, then free up resources */ if (dev_down == (adapter->params.nports - 1)) cxgbe_close(adapter); }