Commit c24602ef authored by Giuseppe CAVALLARO's avatar Giuseppe CAVALLARO Committed by David S. Miller
Browse files

stmmac: support extend descriptors



This patch is to support the extend descriptors available
in the chips newer than the 3.50.

In case of the extend descriptors cannot be supported,
at runtime, the driver will continue to work using the old style.

In detail, this support extends the main descriptor structure
adding new descriptors: 4, 5, 6, 7. The desc4 gives us extra
information about the received ethernet payload when it is
carrying PTP packets or TCP/UDP/ICMP over IP packets.
The descriptors 6 and 7 are used for saving HW L/H timestamps (PTP).

V2: this new version removes the Koption added in the first implementation
because all the checks now to verify if the extended descriptors are
actually supported happen at probe time.
Signed-off-by: default avatarGiuseppe Cavallaro <peppe.cavallaro@st.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4a7d666a
......@@ -89,27 +89,38 @@ static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc)
return ret;
}
static void stmmac_init_dma_chain(struct dma_desc *des, dma_addr_t phy_addr,
unsigned int size)
static void stmmac_init_dma_chain(void *des, dma_addr_t phy_addr,
unsigned int size, unsigned int extend_desc)
{
/*
* In chained mode the des3 points to the next element in the ring.
* The latest element has to point to the head.
*/
int i;
struct dma_desc *p = des;
dma_addr_t dma_phy = phy_addr;
for (i = 0; i < (size - 1); i++) {
dma_phy += sizeof(struct dma_desc);
p->des3 = (unsigned int)dma_phy;
p++;
if (extend_desc) {
struct dma_extended_desc *p = (struct dma_extended_desc *) des;
for (i = 0; i < (size - 1); i++) {
dma_phy += sizeof(struct dma_extended_desc);
p->basic.des3 = (unsigned int)dma_phy;
p++;
}
p->basic.des3 = (unsigned int)phy_addr;
} else {
struct dma_desc *p = (struct dma_desc *) des;
for (i = 0; i < (size - 1); i++) {
dma_phy += sizeof(struct dma_desc);
p->des3 = (unsigned int)dma_phy;
p++;
}
p->des3 = (unsigned int)phy_addr;
}
p->des3 = (unsigned int)phy_addr;
}
const struct stmmac_chain_mode_ops chain_mode_ops = {
.init = stmmac_init_dma_chain,
.is_jumbo_frm = stmmac_is_jumbo_frm,
.jumbo_frm = stmmac_jumbo_frm,
.init_dma_chain = stmmac_init_dma_chain,
};
......@@ -117,6 +117,29 @@ struct stmmac_extra_stats {
unsigned long irq_rx_path_in_lpi_mode_n;
unsigned long irq_rx_path_exit_lpi_mode_n;
unsigned long phy_eee_wakeup_error_n;
/* Extended RDES status */
unsigned long ip_hdr_err;
unsigned long ip_payload_err;
unsigned long ip_csum_bypassed;
unsigned long ipv4_pkt_rcvd;
unsigned long ipv6_pkt_rcvd;
unsigned long rx_msg_type_ext_no_ptp;
unsigned long rx_msg_type_sync;
unsigned long rx_msg_type_follow_up;
unsigned long rx_msg_type_delay_req;
unsigned long rx_msg_type_delay_resp;
unsigned long rx_msg_type_pdelay_req;
unsigned long rx_msg_type_pdelay_resp;
unsigned long rx_msg_type_pdelay_follow_up;
unsigned long ptp_frame_type;
unsigned long ptp_ver;
unsigned long timestamp_dropped;
unsigned long av_pkt_rcvd;
unsigned long av_tagged_pkt_rcvd;
unsigned long vlan_tag_priority_val;
unsigned long l3_filter_match;
unsigned long l4_filter_match;
unsigned long l3_l4_filter_no_match;
};
/* CSR Frequency Access Defines*/
......@@ -260,11 +283,10 @@ struct dma_features {
struct stmmac_desc_ops {
/* DMA RX descriptor ring initialization */
void (*init_rx_desc) (struct dma_desc *p, unsigned int ring_size,
int disable_rx_ic, int mode);
void (*init_rx_desc) (struct dma_desc *p, int disable_rx_ic, int mode,
int end);
/* DMA TX descriptor ring initialization */
void (*init_tx_desc) (struct dma_desc *p, unsigned int ring_size,
int mode);
void (*init_tx_desc) (struct dma_desc *p, int mode, int end);
/* Invoked by the xmit function to prepare the tx descriptor */
void (*prepare_tx_desc) (struct dma_desc *p, int is_fs, int len,
......@@ -294,12 +316,14 @@ struct stmmac_desc_ops {
/* Return the reception status looking at the RDES1 */
int (*rx_status) (void *data, struct stmmac_extra_stats *x,
struct dma_desc *p);
void (*rx_extended_status) (void *data, struct stmmac_extra_stats *x,
struct dma_extended_desc *p);
};
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 burst_len, u32 dma_tx, u32 dma_rx, int atds);
/* Dump DMA registers */
void (*dump_regs) (void __iomem *ioaddr);
/* Set tx/rx threshold in the csr6 register
......@@ -371,10 +395,10 @@ struct stmmac_ring_mode_ops {
};
struct stmmac_chain_mode_ops {
void (*init) (void *des, dma_addr_t phy_addr, unsigned int size,
unsigned int extend_desc);
unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
void (*init_dma_chain) (struct dma_desc *des, dma_addr_t phy_addr,
unsigned int size);
};
struct mac_device_info {
......
......@@ -24,6 +24,7 @@
#ifndef __DESCS_H__
#define __DESCS_H__
/* Basic descriptor structure for normal and alternate descriptors */
struct dma_desc {
/* Receive descriptor */
union {
......@@ -60,7 +61,7 @@ struct dma_desc {
} rx;
struct {
/* RDES0 */
u32 payload_csum_error:1;
u32 rx_mac_addr:1;
u32 crc_error:1;
u32 dribbling:1;
u32 error_gmii:1;
......@@ -162,13 +163,57 @@ struct dma_desc {
unsigned int des3;
};
/* Extended descriptor structure (supported by new SYNP GMAC generations) */
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;
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 */
cic_no_pseudoheader = 2, /* IP header but pseudoheader
* is not calculated */
/* 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
#endif /* __DESCS_H__ */
......@@ -155,6 +155,7 @@ enum inter_frame_gap {
/* Programmable burst length (passed thorugh platform)*/
#define DMA_BUS_MODE_PBL_MASK 0x00003f00 /* Programmable Burst Len */
#define DMA_BUS_MODE_PBL_SHIFT 8
#define DMA_BUS_MODE_ATDS 0x00000080 /* Alternate Descriptor Size */
enum rx_tx_priority_ratio {
double_ratio = 0x00004000, /*2:1 */
......
......@@ -30,8 +30,8 @@
#include "dwmac1000.h"
#include "dwmac_dma.h"
static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb,
int mb, int burst_len, u32 dma_tx, u32 dma_rx)
static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
int burst_len, u32 dma_tx, u32 dma_rx, int atds)
{
u32 value = readl(ioaddr + DMA_BUS_MODE);
int limit;
......@@ -73,6 +73,10 @@ static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb,
#ifdef CONFIG_STMMAC_DA
value |= DMA_BUS_MODE_DA; /* Rx has priority over tx */
#endif
if (atds)
value |= DMA_BUS_MODE_ATDS;
writel(value, ioaddr + DMA_BUS_MODE);
/* In case of GMAC AXI configuration, program the DMA_AXI_BUS_MODE
......
......@@ -32,8 +32,8 @@
#include "dwmac100.h"
#include "dwmac_dma.h"
static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, int fb,
int mb, int burst_len, u32 dma_tx, u32 dma_rx)
static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
int burst_len, u32 dma_tx, u32 dma_rx, int atds)
{
u32 value = readl(ioaddr + DMA_BUS_MODE);
int limit;
......
......@@ -150,6 +150,57 @@ static int enh_desc_coe_rdes0(int ipc_err, int type, int payload_err)
return ret;
}
static void enh_desc_get_ext_status(void *data, struct stmmac_extra_stats *x,
struct dma_extended_desc *p)
{
if (unlikely(p->basic.des01.erx.rx_mac_addr)) {
if (p->des4.erx.ip_hdr_err)
x->ip_hdr_err++;
if (p->des4.erx.ip_payload_err)
x->ip_payload_err++;
if (p->des4.erx.ip_csum_bypassed)
x->ip_csum_bypassed++;
if (p->des4.erx.ipv4_pkt_rcvd)
x->ipv4_pkt_rcvd++;
if (p->des4.erx.ipv6_pkt_rcvd)
x->ipv6_pkt_rcvd++;
if (p->des4.erx.msg_type == RDES_EXT_SYNC)
x->rx_msg_type_sync++;
else if (p->des4.erx.msg_type == RDES_EXT_FOLLOW_UP)
x->rx_msg_type_follow_up++;
else if (p->des4.erx.msg_type == RDES_EXT_DELAY_REQ)
x->rx_msg_type_delay_req++;
else if (p->des4.erx.msg_type == RDES_EXT_DELAY_RESP)
x->rx_msg_type_delay_resp++;
else if (p->des4.erx.msg_type == RDES_EXT_DELAY_REQ)
x->rx_msg_type_pdelay_req++;
else if (p->des4.erx.msg_type == RDES_EXT_PDELAY_RESP)
x->rx_msg_type_pdelay_resp++;
else if (p->des4.erx.msg_type == RDES_EXT_PDELAY_FOLLOW_UP)
x->rx_msg_type_pdelay_follow_up++;
else
x->rx_msg_type_ext_no_ptp++;
if (p->des4.erx.ptp_frame_type)
x->ptp_frame_type++;
if (p->des4.erx.ptp_ver)
x->ptp_ver++;
if (p->des4.erx.timestamp_dropped)
x->timestamp_dropped++;
if (p->des4.erx.av_pkt_rcvd)
x->av_pkt_rcvd++;
if (p->des4.erx.av_tagged_pkt_rcvd)
x->av_tagged_pkt_rcvd++;
if (p->des4.erx.vlan_tag_priority_val)
x->vlan_tag_priority_val++;
if (p->des4.erx.l3_filter_match)
x->l3_filter_match++;
if (p->des4.erx.l4_filter_match)
x->l4_filter_match++;
if (p->des4.erx.l3_l4_filter_no_match)
x->l3_l4_filter_no_match++;
}
}
static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
struct dma_desc *p)
{
......@@ -198,7 +249,7 @@ static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
* At any rate, we need to understand if the CSUM hw computation is ok
* and report this info to the upper layers. */
ret = enh_desc_coe_rdes0(p->des01.erx.ipc_csum_error,
p->des01.erx.frame_type, p->des01.erx.payload_csum_error);
p->des01.erx.frame_type, p->des01.erx.rx_mac_addr);
if (unlikely(p->des01.erx.dribbling)) {
CHIP_DBG(KERN_ERR "GMAC RX: dribbling error\n");
......@@ -225,41 +276,32 @@ static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
x->rx_vlan++;
}
#endif
return ret;
}
static void enh_desc_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
int disable_rx_ic, int mode)
static void enh_desc_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
int mode, int end)
{
int i;
for (i = 0; i < ring_size; i++) {
p->des01.erx.own = 1;
p->des01.erx.buffer1_size = BUF_SIZE_8KiB - 1;
p->des01.erx.own = 1;
p->des01.erx.buffer1_size = BUF_SIZE_8KiB - 1;
if (mode == STMMAC_CHAIN_MODE)
ehn_desc_rx_set_on_chain(p, (i == ring_size - 1));
else
ehn_desc_rx_set_on_ring(p, (i == ring_size - 1));
if (mode == STMMAC_CHAIN_MODE)
ehn_desc_rx_set_on_chain(p, end);
else
ehn_desc_rx_set_on_ring(p, end);
if (disable_rx_ic)
p->des01.erx.disable_ic = 1;
p++;
}
if (disable_rx_ic)
p->des01.erx.disable_ic = 1;
}
static void enh_desc_init_tx_desc(struct dma_desc *p, unsigned int ring_size,
int mode)
static void enh_desc_init_tx_desc(struct dma_desc *p, int mode, int end)
{
int i;
for (i = 0; i < ring_size; i++) {
p->des01.etx.own = 0;
if (mode == STMMAC_CHAIN_MODE)
ehn_desc_tx_set_on_chain(p, (i == ring_size - 1));
else
ehn_desc_tx_set_on_ring(p, (i == ring_size - 1));
p++;
}
p->des01.etx.own = 0;
if (mode == STMMAC_CHAIN_MODE)
ehn_desc_tx_set_on_chain(p, end);
else
ehn_desc_tx_set_on_ring(p, end);
}
static int enh_desc_get_tx_owner(struct dma_desc *p)
......@@ -352,4 +394,5 @@ const struct stmmac_desc_ops enh_desc_ops = {
.set_tx_owner = enh_desc_set_tx_owner,
.set_rx_owner = enh_desc_set_rx_owner,
.get_rx_frame_len = enh_desc_get_rx_frame_len,
.rx_extended_status = enh_desc_get_ext_status,
};
......@@ -122,37 +122,28 @@ static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
return ret;
}
static void ndesc_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
int disable_rx_ic, int mode)
static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode,
int end)
{
int i;
for (i = 0; i < ring_size; i++) {
p->des01.rx.own = 1;
p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;
if (mode == STMMAC_CHAIN_MODE)
ndesc_rx_set_on_chain(p, (i == ring_size - 1));
else
ndesc_rx_set_on_ring(p, (i == ring_size - 1));
if (disable_rx_ic)
p->des01.rx.disable_ic = 1;
p++;
}
p->des01.rx.own = 1;
p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;
if (mode == STMMAC_CHAIN_MODE)
ndesc_rx_set_on_chain(p, end);
else
ndesc_rx_set_on_ring(p, end);
if (disable_rx_ic)
p->des01.rx.disable_ic = 1;
}
static void ndesc_init_tx_desc(struct dma_desc *p, unsigned int ring_size,
int mode)
static void ndesc_init_tx_desc(struct dma_desc *p, int mode, int end)
{
int i;
for (i = 0; i < ring_size; i++) {
p->des01.tx.own = 0;
if (mode == STMMAC_CHAIN_MODE)
ndesc_tx_set_on_chain(p, (i == (ring_size - 1)));
else
ndesc_tx_set_on_ring(p, (i == (ring_size - 1)));
p++;
}
p->des01.tx.own = 0;
if (mode == STMMAC_CHAIN_MODE)
ndesc_tx_set_on_chain(p, end);
else
ndesc_tx_set_on_ring(p, end);
}
static int ndesc_get_tx_owner(struct dma_desc *p)
......
......@@ -34,7 +34,8 @@
struct stmmac_priv {
/* Frequently used values are kept adjacent for cache effect */
struct dma_desc *dma_tx ____cacheline_aligned;
struct dma_desc *dma_tx ____cacheline_aligned; /* Basic TX desc */
struct dma_extended_desc *dma_etx; /* Extended TX descriptor */
dma_addr_t dma_tx_phy;
struct sk_buff **tx_skbuff;
unsigned int cur_tx;
......@@ -42,7 +43,8 @@ struct stmmac_priv {
unsigned int dma_tx_size;
int tx_coalesce;
struct dma_desc *dma_rx ;
struct dma_desc *dma_rx; /* Basic RX descriptor */
struct dma_extended_desc *dma_erx; /* Extended RX descriptor */
unsigned int cur_rx;
unsigned int dirty_rx;
struct sk_buff **rx_skbuff;
......@@ -94,6 +96,7 @@ struct stmmac_priv {
int use_riwt;
u32 rx_riwt;
unsigned int mode;
int extend_desc;
};
extern int phyaddr;
......
......@@ -108,6 +108,29 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
STMMAC_STAT(irq_rx_path_in_lpi_mode_n),
STMMAC_STAT(irq_rx_path_exit_lpi_mode_n),
STMMAC_STAT(phy_eee_wakeup_error_n),
/* Extended RDES status */
STMMAC_STAT(ip_hdr_err),
STMMAC_STAT(ip_payload_err),
STMMAC_STAT(ip_csum_bypassed),
STMMAC_STAT(ipv4_pkt_rcvd),
STMMAC_STAT(ipv6_pkt_rcvd),
STMMAC_STAT(rx_msg_type_ext_no_ptp),
STMMAC_STAT(rx_msg_type_sync),
STMMAC_STAT(rx_msg_type_follow_up),
STMMAC_STAT(rx_msg_type_delay_req),
STMMAC_STAT(rx_msg_type_delay_resp),
STMMAC_STAT(rx_msg_type_pdelay_req),
STMMAC_STAT(rx_msg_type_pdelay_resp),
STMMAC_STAT(rx_msg_type_pdelay_follow_up),
STMMAC_STAT(ptp_frame_type),
STMMAC_STAT(ptp_ver),
STMMAC_STAT(timestamp_dropped),
STMMAC_STAT(av_pkt_rcvd),
STMMAC_STAT(av_tagged_pkt_rcvd),
STMMAC_STAT(vlan_tag_priority_val),
STMMAC_STAT(l3_filter_match),
STMMAC_STAT(l4_filter_match),
STMMAC_STAT(l3_l4_filter_no_match),
};
#define STMMAC_STATS_LEN ARRAY_SIZE(stmmac_gstrings_stats)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment