Commit 5a1bf9ef authored by Dmitry Bezrukov's avatar Dmitry Bezrukov Committed by David S. Miller
Browse files

net: aquantia: rx filters for ptp



We implement HW filter reservation for PTP traffic. Special location
in filters table is marked as reserved, because incoming ptp traffic
should be directed only to PTP designated queue. This way HW will do PTP
timestamping and proper processing.

Co-developed-by: default avatarEgor Pomozov <epomozov@marvell.com>
Signed-off-by: default avatarEgor Pomozov <epomozov@marvell.com>
Co-developed-by: default avatarSergey Samoilenko <sergey.samoilenko@aquantia.com>
Signed-off-by: default avatarSergey Samoilenko <sergey.samoilenko@aquantia.com>
Signed-off-by: default avatarDmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: default avatarIgor Russkikh <igor.russkikh@aquantia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 04a18399
Loading
Loading
Loading
Loading
+11 −6
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2014-2017 aQuantia Corporation. */
/* Copyright (C) 2014-2019 aQuantia Corporation. */

/* File aq_filters.c: RX filters related functions. */

@@ -89,12 +89,14 @@ static int aq_check_approve_fl3l4(struct aq_nic_s *aq_nic,
				  struct aq_hw_rx_fltrs_s *rx_fltrs,
				  struct ethtool_rx_flow_spec *fsp)
{
	u32 last_location = AQ_RX_LAST_LOC_FL3L4 -
			    aq_nic->aq_hw_rx_fltrs.fl3l4.reserved_count;

	if (fsp->location < AQ_RX_FIRST_LOC_FL3L4 ||
	    fsp->location > AQ_RX_LAST_LOC_FL3L4) {
	    fsp->location > last_location) {
		netdev_err(aq_nic->ndev,
			   "ethtool: location must be in range [%d, %d]",
			   AQ_RX_FIRST_LOC_FL3L4,
			   AQ_RX_LAST_LOC_FL3L4);
			   AQ_RX_FIRST_LOC_FL3L4, last_location);
		return -EINVAL;
	}
	if (rx_fltrs->fl3l4.is_ipv6 && rx_fltrs->fl3l4.active_ipv4) {
@@ -124,12 +126,15 @@ aq_check_approve_fl2(struct aq_nic_s *aq_nic,
		     struct aq_hw_rx_fltrs_s *rx_fltrs,
		     struct ethtool_rx_flow_spec *fsp)
{
	u32 last_location = AQ_RX_LAST_LOC_FETHERT -
			    aq_nic->aq_hw_rx_fltrs.fet_reserved_count;

	if (fsp->location < AQ_RX_FIRST_LOC_FETHERT ||
	    fsp->location > AQ_RX_LAST_LOC_FETHERT) {
	    fsp->location > last_location) {
		netdev_err(aq_nic->ndev,
			   "ethtool: location must be in range [%d, %d]",
			   AQ_RX_FIRST_LOC_FETHERT,
			   AQ_RX_LAST_LOC_FETHERT);
			   last_location);
		return -EINVAL;
	}

+44 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include "aq_pci_func.h"
#include "aq_main.h"
#include "aq_ptp.h"
#include "aq_filters.h"

#include <linux/moduleparam.h>
#include <linux/netdevice.h>
@@ -1105,3 +1106,46 @@ void aq_nic_shutdown(struct aq_nic_s *self)
err_exit:
	rtnl_unlock();
}

u8 aq_nic_reserve_filter(struct aq_nic_s *self, enum aq_rx_filter_type type)
{
	u8 location = 0xFF;
	u32 fltr_cnt;
	u32 n_bit;

	switch (type) {
	case aq_rx_filter_ethertype:
		location = AQ_RX_LAST_LOC_FETHERT - AQ_RX_FIRST_LOC_FETHERT -
			   self->aq_hw_rx_fltrs.fet_reserved_count;
		self->aq_hw_rx_fltrs.fet_reserved_count++;
		break;
	case aq_rx_filter_l3l4:
		fltr_cnt = AQ_RX_LAST_LOC_FL3L4 - AQ_RX_FIRST_LOC_FL3L4;
		n_bit = fltr_cnt - self->aq_hw_rx_fltrs.fl3l4.reserved_count;

		self->aq_hw_rx_fltrs.fl3l4.active_ipv4 |= BIT(n_bit);
		self->aq_hw_rx_fltrs.fl3l4.reserved_count++;
		location = n_bit;
		break;
	default:
		break;
	}

	return location;
}

void aq_nic_release_filter(struct aq_nic_s *self, enum aq_rx_filter_type type,
			   u32 location)
{
	switch (type) {
	case aq_rx_filter_ethertype:
		self->aq_hw_rx_fltrs.fet_reserved_count--;
		break;
	case aq_rx_filter_l3l4:
		self->aq_hw_rx_fltrs.fl3l4.reserved_count--;
		self->aq_hw_rx_fltrs.fl3l4.active_ipv4 &= ~BIT(location);
		break;
	default:
		break;
	}
}
+7 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ struct aq_hw_ops;
struct aq_fw_s;
struct aq_vec_s;
struct aq_ptp_s;
enum aq_rx_filter_type;

struct aq_nic_cfg_s {
	const struct aq_hw_caps_s *aq_hw_caps;
@@ -72,6 +73,7 @@ struct aq_hw_rx_fl3l4 {
	u8   active_ipv4;
	u8   active_ipv6:2;
	u8 is_ipv6;
	u8 reserved_count;
};

struct aq_hw_rx_fltrs_s {
@@ -79,6 +81,8 @@ struct aq_hw_rx_fltrs_s {
	u16                   active_filters;
	struct aq_hw_rx_fl2   fl2;
	struct aq_hw_rx_fl3l4 fl3l4;
	/*filter ether type */
	u8 fet_reserved_count;
};

struct aq_nic_s {
@@ -154,5 +158,7 @@ u32 aq_nic_get_fw_version(struct aq_nic_s *self);
int aq_nic_change_pm_state(struct aq_nic_s *self, pm_message_t *pm_msg);
int aq_nic_update_interrupt_moderation_settings(struct aq_nic_s *self);
void aq_nic_shutdown(struct aq_nic_s *self);

u8 aq_nic_reserve_filter(struct aq_nic_s *self, enum aq_rx_filter_type type);
void aq_nic_release_filter(struct aq_nic_s *self, enum aq_rx_filter_type type,
			   u32 location);
#endif /* AQ_NIC_H */
+14 −0
Original line number Diff line number Diff line
@@ -8,12 +8,14 @@
 */

#include <linux/ptp_clock_kernel.h>
#include <linux/ptp_classify.h>
#include <linux/interrupt.h>
#include <linux/clocksource.h>

#include "aq_nic.h"
#include "aq_ptp.h"
#include "aq_ring.h"
#include "aq_filters.h"

#define AQ_PTP_TX_TIMEOUT        (HZ *  10)

@@ -62,6 +64,9 @@ struct aq_ptp_s {
	struct aq_ring_s hwts_rx;

	struct ptp_skb_ring skb_ring;

	struct aq_rx_filter_l3l4 udp_filter;
	struct aq_rx_filter_l2 eth_type_filter;
};

struct ptp_tm_offset {
@@ -933,6 +938,11 @@ int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec)
	aq_ptp_clock_init(aq_nic);
	mutex_unlock(&aq_nic->fwreq_mutex);

	aq_ptp->eth_type_filter.location =
			aq_nic_reserve_filter(aq_nic, aq_rx_filter_ethertype);
	aq_ptp->udp_filter.location =
			aq_nic_reserve_filter(aq_nic, aq_rx_filter_l3l4);

	return 0;

err_exit:
@@ -958,6 +968,10 @@ void aq_ptp_free(struct aq_nic_s *aq_nic)
	if (!aq_ptp)
		return;

	aq_nic_release_filter(aq_nic, aq_rx_filter_ethertype,
			      aq_ptp->eth_type_filter.location);
	aq_nic_release_filter(aq_nic, aq_rx_filter_l3l4,
			      aq_ptp->udp_filter.location);
	/* disable ptp */
	mutex_lock(&aq_nic->fwreq_mutex);
	aq_nic->aq_fw_ops->enable_ptp(aq_nic->aq_hw, 0);
+9 −3
Original line number Diff line number Diff line
@@ -1261,7 +1261,8 @@ static int hw_atl_b0_hw_fl3l4_set(struct aq_hw_s *self,

	hw_atl_b0_hw_fl3l4_clear(self, data);

	if (data->cmd) {
	if (data->cmd & (HW_ATL_RX_ENABLE_CMP_DEST_ADDR_L3 |
			 HW_ATL_RX_ENABLE_CMP_SRC_ADDR_L3)) {
		if (!data->is_ipv6) {
			hw_atl_rpfl3l4_ipv4_dest_addr_set(self,
							  location,
@@ -1278,8 +1279,13 @@ static int hw_atl_b0_hw_fl3l4_set(struct aq_hw_s *self,
							 data->ip_src);
		}
	}

	if (data->cmd & (HW_ATL_RX_ENABLE_CMP_DEST_PORT_L4 |
			 HW_ATL_RX_ENABLE_CMP_SRC_PORT_L4)) {
		hw_atl_rpf_l4_dpd_set(self, data->p_dst, location);
		hw_atl_rpf_l4_spd_set(self, data->p_src, location);
	}

	hw_atl_rpfl3l4_cmd_set(self, location, data->cmd);

	return aq_hw_err_from_flags(self);
Loading