/** * ixgbe_ptp_hwtstamp_ioctl - control hardware time stamping * @adapter: pointer to adapter struct * @ifreq: ioctl data * @cmd: particular ioctl requested * * Outgoing time stamping can be enabled and disabled. Play nice and * disable it when requested, although it shouldn't case any overhead * when no packet needs it. At most one packet in the queue may be * marked for time stamping, otherwise it would be impossible to tell * for sure to which packet the hardware time stamp belongs. * * Incoming time stamping has to be configured via the hardware * filters. Not all combinations are supported, in particular event * type has to be specified. Matching the kind of event packet is * not supported, with the exception of "all V2 events regardless of * level 2 or 4". */ int ixgbe_ptp_hwtstamp_ioctl(struct ixgbe_adapter *adapter, struct ifreq *ifr, int cmd) { struct ixgbe_hw *hw = &adapter->hw; struct hwtstamp_config config; u32 tsync_tx_ctl = IXGBE_TSYNCTXCTL_ENABLED; u32 tsync_rx_ctl = IXGBE_TSYNCRXCTL_ENABLED; u32 tsync_rx_mtrl = 0; bool is_l4 = false; bool is_l2 = false; u32 regval; if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) return -EFAULT; /* reserved for future extensions */ if (config.flags) return -EINVAL; switch (config.tx_type) { case HWTSTAMP_TX_OFF: tsync_tx_ctl = 0; case HWTSTAMP_TX_ON: break; default: return -ERANGE; } switch (config.rx_filter) { case HWTSTAMP_FILTER_NONE: tsync_rx_ctl = 0; break; case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_L4_V1; tsync_rx_mtrl = IXGBE_RXMTRL_V1_SYNC_MSG; is_l4 = true; break; case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_L4_V1; tsync_rx_mtrl = IXGBE_RXMTRL_V1_DELAY_REQ_MSG; is_l4 = true; break; case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_L2_L4_V2; tsync_rx_mtrl = IXGBE_RXMTRL_V2_SYNC_MSG; is_l2 = true; is_l4 = true; config.rx_filter = HWTSTAMP_FILTER_SOME; break; case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_L2_L4_V2; tsync_rx_mtrl = IXGBE_RXMTRL_V2_DELAY_REQ_MSG; is_l2 = true; is_l4 = true; config.rx_filter = HWTSTAMP_FILTER_SOME; break; case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: case HWTSTAMP_FILTER_PTP_V2_EVENT: tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_EVENT_V2; config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; is_l2 = true; is_l4 = true; break; case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: case HWTSTAMP_FILTER_ALL: default: /* * register RXMTRL must be set, therefore it is not * possible to time stamp both V1 Sync and Delay_Req messages * and hardware does not support timestamping all packets * => return error */ return -ERANGE; } if (hw->mac.type == ixgbe_mac_82598EB) { if (tsync_rx_ctl | tsync_tx_ctl) return -ERANGE; return 0; } /* define ethertype filter for timestamped packets */ if (is_l2) IXGBE_WRITE_REG(hw, IXGBE_ETQF(3), (IXGBE_ETQF_FILTER_EN | /* enable filter */ IXGBE_ETQF_1588 | /* enable timestamping */ ETH_P_1588)); /* 1588 eth protocol type */ else IXGBE_WRITE_REG(hw, IXGBE_ETQF(3), 0); #define PTP_PORT 319 /* L4 Queue Filter[3]: filter by destination port and protocol */ if (is_l4) { u32 ftqf = (IXGBE_FTQF_PROTOCOL_UDP /* UDP */ | IXGBE_FTQF_POOL_MASK_EN /* Pool not compared */ | IXGBE_FTQF_QUEUE_ENABLE); ftqf |= ((IXGBE_FTQF_PROTOCOL_COMP_MASK /* protocol check */ & IXGBE_FTQF_DEST_PORT_MASK /* dest check */ & IXGBE_FTQF_SOURCE_PORT_MASK) /* source check */ << IXGBE_FTQF_5TUPLE_MASK_SHIFT); IXGBE_WRITE_REG(hw, IXGBE_L34T_IMIR(3), (3 << IXGBE_IMIR_RX_QUEUE_SHIFT_82599 | IXGBE_IMIR_SIZE_BP_82599)); /* enable port check */ IXGBE_WRITE_REG(hw, IXGBE_SDPQF(3), (htons(PTP_PORT) | htons(PTP_PORT) << 16)); IXGBE_WRITE_REG(hw, IXGBE_FTQF(3), ftqf); tsync_rx_mtrl |= PTP_PORT << 16; } else { IXGBE_WRITE_REG(hw, IXGBE_FTQF(3), 0); } /* enable/disable TX */ regval = IXGBE_READ_REG(hw, IXGBE_TSYNCTXCTL); regval &= ~IXGBE_TSYNCTXCTL_ENABLED; regval |= tsync_tx_ctl; IXGBE_WRITE_REG(hw, IXGBE_TSYNCTXCTL, regval); /* enable/disable RX */ regval = IXGBE_READ_REG(hw, IXGBE_TSYNCRXCTL); regval &= ~(IXGBE_TSYNCRXCTL_ENABLED | IXGBE_TSYNCRXCTL_TYPE_MASK); regval |= tsync_rx_ctl; IXGBE_WRITE_REG(hw, IXGBE_TSYNCRXCTL, regval); /* define which PTP packets are time stamped */ IXGBE_WRITE_REG(hw, IXGBE_RXMTRL, tsync_rx_mtrl); IXGBE_WRITE_FLUSH(hw); /* clear TX/RX time stamp registers, just to be sure */ regval = IXGBE_READ_REG(hw, IXGBE_TXSTMPH); regval = IXGBE_READ_REG(hw, IXGBE_RXSTMPH); return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? -EFAULT : 0; }
int mg_5tuple_add_HWfilter_ixgbe(uint8_t port_id, uint16_t index, struct rte_5tuple_filter *filter, uint16_t rx_queue) { //printf("add filter: port_id = %u, index = %u, queue = %u\n", port_id, index, rx_queue); //printf("mask = %u, %u, %u, %u, %u\n", filter->dst_ip_mask, filter->src_ip_mask, filter->dst_port_mask, filter->src_port_mask, filter->protocol_mask); //printhex("filter: ", filter, 21); // the following code is merged from dpdk version 1.x and 2.0 // as the version shipped with moongen (1.x) has not yet implemented // support for 5tuple filters on x540 NICs // NOTE: this function overrides most device compatibility checks and assumes // a x540 or similar NIC struct rte_eth_dev *dev; if (port_id >= rte_eth_dev_count()) { PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id); return -ENODEV; } if (filter->protocol != IPPROTO_TCP && filter->tcp_flags != 0){ PMD_DEBUG_TRACE("tcp flags is 0x%x, but the protocol value" " is not TCP\n", filter->tcp_flags); return -EINVAL; } uint8_t protocol = 0x3; switch (filter->protocol){ case IPPROTO_TCP: protocol = 0x0; break; case IPPROTO_UDP: protocol = 0x1; break; case IPPROTO_SCTP: protocol = 0x2; break; } if(filter->tcp_flags != 0){ PMD_DEBUG_TRACE("tcp flags not supported in filter\n"); return -EINVAL; } dev = &rte_eth_devices[port_id]; // I leave this check, as it will sort out some not supported cards... FUNC_PTR_OR_ERR_RET(*dev->dev_ops->add_5tuple_filter, -ENOTSUP); // XXX the following is hard coded network card specific code // this will (hopefully) work for ixgbe cards. // TODO: find a safe way to check, if this code works on the selected NIC // XXX: Best solution would be to write a patch for ixgbe_ethdev.c struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); //struct ixgbe_filter_info *filter_info = // IXGBE_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private); int i; uint32_t ftqf, sdpqf; uint32_t l34timir = 0; uint8_t mask = 0xff; i = index; sdpqf = (uint32_t)(filter->dst_port << IXGBE_SDPQF_DSTPORT_SHIFT); sdpqf = sdpqf | (filter->src_port & IXGBE_SDPQF_SRCPORT); ftqf = (uint32_t)(protocol & IXGBE_FTQF_PROTOCOL_MASK); ftqf |= (uint32_t)((filter->priority & IXGBE_FTQF_PRIORITY_MASK) << IXGBE_FTQF_PRIORITY_SHIFT); if (filter->src_ip_mask == 0) /* 0 means compare. */ mask &= IXGBE_FTQF_SOURCE_ADDR_MASK; if (filter->dst_ip_mask == 0) mask &= IXGBE_FTQF_DEST_ADDR_MASK; if (filter->src_port_mask == 0) mask &= IXGBE_FTQF_SOURCE_PORT_MASK; if (filter->dst_port_mask == 0) mask &= IXGBE_FTQF_DEST_PORT_MASK; if (filter->protocol_mask == 0) mask &= IXGBE_FTQF_PROTOCOL_COMP_MASK; ftqf |= mask << IXGBE_FTQF_5TUPLE_MASK_SHIFT; ftqf |= IXGBE_FTQF_POOL_MASK_EN; ftqf |= IXGBE_FTQF_QUEUE_ENABLE; IXGBE_WRITE_REG(hw, IXGBE_DAQF(i), filter->dst_ip); IXGBE_WRITE_REG(hw, IXGBE_SAQF(i), filter->src_ip); IXGBE_WRITE_REG(hw, IXGBE_SDPQF(i), sdpqf); IXGBE_WRITE_REG(hw, IXGBE_FTQF(i), ftqf); l34timir |= IXGBE_L34T_IMIR_RESERVE; l34timir |= (uint32_t)(rx_queue << IXGBE_L34T_IMIR_QUEUE_SHIFT); IXGBE_WRITE_REG(hw, IXGBE_L34T_IMIR(i), l34timir); return 0; }