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

Commit d93e4093 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'stmmac-optimizations'

Alexandre TORGUE says:

====================
stmmac: enhance driver performances and update the version

According to Giuseppe, I send the v3 series.

This is a subset of patches to rework the driver in order to improve its
performances and make it more robust under stress conditions.

All patches have been ported on STi mainstream kernel branch and
tested on ARM STiH4xx platforms and newer ones.

This series also updates the driver version and prepares it
to include further development to support new chips.

In detail, these patches are:

o to rework and improve the internal DMA bus settings

  Fine tuning is mandatory on some platforms for both
  performance and stability issues.

o to rework and optimize the descriptor management.

  This will help a lot on performance side and preparing
  the inclusion on the GMAC4.x.

o to add a set of optimizations for both xmit and rx functions.

  These will help a lot on performance side and making the driver
  more robust in case of low memory conditions and under some
  stress test, performed for example on IP-STB.

Below some throughput figures obtained on some boxes before and after
the patches.

                       nuttcp (mbps)       iperf (Mbps)
------------------------------------------------------------------
                      tcp     udp          tcp      udp
                   tx   rx   tx  rx      tx   rx   tx  rx
                    ------------------------------------------
   old             680   800 480  506    760  800   600  700
   new             830   880 540  630    840  880   700   800

V2: - rx_copybreak is now managed by using ethtool.
V3: - improve comments on PCIe detailing that there are no regressions
    - rework some APIs to properly define some params as bool as expected
    - rework the formula to get the element inside the ring. Comparing V2,
	patches 4 and 13 have been merged because the same formula have been
	used. After this rework, no evident benefit has been noticed in terms
	of performances so the table above is still valid. Disassembling the
	code for SH4 and ARM, with the new formula just an instr is saved
	(depending on compiler flags) and this gives us not so relevanti gain,
	for example, on SH4 where some instr are executed in the same pipeline
	stage.
	Ring sizes are now fixed and maybe they can be reworked to be tuned
	w/o using stmmaceth= cmdline option. Indeed, nobody change these sizes
	and indeed the numbers selected by default respect the budget and
	avoid to pass invalid setup. These are the best driver default sizes
	for ring and chain.

====================
parents fcb3f55f 3796e44d
Loading
Loading
Loading
Loading
+37 −17
Original line number Diff line number Diff line
@@ -17,7 +17,25 @@ Required properties:
	The 1st cell is reset pre-delay in micro seconds.
	The 2nd cell is reset pulse in micro seconds.
	The 3rd cell is reset post-delay in micro seconds.

Optional properties:
- resets: Should contain a phandle to the STMMAC reset signal, if any
- reset-names: Should contain the reset signal name "stmmaceth", if a
	reset phandle is given
- max-frame-size: See ethernet.txt file in the same directory
- clocks: If present, the first clock should be the GMAC main clock and
  the second clock should be peripheral's register interface clock. Further
  clocks may be specified in derived bindings.
- clock-names: One name for each entry in the clocks property, the
  first one should be "stmmaceth" and the second one should be "pclk".
- clk_ptp_ref: this is the PTP reference clock; in case of the PTP is
  available this clock is used for programming the Timestamp Addend Register.
  If not passed then the system clock will be used and this is fine on some
  platforms.
- tx-fifo-depth: See ethernet.txt file in the same directory
- rx-fifo-depth: See ethernet.txt file in the same directory
- snps,pbl		Programmable Burst Length
- snps,aal		Address-Aligned Beats
- snps,fixed-burst	Program the DMA to use the fixed burst mode
- snps,mixed-burst	Program the DMA to use the mixed burst mode
- snps,force_thresh_dma_mode	Force DMA to use the threshold mode for
@@ -29,27 +47,28 @@ Required properties:
				supported by this device instance
- snps,perfect-filter-entries:	Number of perfect filter entries supported
				by this device instance

Optional properties:
- resets: Should contain a phandle to the STMMAC reset signal, if any
- reset-names: Should contain the reset signal name "stmmaceth", if a
	reset phandle is given
- max-frame-size: See ethernet.txt file in the same directory
- clocks: If present, the first clock should be the GMAC main clock
  The optional second clock should be peripheral's register interface clock.
  The third optional clock should be the ptp reference clock.
  Further clocks may be specified in derived bindings.
- clock-names: One name for each entry in the clocks property.
  The first one should be "stmmaceth".
  The optional second one should be "pclk".
  The optional third one should be "clk_ptp_ref".
- snps,burst_len: The AXI burst lenth value of the AXI BUS MODE register.
- tx-fifo-depth: See ethernet.txt file in the same directory
- rx-fifo-depth: See ethernet.txt file in the same directory
- AXI BUS Mode parameters: below the list of all the parameters to program the
			   AXI register inside the DMA module:
	- snps,lpi_en: enable Low Power Interface
	- snps,xit_frm: unlock on WoL
	- snps,wr_osr_lmt: max write oustanding req. limit
	- snps,rd_osr_lmt: max read oustanding req. limit
	- snps,kbbe: do not cross 1KiB boundary.
	- snps,axi_all: align address
	- snps,blen: this is a vector of supported burst length.
	- snps,fb: fixed-burst
	- snps,mb: mixed-burst
	- snps,rb: rebuild INCRx Burst
- mdio: with compatible = "snps,dwmac-mdio", create and register mdio bus.

Examples:

	stmmac_axi_setup: stmmac-axi-config {
		snps,wr_osr_lmt = <0xf>;
		snps,rd_osr_lmt = <0xf>;
		snps,blen = <256 128 64 32 0 0 0>;
	};

	gmac0: ethernet@e0800000 {
		compatible = "st,spear600-gmac";
		reg = <0xe0800000 0x8000>;
@@ -65,6 +84,7 @@ Examples:
		tx-fifo-depth = <16384>;
		clocks = <&clock>;
		clock-names = "stmmaceth";
		snps,axi-config = <&stmmac_axi_setup>;
		mdio0 {
			#address-cells = <1>;
			#size-cells = <0>;
+23 −14
Original line number Diff line number Diff line
@@ -31,8 +31,7 @@
static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
{
	struct stmmac_priv *priv = (struct stmmac_priv *)p;
	unsigned int txsize = priv->dma_tx_size;
	unsigned int entry = priv->cur_tx % txsize;
	unsigned int entry = priv->cur_tx;
	struct dma_desc *desc = priv->dma_tx + entry;
	unsigned int nopaged_len = skb_headlen(skb);
	unsigned int bmax;
@@ -50,11 +49,14 @@ static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
	if (dma_mapping_error(priv->device, desc->des2))
		return -1;
	priv->tx_skbuff_dma[entry].buf = desc->des2;
	priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum, STMMAC_CHAIN_MODE);
	priv->tx_skbuff_dma[entry].len = bmax;
	/* do not close the descriptor and do not set own bit */
	priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum, STMMAC_CHAIN_MODE,
					0, false);

	while (len != 0) {
		priv->tx_skbuff[entry] = NULL;
		entry = (++priv->cur_tx) % txsize;
		entry = STMMAC_GET_ENTRY(entry, DMA_TX_SIZE);
		desc = priv->dma_tx + entry;

		if (len > bmax) {
@@ -64,9 +66,10 @@ static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
			if (dma_mapping_error(priv->device, desc->des2))
				return -1;
			priv->tx_skbuff_dma[entry].buf = desc->des2;
			priv->tx_skbuff_dma[entry].len = bmax;
			priv->hw->desc->prepare_tx_desc(desc, 0, bmax, csum,
							STMMAC_CHAIN_MODE);
			priv->hw->desc->set_tx_owner(desc);
							STMMAC_CHAIN_MODE, 1,
							false);
			len -= bmax;
			i++;
		} else {
@@ -76,12 +79,17 @@ static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
			if (dma_mapping_error(priv->device, desc->des2))
				return -1;
			priv->tx_skbuff_dma[entry].buf = desc->des2;
			priv->tx_skbuff_dma[entry].len = len;
			/* last descriptor can be set now */
			priv->hw->desc->prepare_tx_desc(desc, 0, len, csum,
							STMMAC_CHAIN_MODE);
			priv->hw->desc->set_tx_owner(desc);
							STMMAC_CHAIN_MODE, 1,
							true);
			len = 0;
		}
	}

	priv->cur_tx = entry;

	return entry;
}

@@ -138,23 +146,24 @@ static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
		 */
		p->des3 = (unsigned int)(priv->dma_rx_phy +
					 (((priv->dirty_rx) + 1) %
					  priv->dma_rx_size) *
					  DMA_RX_SIZE) *
					 sizeof(struct dma_desc));
}

static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p)
{
	struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
	unsigned int entry = priv->dirty_tx;

	if (priv->hw->desc->get_tx_ls(p) && !priv->extend_desc)
	if (priv->tx_skbuff_dma[entry].last_segment && !priv->extend_desc &&
	    priv->hwts_tx_en)
		/* NOTE: Device will overwrite des3 with timestamp value if
		 * 1588-2002 time stamping is enabled, hence reinitialize it
		 * to keep explicit chaining in the descriptor.
		 */
		p->des3 = (unsigned int)(priv->dma_tx_phy +
					 (((priv->dirty_tx + 1) %
					   priv->dma_tx_size) *
					  sizeof(struct dma_desc)));
		p->des3 = (unsigned int)((priv->dma_tx_phy +
					  ((priv->dirty_tx + 1) % DMA_TX_SIZE))
					  * sizeof(struct dma_desc));
}

const struct stmmac_mode_ops chain_mode_ops = {
+27 −12
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@

#include <linux/etherdevice.h>
#include <linux/netdevice.h>
#include <linux/stmmac.h>
#include <linux/phy.h>
#include <linux/module.h>
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
@@ -41,6 +42,10 @@
#define	DWMAC_CORE_3_40	0x34
#define	DWMAC_CORE_3_50	0x35

#define DMA_TX_SIZE 512
#define DMA_RX_SIZE 512
#define STMMAC_GET_ENTRY(x, size)	((x + 1) & (size - 1))

#undef FRAME_FILTER_DEBUG
/* #define FRAME_FILTER_DEBUG */

@@ -95,7 +100,7 @@ struct stmmac_extra_stats {
	unsigned long napi_poll;
	unsigned long tx_normal_irq_n;
	unsigned long tx_clean;
	unsigned long tx_reset_ic_bit;
	unsigned long tx_set_ic_bit;
	unsigned long irq_receive_pmt_irq_n;
	/* MMC info */
	unsigned long mmc_tx_irq_n;
@@ -233,10 +238,19 @@ struct stmmac_extra_stats {

/* Rx IPC status */
enum rx_frame_status {
	good_frame = 0,
	discard_frame = 1,
	csum_none = 2,
	llc_snap = 4,
	good_frame = 0x0,
	discard_frame = 0x1,
	csum_none = 0x2,
	llc_snap = 0x4,
	dma_own = 0x8,
};

/* Tx status */
enum tx_frame_status {
	tx_done = 0x0,
	tx_not_ls = 0x1,
	tx_err = 0x2,
	tx_dma_own = 0x4,
};

enum dma_irq_status {
@@ -332,17 +346,16 @@ struct stmmac_desc_ops {

	/* Invoked by the xmit function to prepare the tx descriptor */
	void (*prepare_tx_desc) (struct dma_desc *p, int is_fs, int len,
				 int csum_flag, int mode);
				 bool csum_flag, int mode, bool tx_own,
				 bool ls);
	/* Set/get the owner of the descriptor */
	void (*set_tx_owner) (struct dma_desc *p);
	int (*get_tx_owner) (struct dma_desc *p);
	/* Invoked by the xmit function to close the tx descriptor */
	void (*close_tx_desc) (struct dma_desc *p);
	/* Clean the tx descriptor as soon as the tx irq is received */
	void (*release_tx_desc) (struct dma_desc *p, int mode);
	/* Clear interrupt on tx frame completion. When this bit is
	 * set an interrupt happens as soon as the frame is transmitted */
	void (*clear_tx_ic) (struct dma_desc *p);
	void (*set_tx_ic)(struct dma_desc *p);
	/* Last tx segment reports the transmit status */
	int (*get_tx_ls) (struct dma_desc *p);
	/* Return the transmit status looking at the TDES1 */
@@ -351,7 +364,6 @@ struct stmmac_desc_ops {
	/* Get the buffer size from the descriptor */
	int (*get_tx_len) (struct dma_desc *p);
	/* Handle extra events on specific interrupts hw dependent */
	int (*get_rx_owner) (struct dma_desc *p);
	void (*set_rx_owner) (struct dma_desc *p);
	/* Get the receive frame size */
	int (*get_rx_frame_len) (struct dma_desc *p, int rx_coe_type);
@@ -376,8 +388,11 @@ extern const struct stmmac_desc_ops ndesc_ops;
/* Specific DMA helpers */
struct stmmac_dma_ops {
	/* DMA core initialization */
	int (*init) (void __iomem *ioaddr, int pbl, int fb, int mb,
		     int burst_len, u32 dma_tx, u32 dma_rx, int atds);
	int (*reset)(void __iomem *ioaddr);
	void (*init)(void __iomem *ioaddr, int pbl, int fb, int mb,
		     int aal, u32 dma_tx, u32 dma_rx, int atds);
	/* Configure the AXI Bus Mode Register */
	void (*axi)(void __iomem *ioaddr, struct stmmac_axi *axi);
	/* Dump DMA registers */
	void (*dump_regs) (void __iomem *ioaddr);
	/* Set tx/rx threshold in the csr6 register
+148 −182
Original line number Diff line number Diff line
/*******************************************************************************
  Header File to describe the DMA descriptors.
  Enhanced descriptors have been in case of DWMAC1000 Cores.
  Header File to describe the DMA descriptors and related definitions.
  This is for DWMAC100 and 1000 cores.

  This program is free software; you can redistribute it and/or modify it
  under the terms and conditions of the GNU General Public License,
@@ -24,198 +24,164 @@
#ifndef __DESCS_H__
#define __DESCS_H__

/* Basic descriptor structure for normal and alternate descriptors */
struct dma_desc {
	/* Receive descriptor */
	union {
		struct {
			/* RDES0 */
			u32 payload_csum_error:1;
			u32 crc_error:1;
			u32 dribbling:1;
			u32 mii_error:1;
			u32 receive_watchdog:1;
			u32 frame_type:1;
			u32 collision:1;
			u32 ipc_csum_error:1;
			u32 last_descriptor:1;
			u32 first_descriptor:1;
			u32 vlan_tag:1;
			u32 overflow_error:1;
			u32 length_error:1;
			u32 sa_filter_fail:1;
			u32 descriptor_error:1;
			u32 error_summary:1;
			u32 frame_length:14;
			u32 da_filter_fail:1;
			u32 own:1;
			/* RDES1 */
			u32 buffer1_size:11;
			u32 buffer2_size:11;
			u32 reserved1:2;
			u32 second_address_chained:1;
			u32 end_ring:1;
			u32 reserved2:5;
			u32 disable_ic:1;

		} rx;
		struct {
#include <linux/bitops.h>

/* Normal receive descriptor defines */

/* RDES0 */
			u32 rx_mac_addr:1;
			u32 crc_error:1;
			u32 dribbling:1;
			u32 error_gmii:1;
			u32 receive_watchdog:1;
			u32 frame_type:1;
			u32 late_collision:1;
			u32 ipc_csum_error:1;
			u32 last_descriptor:1;
			u32 first_descriptor:1;
			u32 vlan_tag:1;
			u32 overflow_error:1;
			u32 length_error:1;
			u32 sa_filter_fail:1;
			u32 descriptor_error:1;
			u32 error_summary:1;
			u32 frame_length:14;
			u32 da_filter_fail:1;
			u32 own:1;
#define	RDES0_PAYLOAD_CSUM_ERR	BIT(0)
#define	RDES0_CRC_ERROR		BIT(1)
#define	RDES0_DRIBBLING		BIT(2)
#define	RDES0_MII_ERROR		BIT(3)
#define	RDES0_RECEIVE_WATCHDOG	BIT(4)
#define	RDES0_FRAME_TYPE	BIT(5)
#define	RDES0_COLLISION		BIT(6)
#define	RDES0_IPC_CSUM_ERROR	BIT(7)
#define	RDES0_LAST_DESCRIPTOR	BIT(8)
#define	RDES0_FIRST_DESCRIPTOR	BIT(9)
#define	RDES0_VLAN_TAG		BIT(10)
#define	RDES0_OVERFLOW_ERROR	BIT(11)
#define	RDES0_LENGTH_ERROR	BIT(12)
#define	RDES0_SA_FILTER_FAIL	BIT(13)
#define	RDES0_DESCRIPTOR_ERROR	BIT(14)
#define	RDES0_ERROR_SUMMARY	BIT(15)
#define	RDES0_FRAME_LEN_MASK	GENMASK(29, 16)
#define RDES0_FRAME_LEN_SHIFT	16
#define	RDES0_DA_FILTER_FAIL	BIT(30)
#define	RDES0_OWN		BIT(31)
			/* RDES1 */
			u32 buffer1_size:13;
			u32 reserved1:1;
			u32 second_address_chained:1;
			u32 end_ring:1;
			u32 buffer2_size:13;
			u32 reserved2:2;
			u32 disable_ic:1;
		} erx;		/* -- enhanced -- */

		/* Transmit descriptor */
		struct {
#define	RDES1_BUFFER1_SIZE_MASK		GENMASK(10, 0)
#define	RDES1_BUFFER2_SIZE_MASK		GENMASK(21, 11)
#define	RDES1_BUFFER2_SIZE_SHIFT	11
#define	RDES1_SECOND_ADDRESS_CHAINED	BIT(24)
#define	RDES1_END_RING			BIT(25)
#define	RDES1_DISABLE_IC		BIT(31)

/* Enhanced receive descriptor defines */

/* RDES0 (similar to normal RDES) */
#define	 ERDES0_RX_MAC_ADDR	BIT(0)

/* RDES1: completely differ from normal desc definitions */
#define	ERDES1_BUFFER1_SIZE_MASK	GENMASK(12, 0)
#define	ERDES1_SECOND_ADDRESS_CHAINED	BIT(14)
#define	ERDES1_END_RING			BIT(15)
#define	ERDES1_BUFFER2_SIZE_MASK	GENMASK(28, 16)
#define ERDES1_BUFFER2_SIZE_SHIFT	16
#define	ERDES1_DISABLE_IC		BIT(31)

/* Normal transmit descriptor defines */
/* TDES0 */
			u32 deferred:1;
			u32 underflow_error:1;
			u32 excessive_deferral:1;
			u32 collision_count:4;
			u32 vlan_frame:1;
			u32 excessive_collisions:1;
			u32 late_collision:1;
			u32 no_carrier:1;
			u32 loss_carrier:1;
			u32 payload_error:1;
			u32 frame_flushed:1;
			u32 jabber_timeout:1;
			u32 error_summary:1;
			u32 ip_header_error:1;
			u32 time_stamp_status:1;
			u32 reserved1:13;
			u32 own:1;
#define	TDES0_DEFERRED			BIT(0)
#define	TDES0_UNDERFLOW_ERROR		BIT(1)
#define	TDES0_EXCESSIVE_DEFERRAL	BIT(2)
#define	TDES0_COLLISION_COUNT_MASK	GENMASK(6, 3)
#define	TDES0_VLAN_FRAME		BIT(7)
#define	TDES0_EXCESSIVE_COLLISIONS	BIT(8)
#define	TDES0_LATE_COLLISION		BIT(9)
#define	TDES0_NO_CARRIER		BIT(10)
#define	TDES0_LOSS_CARRIER		BIT(11)
#define	TDES0_PAYLOAD_ERROR		BIT(12)
#define	TDES0_FRAME_FLUSHED		BIT(13)
#define	TDES0_JABBER_TIMEOUT		BIT(14)
#define	TDES0_ERROR_SUMMARY		BIT(15)
#define	TDES0_IP_HEADER_ERROR		BIT(16)
#define	TDES0_TIME_STAMP_STATUS		BIT(17)
#define	TDES0_OWN			BIT(31)
/* TDES1 */
			u32 buffer1_size:11;
			u32 buffer2_size:11;
			u32 time_stamp_enable:1;
			u32 disable_padding:1;
			u32 second_address_chained:1;
			u32 end_ring:1;
			u32 crc_disable:1;
			u32 checksum_insertion:2;
			u32 first_segment:1;
			u32 last_segment:1;
			u32 interrupt:1;
		} tx;
		struct {
#define	TDES1_BUFFER1_SIZE_MASK		GENMASK(10, 0)
#define	TDES1_BUFFER2_SIZE_MASK		GENMASK(21, 11)
#define	TDES1_BUFFER2_SIZE_SHIFT	11
#define	TDES1_TIME_STAMP_ENABLE		BIT(22)
#define	TDES1_DISABLE_PADDING		BIT(23)
#define	TDES1_SECOND_ADDRESS_CHAINED	BIT(24)
#define	TDES1_END_RING			BIT(25)
#define	TDES1_CRC_DISABLE		BIT(26)
#define	TDES1_CHECKSUM_INSERTION_MASK	GENMASK(28, 27)
#define	TDES1_CHECKSUM_INSERTION_SHIFT	27
#define	TDES1_FIRST_SEGMENT		BIT(29)
#define	TDES1_LAST_SEGMENT		BIT(30)
#define	TDES1_INTERRUPT			BIT(31)

/* Enhanced transmit descriptor defines */
/* TDES0 */
			u32 deferred:1;
			u32 underflow_error:1;
			u32 excessive_deferral:1;
			u32 collision_count:4;
			u32 vlan_frame:1;
			u32 excessive_collisions:1;
			u32 late_collision:1;
			u32 no_carrier:1;
			u32 loss_carrier:1;
			u32 payload_error:1;
			u32 frame_flushed:1;
			u32 jabber_timeout:1;
			u32 error_summary:1;
			u32 ip_header_error:1;
			u32 time_stamp_status:1;
			u32 reserved1:2;
			u32 second_address_chained:1;
			u32 end_ring:1;
			u32 checksum_insertion:2;
			u32 reserved2:1;
			u32 time_stamp_enable:1;
			u32 disable_padding:1;
			u32 crc_disable:1;
			u32 first_segment:1;
			u32 last_segment:1;
			u32 interrupt:1;
			u32 own:1;
#define	ETDES0_DEFERRED			BIT(0)
#define	ETDES0_UNDERFLOW_ERROR		BIT(1)
#define	ETDES0_EXCESSIVE_DEFERRAL	BIT(2)
#define	ETDES0_COLLISION_COUNT_MASK	GENMASK(6, 3)
#define	ETDES0_VLAN_FRAME		BIT(7)
#define	ETDES0_EXCESSIVE_COLLISIONS	BIT(8)
#define	ETDES0_LATE_COLLISION		BIT(9)
#define	ETDES0_NO_CARRIER		BIT(10)
#define	ETDES0_LOSS_CARRIER		BIT(11)
#define	ETDES0_PAYLOAD_ERROR		BIT(12)
#define	ETDES0_FRAME_FLUSHED		BIT(13)
#define	ETDES0_JABBER_TIMEOUT		BIT(14)
#define	ETDES0_ERROR_SUMMARY		BIT(15)
#define	ETDES0_IP_HEADER_ERROR		BIT(16)
#define	ETDES0_TIME_STAMP_STATUS	BIT(17)
#define	ETDES0_SECOND_ADDRESS_CHAINED	BIT(20)
#define	ETDES0_END_RING			BIT(21)
#define	ETDES0_CHECKSUM_INSERTION_MASK	GENMASK(23, 22)
#define	ETDES0_CHECKSUM_INSERTION_SHIFT	22
#define	ETDES0_TIME_STAMP_ENABLE	BIT(25)
#define	ETDES0_DISABLE_PADDING		BIT(26)
#define	ETDES0_CRC_DISABLE		BIT(27)
#define	ETDES0_FIRST_SEGMENT		BIT(28)
#define	ETDES0_LAST_SEGMENT		BIT(29)
#define	ETDES0_INTERRUPT		BIT(30)
#define	ETDES0_OWN			BIT(31)
/* TDES1 */
			u32 buffer1_size:13;
			u32 reserved3:3;
			u32 buffer2_size:13;
			u32 reserved4:3;
		} etx;		/* -- enhanced -- */

		u64 all_flags;
	} des01;
#define	ETDES1_BUFFER1_SIZE_MASK	GENMASK(12, 0)
#define	ETDES1_BUFFER2_SIZE_MASK	GENMASK(28, 16)
#define	ETDES1_BUFFER2_SIZE_SHIFT	16

/* Extended Receive descriptor definitions */
#define	ERDES4_IP_PAYLOAD_TYPE_MASK	GENMASK(2, 6)
#define	ERDES4_IP_HDR_ERR		BIT(3)
#define	ERDES4_IP_PAYLOAD_ERR		BIT(4)
#define	ERDES4_IP_CSUM_BYPASSED		BIT(5)
#define	ERDES4_IPV4_PKT_RCVD		BIT(6)
#define	ERDES4_IPV6_PKT_RCVD		BIT(7)
#define	ERDES4_MSG_TYPE_MASK		GENMASK(11, 8)
#define	ERDES4_PTP_FRAME_TYPE		BIT(12)
#define	ERDES4_PTP_VER			BIT(13)
#define	ERDES4_TIMESTAMP_DROPPED	BIT(14)
#define	ERDES4_AV_PKT_RCVD		BIT(16)
#define	ERDES4_AV_TAGGED_PKT_RCVD	BIT(17)
#define	ERDES4_VLAN_TAG_PRI_VAL_MASK	GENMASK(20, 18)
#define	ERDES4_L3_FILTER_MATCH		BIT(24)
#define	ERDES4_L4_FILTER_MATCH		BIT(25)
#define	ERDES4_L3_L4_FILT_NO_MATCH_MASK	GENMASK(27, 26)

/* Extended RDES4 message type definitions */
#define RDES_EXT_NO_PTP			0
#define RDES_EXT_SYNC			1
#define RDES_EXT_FOLLOW_UP		2
#define RDES_EXT_DELAY_REQ		3
#define RDES_EXT_DELAY_RESP		4
#define RDES_EXT_PDELAY_REQ		5
#define RDES_EXT_PDELAY_RESP		6
#define RDES_EXT_PDELAY_FOLLOW_UP	7

/* Basic descriptor structure for normal and alternate descriptors */
struct dma_desc {
	unsigned int des0;
	unsigned int des1;
	unsigned int des2;
	unsigned int des3;
};

/* Extended descriptor structure (supported by new SYNP GMAC generations) */
/* Extended descriptor structure (e.g. >= databook 3.50a) */
struct dma_extended_desc {
	struct dma_desc basic;
	union {
		struct {
			u32 ip_payload_type:3;
			u32 ip_hdr_err:1;
			u32 ip_payload_err:1;
			u32 ip_csum_bypassed:1;
			u32 ipv4_pkt_rcvd:1;
			u32 ipv6_pkt_rcvd:1;
			u32 msg_type:4;
			u32 ptp_frame_type:1;
			u32 ptp_ver:1;
			u32 timestamp_dropped:1;
			u32 reserved:1;
			u32 av_pkt_rcvd:1;
			u32 av_tagged_pkt_rcvd:1;
			u32 vlan_tag_priority_val:3;
			u32 reserved3:3;
			u32 l3_filter_match:1;
			u32 l4_filter_match:1;
			u32 l3_l4_filter_no_match:2;
			u32 reserved4:4;
		} erx;
		struct {
			u32 reserved;
		} etx;
	} des4;
	struct dma_desc basic;	/* Basic descriptors */
	unsigned int des4;	/* Extended Status */
	unsigned int des5;	/* Reserved */
	unsigned int des6;	/* Tx/Rx Timestamp Low */
	unsigned int des7;	/* Tx/Rx Timestamp High */
};

/* Transmit checksum insertion control */
enum tdes_csum_insertion {
	cic_disabled = 0,	/* Checksum Insertion Control */
	cic_only_ip = 1,	/* Only IP header */
	/* IP header but pseudoheader is not calculated */
	cic_no_pseudoheader = 2,
	cic_full = 3,		/* IP header and pseudoheader */
};

/* Extended RDES4 definitions */
#define RDES_EXT_NO_PTP			0
#define RDES_EXT_SYNC			0x1
#define RDES_EXT_FOLLOW_UP		0x2
#define RDES_EXT_DELAY_REQ		0x3
#define RDES_EXT_DELAY_RESP		0x4
#define RDES_EXT_PDELAY_REQ		0x5
#define RDES_EXT_PDELAY_RESP		0x6
#define RDES_EXT_PDELAY_FOLLOW_UP	0x7
#define	TX_CIC_FULL	3	/* Include IP header and pseudoheader */

#endif /* __DESCS_H__ */
+34 −43
Original line number Diff line number Diff line
@@ -35,100 +35,91 @@
/* Enhanced descriptors */
static inline void ehn_desc_rx_set_on_ring(struct dma_desc *p, int end)
{
	p->des01.erx.buffer2_size = BUF_SIZE_8KiB - 1;
	if (end)
		p->des01.erx.end_ring = 1;
}
	p->des1 |= ((BUF_SIZE_8KiB - 1) << ERDES1_BUFFER2_SIZE_SHIFT)
		   & ERDES1_BUFFER2_SIZE_MASK;

static inline void ehn_desc_tx_set_on_ring(struct dma_desc *p, int end)
{
	if (end)
		p->des01.etx.end_ring = 1;
		p->des1 |= ERDES1_END_RING;
}

static inline void enh_desc_end_tx_desc_on_ring(struct dma_desc *p, int ter)
static inline void enh_desc_end_tx_desc_on_ring(struct dma_desc *p, int end)
{
	p->des01.etx.end_ring = ter;
	if (end)
		p->des0 |= ETDES0_END_RING;
	else
		p->des0 &= ~ETDES0_END_RING;
}

static inline void enh_set_tx_desc_len_on_ring(struct dma_desc *p, int len)
{
	if (unlikely(len > BUF_SIZE_4KiB)) {
		p->des01.etx.buffer1_size = BUF_SIZE_4KiB;
		p->des01.etx.buffer2_size = len - BUF_SIZE_4KiB;
		p->des1 |= (((len - BUF_SIZE_4KiB) << ETDES1_BUFFER2_SIZE_SHIFT)
			    & ETDES1_BUFFER2_SIZE_MASK) | (BUF_SIZE_4KiB
			    & ETDES1_BUFFER1_SIZE_MASK);
	} else
		p->des01.etx.buffer1_size = len;
		p->des1 |= (len & ETDES1_BUFFER1_SIZE_MASK);
}

/* Normal descriptors */
static inline void ndesc_rx_set_on_ring(struct dma_desc *p, int end)
{
	p->des01.rx.buffer2_size = BUF_SIZE_2KiB - 1;
	if (end)
		p->des01.rx.end_ring = 1;
}
	p->des1 |= ((BUF_SIZE_2KiB - 1) << RDES1_BUFFER2_SIZE_SHIFT)
		    & RDES1_BUFFER2_SIZE_MASK;

static inline void ndesc_tx_set_on_ring(struct dma_desc *p, int end)
{
	if (end)
		p->des01.tx.end_ring = 1;
		p->des1 |= RDES1_END_RING;
}

static inline void ndesc_end_tx_desc_on_ring(struct dma_desc *p, int ter)
static inline void ndesc_end_tx_desc_on_ring(struct dma_desc *p, int end)
{
	p->des01.tx.end_ring = ter;
	if (end)
		p->des1 |= TDES1_END_RING;
	else
		p->des1 &= ~TDES1_END_RING;
}

static inline void norm_set_tx_desc_len_on_ring(struct dma_desc *p, int len)
{
	if (unlikely(len > BUF_SIZE_2KiB)) {
		p->des01.etx.buffer1_size = BUF_SIZE_2KiB - 1;
		p->des01.etx.buffer2_size = len - p->des01.etx.buffer1_size;
		unsigned int buffer1 = (BUF_SIZE_2KiB - 1)
					& TDES1_BUFFER1_SIZE_MASK;
		p->des1 |= ((((len - buffer1) << TDES1_BUFFER2_SIZE_SHIFT)
			    & TDES1_BUFFER2_SIZE_MASK) | buffer1);
	} else
		p->des01.tx.buffer1_size = len;
		p->des1 |= (len & TDES1_BUFFER1_SIZE_MASK);
}

/* Specific functions used for Chain mode */

/* Enhanced descriptors */
static inline void ehn_desc_rx_set_on_chain(struct dma_desc *p, int end)
{
	p->des01.erx.second_address_chained = 1;
}

static inline void ehn_desc_tx_set_on_chain(struct dma_desc *p, int end)
static inline void ehn_desc_rx_set_on_chain(struct dma_desc *p)
{
	p->des01.etx.second_address_chained = 1;
	p->des1 |= ERDES1_SECOND_ADDRESS_CHAINED;
}

static inline void enh_desc_end_tx_desc_on_chain(struct dma_desc *p, int ter)
static inline void enh_desc_end_tx_desc_on_chain(struct dma_desc *p)
{
	p->des01.etx.second_address_chained = 1;
	p->des0 |= ETDES0_SECOND_ADDRESS_CHAINED;
}

static inline void enh_set_tx_desc_len_on_chain(struct dma_desc *p, int len)
{
	p->des01.etx.buffer1_size = len;
	p->des1 |= (len & ETDES1_BUFFER1_SIZE_MASK);
}

/* Normal descriptors */
static inline void ndesc_rx_set_on_chain(struct dma_desc *p, int end)
{
	p->des01.rx.second_address_chained = 1;
}

static inline void ndesc_tx_set_on_chain(struct dma_desc *p, int ring_size)
{
	p->des01.tx.second_address_chained = 1;
	p->des1 |= RDES1_SECOND_ADDRESS_CHAINED;
}

static inline void ndesc_end_tx_desc_on_chain(struct dma_desc *p, int ter)
static inline void ndesc_tx_set_on_chain(struct dma_desc *p)
{
	p->des01.tx.second_address_chained = 1;
	p->des1 |= TDES1_SECOND_ADDRESS_CHAINED;
}

static inline void norm_set_tx_desc_len_on_chain(struct dma_desc *p, int len)
{
	p->des01.tx.buffer1_size = len;
	p->des1 |= len & TDES1_BUFFER1_SIZE_MASK;
}
#endif /* __DESC_COM_H__ */
Loading