Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8c3beed2 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: emac: Precision Time Protocol (PTP) support"

parents 0b432214 5297107d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -4,4 +4,4 @@

obj-$(CONFIG_MSM_EMAC) += msm_emac.o

msm_emac-objs := emac_main.o emac_hw.o emac_ethtool.o
msm_emac-objs := emac_main.o emac_hw.o emac_ethtool.o emac_ptp.o
+17 −0
Original line number Diff line number Diff line
@@ -86,6 +86,17 @@ enum emac_fc_mode {
	emac_fc_default
};

/* IEEE1588 */
enum emac_ptp_clk_mode {
	emac_ptp_clk_mode_oc_two_step,
	emac_ptp_clk_mode_oc_one_step
};

enum emac_ptp_mode {
	emac_ptp_mode_slave,
	emac_ptp_mode_master
};

struct emac_hw_stats {
	/* rx */
	u64 rx_ok;              /* good packets */
@@ -200,6 +211,11 @@ struct emac_hw {
#define EMAC_HW_FLAG_MULTIALL_EN         2
#define EMAC_HW_FLAG_LOOPBACK_EN         3

#define EMAC_HW_FLAG_PTP_CAP             4
#define EMAC_HW_FLAG_PTP_EN              5
#define EMAC_HW_FLAG_TS_RX_EN            6
#define EMAC_HW_FLAG_TS_TX_EN            7

#define CHK_HW_FLAG(_flag)              CHK_FLAG(hw, HW, _flag)
#define SET_HW_FLAG(_flag)              SET_FLAG(hw, HW, _flag)
#define CLI_HW_FLAG(_flag)              CLI_FLAG(hw, HW, _flag)
@@ -431,6 +447,7 @@ union emac_sw_tpdesc {
		((_que)->tpd.tpdesc + (_size * (_i)))

#define EMAC_TPD_LAST_FRAGMENT  0x80000000
#define EMAC_TPD_TSTAMP_SAVE    0x80000000

/* emac_ring_header represents a single, contiguous block of DMA space
 * mapped for the three descriptor rings (tpd, rfd, rrd)
+72 −0
Original line number Diff line number Diff line
@@ -267,10 +267,82 @@
#define H1TPD_PROD_IDX_SHFT                                           0

/* EMAC_EMAC_WRAPPER_CSR1 */
#define TX_TS_ENABLE                                            0x10000
#define DIS_1588_CLKS                                             0x800
#define FREQ_MODE                                                 0x200
#define ENABLE_RRD_TIMESTAMP                                        0x8

/* EMAC_EMAC_WRAPPER_CSR2 */
#define WOL_EN                                                     0x80

/* EMAC_EMAC_WRAPPER_CSR10 */
#define RD_CLR_1588                                                 0x2
#define DIS_1588                                                    0x1

/* EMAC_EMAC_WRAPPER_TX_TS_INX */
#define EMAC_WRAPPER_TX_TS_EMPTY                             0x80000000
#define EMAC_WRAPPER_TX_TS_INX_BMSK                              0xffff

/* EMAC_P1588_CTRL_REG */
#define ATTACH_EN                                                  0x10
#define BYPASS_O                                                    0x8
#define CLOCK_MODE_BMSK                                             0x6
#define CLOCK_MODE_SHFT                                               1
#define ETH_MODE_SW                                                 0x1

/* EMAC_P1588_INC_VALUE_2 */
#define INC_VALUE_2_BMSK                                         0xffff

/* EMAC_P1588_INC_VALUE_1 */
#define INC_VALUE_1_BMSK                                         0xffff

/* EMAC_P1588_NANO_OFFSET_2 */
#define NANO_OFFSET_2_BMSK                                       0xffff

/* EMAC_P1588_NANO_OFFSET_1 */
#define NANO_OFFSET_1_BMSK                                       0xffff

/* EMAC_P1588_SEC_OFFSET_2 */
#define SEC_OFFSET_2_BMSK                                        0xffff

/* EMAC_P1588_SEC_OFFSET_1 */
#define SEC_OFFSET_1_BMSK                                        0xffff

/* EMAC_P1588_REAL_TIME_5 */
#define REAL_TIME_5_BMSK                                         0xffff
#define REAL_TIME_5_SHFT                                              0

/* EMAC_P1588_REAL_TIME_4 */
#define REAL_TIME_4_BMSK                                         0xffff
#define REAL_TIME_4_SHFT                                              0

/* EMAC_P1588_REAL_TIME_3 */
#define REAL_TIME_3_BMSK                                         0xffff
#define REAL_TIME_3_SHFT                                              0

/* EMAC_P1588_REAL_TIME_2 */
#define REAL_TIME_2_BMSK                                         0xffff
#define REAL_TIME_2_SHFT                                              0

/* EMAC_P1588_REAL_TIME_1 */
#define REAL_TIME_1_BMSK                                         0xffff
#define REAL_TIME_1_SHFT                                              0

/* EMAC_P1588_RTC_EXPANDED_CONFIG */
#define RTC_READ_MODE                                              0x20
#define RTC_SNAPSHOT                                               0x10
#define LOAD_RTC                                                    0x1

/* EMAC_P1588_RTC_PRELOADED_4 */
#define RTC_PRELOADED_4_BMSK                                     0xffff

/* EMAC_P1588_RTC_PRELOADED_3 */
#define RTC_PRELOADED_3_BMSK                                     0xffff

/* EMAC_P1588_RTC_PRELOADED_2 */
#define RTC_PRELOADED_2_BMSK                                     0xffff

/* EMAC_P1588_RTC_PRELOADED_1 */
#define RTC_PRELOADED_1_BMSK                                     0xffff

#endif /* __EMAC_DEFINES_H__ */
+12 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include <linux/if_vlan.h>

#include "emac_hw.h"
#include "emac_ptp.h"

#define RFD_PREF_LOW_TH     0x10
#define RFD_PREF_UP_TH      0x10
@@ -339,6 +340,7 @@ void emac_hw_disable_intr(struct emac_hw *hw)
{
	emac_reg_w32(hw, EMAC, EMAC_INT_STATUS, DIS_INT);
	emac_reg_w32(hw, EMAC, EMAC_INT_MASK, 0);
	emac_reg_w32(hw, EMAC_1588, EMAC_P1588_PTP_EXPANDED_INT_MASK, 0);
	wmb();
}

@@ -777,6 +779,9 @@ void emac_hw_config_mac(struct emac_hw *hw)
	emac_hw_config_rx_ctrl(hw);
	emac_hw_config_dma_ctrl(hw);

	if (CHK_HW_FLAG(PTP_CAP))
		emac_ptp_config(hw);

	val = emac_reg_r32(hw, EMAC, EMAC_AXI_MAST_CTRL);
	val &= ~(DATA_BYTE_SWAP | MAX_BOUND);
	val |= MAX_BTYPE;
@@ -864,6 +869,13 @@ void emac_hw_start_mac(struct emac_hw *hw)
	/* clear all interrupts, set interrupt read clear */
	emac_reg_w32(hw, EMAC, EMAC_DMA_MAS_CTRL, INT_RD_CLR_EN);

	if (CHK_HW_FLAG(PTP_EN)) {
		if (hw->link_speed == EMAC_LINK_SPEED_1GB_FULL)
			emac_ptp_set_linkspeed(hw, emac_mac_speed_1000);
		else
			emac_ptp_set_linkspeed(hw, emac_mac_speed_10_100);
	}

	emac_hw_config_mac_ctrl(hw);

	emac_reg_update32(hw, EMAC, EMAC_ATHR_HEADER_CTRL,
+81 −2
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@

#include "emac.h"
#include "emac_hw.h"
#include "emac_ptp.h"

#define DRV_VERSION "1.0.0.0"

@@ -265,6 +266,19 @@ static void emac_set_tpdesc_lastfrag(struct emac_tx_queue *txque)
	writel_relaxed(tmp_tpd, htpd + 1);
}

void emac_set_tpdesc_tstamp_sav(struct emac_tx_queue *txque)
{
	struct emac_adapter *adpt = netdev_priv(txque->netdev);
	u32 tmp_tpd;
	u32 *htpd = EMAC_TPD(txque, adpt->tpdesc_size,
			     txque->tpd.last_produce_idx);

	tmp_tpd = readl_relaxed(htpd + 3);
	tmp_tpd |= EMAC_TPD_TSTAMP_SAVE;
	writel_relaxed(tmp_tpd, htpd + 3);
	wmb();
}

/* Fill up receive queue's RFD with preallocated receive buffers */
static int emac_refresh_rx_buffer(struct emac_rx_queue *rxque)
{
@@ -345,6 +359,42 @@ static void emac_clean_rfdesc(struct emac_rx_queue *rxque,
	rxque->rfd.process_idx = consume_idx;
}

static void emac_read_tx_tstamp_fifo(struct emac_hw *hw,
				     struct emac_tx_queue *txque)
{
	struct emac_buffer *tpbuf;
	u32 ts_idx = 0;
	u32 sec, ns;

	while (1) {
		ts_idx = emac_reg_r32(hw, EMAC_CSR,
				      EMAC_EMAC_WRAPPER_TX_TS_INX);
		if (ts_idx & EMAC_WRAPPER_TX_TS_EMPTY)
			break;

		ns = emac_reg_r32(hw, EMAC_CSR, EMAC_EMAC_WRAPPER_TX_TS_LO);
		sec = emac_reg_r32(hw, EMAC_CSR, EMAC_EMAC_WRAPPER_TX_TS_HI);

		ts_idx &= EMAC_WRAPPER_TX_TS_INX_BMSK;
		if ((ts_idx < txque->tpd.consume_idx) ||
		    (ts_idx > txque->tpd.last_produce_idx)) {
			emac_warn(hw->adpt, tx_done,
				  "zombie timestamp desc idx %d\n", ts_idx);
			continue;
		}

		tpbuf  = GET_TPD_BUFFER(txque, ts_idx);

		if (tpbuf->skb &&
		    (skb_shinfo(tpbuf->skb)->tx_flags & SKBTX_HW_TSTAMP)) {
			struct skb_shared_hwtstamps ts;

			ts.hwtstamp = ktime_set(sec, ns);
			skb_tstamp_tx(tpbuf->skb, &ts);
		}
	}
}

/* Process receive event */
static void emac_handle_rx(struct emac_adapter *adpt,
			   struct emac_rx_queue *rxque,
@@ -401,6 +451,14 @@ static void emac_handle_rx(struct emac_adapter *adpt,
		skb->ip_summed = CHECKSUM_NONE;
		skb->dev = netdev;
		skb->protocol = eth_type_trans(skb, skb->dev);

		if (CHK_HW_FLAG(TS_RX_EN)) {
			struct skb_shared_hwtstamps *hwts = skb_hwtstamps(skb);

			hwts->hwtstamp = ktime_set(srrd.genr.ts_high,
						   srrd.genr.ts_low);
		}

		emac_receive_skb(rxque, skb, (u16)srrd.genr.cvlan_tag,
				 (bool)srrd.genr.cvlan_flag);

@@ -439,6 +497,7 @@ static void emac_handle_tx(struct emac_adapter *adpt,
		 txque->que_idx, hw_consume_idx);

	while (txque->tpd.consume_idx != hw_consume_idx) {
		emac_read_tx_tstamp_fifo(hw, txque);
		tpbuf = GET_TPD_BUFFER(txque, txque->tpd.consume_idx);
		if (tpbuf->dma) {
			dma_unmap_single(txque->dev, tpbuf->dma, tpbuf->length,
@@ -608,6 +667,7 @@ static void emac_tx_map(struct emac_adapter *adpt,
			struct sk_buff *skb,
			union emac_sw_tpdesc *stpd)
{
	struct emac_hw  *hw = &adpt->hw;
	struct emac_buffer *tpbuf = NULL;
	u16 nr_frags = skb_shinfo(skb)->nr_frags;
	u32 len = skb_headlen(skb);
@@ -628,7 +688,6 @@ static void emac_tx_map(struct emac_adapter *adpt,
		stpd->genr.addr_lo = EMAC_DMA_ADDR_LO(tpbuf->dma);
		stpd->genr.addr_hi = EMAC_DMA_ADDR_HI(tpbuf->dma);
		stpd->genr.buffer_len = tpbuf->length;

		emac_set_tpdesc(txque, stpd);
	}

@@ -663,6 +722,12 @@ static void emac_tx_map(struct emac_adapter *adpt,
	/* The last tpd */
	emac_set_tpdesc_lastfrag(txque);

	if (CHK_HW_FLAG(TS_TX_EN) &&
	    (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
		emac_set_tpdesc_tstamp_sav(txque);
		skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
	}

	/* The last buffer info contain the skb address,
	 * so it will be freed after unmap
	 */
@@ -1385,6 +1450,7 @@ err_alloc_rtx:
static int emac_close(struct net_device *netdev)
{
	struct emac_adapter *adpt = netdev_priv(netdev);
	struct emac_hw *hw = &adpt->hw;

	/* ensure no task is running and no reset is in progress */
	while (CHK_AND_SET_ADPT_FLAG(STATE_RESETTING))
@@ -1395,6 +1461,9 @@ static int emac_close(struct net_device *netdev)
	else
		emac_hw_reset_mac(hw);

	if (CHK_HW_FLAG(PTP_CAP))
		emac_ptp_stop(hw);

	emac_free_all_rtx_descriptor(adpt);

	CLI_ADPT_FLAG(STATE_RESETTING);
@@ -1459,6 +1528,8 @@ static int emac_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
	case SIOCGMIIREG:
	case SIOCSMIIREG:
		return emac_mii_ioctl(netdev, ifr, cmd);
	case SIOCSHWTSTAMP:
		return emac_tstamp_ioctl(netdev, ifr, cmd);
	default:
		return -EOPNOTSUPP;
	}
@@ -1849,6 +1920,9 @@ static void emac_init_adapter(struct emac_adapter *adpt)

	/* phy */
	emac_hw_init_phy(hw);

	if (CHK_HW_FLAG(PTP_CAP))
		emac_ptp_init(hw);
}

#ifdef CONFIG_PM
@@ -2057,7 +2131,7 @@ static int emac_probe(struct platform_device *pdev)
	dma_set_max_seg_size(&pdev->dev, 65536);
	dma_set_seg_boundary(&pdev->dev, 0xffffffff);

	adpt->tstamp_en = false;
	adpt->tstamp_en = true;
	retval = emac_get_resources(pdev, adpt);
	if (retval)
		goto err_res;
@@ -2075,6 +2149,11 @@ static int emac_probe(struct platform_device *pdev)
	adpt->tpdesc_size = EMAC_TPDESC_SIZE;
	adpt->rfdesc_size = EMAC_RFDESC_SIZE;

	if (adpt->tstamp_en) {
		hw->rtc_ref_clkrate = DEFAULT_RTC_REF_CLKRATE;
		SET_HW_FLAG(PTP_CAP);
	}

	/* init netdev */
	netdev->netdev_ops = &emac_netdev_ops;

Loading