+static const uint32_t *
+pfe_supported_ptypes_get(struct rte_eth_dev *dev)
+{
+ static const uint32_t ptypes[] = {
+ /*todo -= add more types */
+ RTE_PTYPE_L2_ETHER,
+ RTE_PTYPE_L3_IPV4,
+ RTE_PTYPE_L3_IPV4_EXT,
+ RTE_PTYPE_L3_IPV6,
+ RTE_PTYPE_L3_IPV6_EXT,
+ RTE_PTYPE_L4_TCP,
+ RTE_PTYPE_L4_UDP,
+ RTE_PTYPE_L4_SCTP
+ };
+
+ if (dev->rx_pkt_burst == pfe_recv_pkts ||
+ dev->rx_pkt_burst == pfe_recv_pkts_on_intr)
+ return ptypes;
+ return NULL;
+}
+
+static inline int
+pfe_eth_atomic_read_link_status(struct rte_eth_dev *dev,
+ struct rte_eth_link *link)
+{
+ struct rte_eth_link *dst = link;
+ struct rte_eth_link *src = &dev->data->dev_link;
+
+ if (rte_atomic64_cmpset((uint64_t *)dst, *(uint64_t *)dst,
+ *(uint64_t *)src) == 0)
+ return -1;
+
+ return 0;
+}
+
+static inline int
+pfe_eth_atomic_write_link_status(struct rte_eth_dev *dev,
+ struct rte_eth_link *link)
+{
+ struct rte_eth_link *dst = &dev->data->dev_link;
+ struct rte_eth_link *src = link;
+
+ if (rte_atomic64_cmpset((uint64_t *)dst, *(uint64_t *)dst,
+ *(uint64_t *)src) == 0)
+ return -1;
+
+ return 0;
+}
+
+static int
+pfe_eth_link_update(struct rte_eth_dev *dev, int wait_to_complete __rte_unused)
+{
+ int ret, ioctl_cmd = 0;
+ struct pfe_eth_priv_s *priv = dev->data->dev_private;
+ struct rte_eth_link link, old;
+ unsigned int lstatus = 1;
+
+ if (dev == NULL) {
+ PFE_PMD_ERR("Invalid device in link_update.\n");
+ return 0;
+ }
+
+ memset(&old, 0, sizeof(old));
+ memset(&link, 0, sizeof(struct rte_eth_link));
+
+ pfe_eth_atomic_read_link_status(dev, &old);
+
+ /* Read from PFE CDEV, status of link, if file was successfully
+ * opened.
+ */
+ if (priv->link_fd != PFE_CDEV_INVALID_FD) {
+ if (priv->id == 0)
+ ioctl_cmd = PFE_CDEV_ETH0_STATE_GET;
+ if (priv->id == 1)
+ ioctl_cmd = PFE_CDEV_ETH1_STATE_GET;
+
+ ret = ioctl(priv->link_fd, ioctl_cmd, &lstatus);
+ if (ret != 0) {
+ PFE_PMD_ERR("Unable to fetch link status (ioctl)\n");
+ /* use dummy link value */
+ link.link_status = 1;
+ }
+ PFE_PMD_DEBUG("Fetched link state (%d) for dev %d.\n",
+ lstatus, priv->id);
+ }
+
+ if (old.link_status == lstatus) {
+ /* no change in status */
+ PFE_PMD_DEBUG("No change in link status; Not updating.\n");
+ return -1;
+ }
+
+ link.link_status = lstatus;
+ link.link_speed = ETH_LINK_SPEED_1G;
+ link.link_duplex = ETH_LINK_FULL_DUPLEX;
+ link.link_autoneg = ETH_LINK_AUTONEG;
+
+ pfe_eth_atomic_write_link_status(dev, &link);
+
+ PFE_PMD_INFO("Port (%d) link is %s\n", dev->data->port_id,
+ link.link_status ? "up" : "down");
+
+ return 0;
+}
+
+static int
+pfe_promiscuous_enable(struct rte_eth_dev *dev)
+{
+ struct pfe_eth_priv_s *priv = dev->data->dev_private;
+
+ priv->promisc = 1;
+ dev->data->promiscuous = 1;
+ gemac_enable_copy_all(priv->EMAC_baseaddr);
+
+ return 0;
+}
+
+static int
+pfe_promiscuous_disable(struct rte_eth_dev *dev)
+{
+ struct pfe_eth_priv_s *priv = dev->data->dev_private;
+
+ priv->promisc = 0;
+ dev->data->promiscuous = 0;
+ gemac_disable_copy_all(priv->EMAC_baseaddr);
+
+ return 0;
+}
+
+static int
+pfe_allmulticast_enable(struct rte_eth_dev *dev)
+{
+ struct pfe_eth_priv_s *priv = dev->data->dev_private;
+ struct pfe_mac_addr hash_addr; /* hash register structure */
+
+ /* Set the hash to rx all multicast frames */
+ hash_addr.bottom = 0xFFFFFFFF;
+ hash_addr.top = 0xFFFFFFFF;
+ gemac_set_hash(priv->EMAC_baseaddr, &hash_addr);
+ dev->data->all_multicast = 1;
+
+ return 0;
+}
+
+static int
+pfe_link_down(struct rte_eth_dev *dev)
+{
+ return pfe_eth_stop(dev);
+}
+
+static int
+pfe_link_up(struct rte_eth_dev *dev)
+{
+ struct pfe_eth_priv_s *priv = dev->data->dev_private;
+
+ pfe_eth_start(priv);
+ return 0;
+}
+
+static int
+pfe_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
+{
+ int ret;
+ struct pfe_eth_priv_s *priv = dev->data->dev_private;
+ uint16_t frame_size = mtu + RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN;
+
+ /*TODO Support VLAN*/
+ ret = gemac_set_rx(priv->EMAC_baseaddr, frame_size);
+ if (!ret)
+ dev->data->mtu = mtu;
+
+ return ret;
+}
+
+/* pfe_eth_enet_addr_byte_mac
+ */
+static int
+pfe_eth_enet_addr_byte_mac(u8 *enet_byte_addr,
+ struct pfe_mac_addr *enet_addr)
+{
+ if (!enet_byte_addr || !enet_addr) {
+ return -1;
+
+ } else {
+ enet_addr->bottom = enet_byte_addr[0] |
+ (enet_byte_addr[1] << 8) |
+ (enet_byte_addr[2] << 16) |
+ (enet_byte_addr[3] << 24);
+ enet_addr->top = enet_byte_addr[4] |
+ (enet_byte_addr[5] << 8);
+ return 0;
+ }
+}
+
+static int
+pfe_dev_set_mac_addr(struct rte_eth_dev *dev,
+ struct rte_ether_addr *addr)
+{
+ struct pfe_eth_priv_s *priv = dev->data->dev_private;
+ struct pfe_mac_addr spec_addr;
+ int ret;
+
+ ret = pfe_eth_enet_addr_byte_mac(addr->addr_bytes, &spec_addr);
+ if (ret)
+ return ret;
+
+ gemac_set_laddrN(priv->EMAC_baseaddr,
+ (struct pfe_mac_addr *)&spec_addr, 1);
+ rte_ether_addr_copy(addr, &dev->data->mac_addrs[0]);
+ return 0;
+}
+
+static int
+pfe_stats_get(struct rte_eth_dev *dev,
+ struct rte_eth_stats *stats)
+{
+ struct pfe_eth_priv_s *priv = dev->data->dev_private;
+ struct rte_eth_stats *eth_stats = &priv->stats;
+
+ if (stats == NULL)
+ return -1;
+
+ memset(stats, 0, sizeof(struct rte_eth_stats));
+
+ stats->ipackets = eth_stats->ipackets;
+ stats->ibytes = eth_stats->ibytes;
+ stats->opackets = eth_stats->opackets;
+ stats->obytes = eth_stats->obytes;
+
+ return 0;
+}
+