Exemple #1
0
/**
 * 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;
}