aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGiuseppe CAVALLARO <peppe.cavallaro@st.com>2011-10-17 20:01:24 -0400
committerDavid S. Miller <davem@davemloft.net>2011-10-19 19:24:18 -0400
commit286a837217204b1ef105e3a554d0757e4fdfaac1 (patch)
tree466ed6dbe1e6281173adc57cf09a40e86f0c80fd
parent38fe7a93fc734357c4811f1c710b1906a87d315c (diff)
stmmac: add CHAINED descriptor mode support (V4)
This patch enhances the STMMAC driver to support CHAINED mode of descriptor. STMMAC supports DMA descriptor to operate both in dual buffer(RING) and linked-list(CHAINED) mode. In RING mode (default) each descriptor points to two data buffer pointers whereas in CHAINED mode they point to only one data buffer pointer. In CHAINED mode each descriptor will have pointer to next descriptor in the list, hence creating the explicit chaining in the descriptor itself, whereas such explicit chaining is not possible in RING mode. First version of this work has been done by Rayagond. Then the patch has been reworked avoiding ifdef inside the C code. A new header file has been added to define all the functions needed for managing enhanced and normal descriptors. In fact, these have to be specialized according to the ring/chain usage. Two new C files have been also added to implement the helper routines needed to manage: jumbo frames, chain and ring setup (i.e. desc3). Signed-off-by: Rayagond Kokatanur <rayagond@vayavyalabs.com> Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Kconfig18
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Makefile2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/chain_mode.c137
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/common.h13
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/descs_com.h126
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/enh_desc.c22
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/norm_desc.c20
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/ring_mode.c126
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac.h2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c130
10 files changed, 491 insertions, 105 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index 8cd9ddec05a0..ac6f190743dd 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -63,4 +63,22 @@ config STMMAC_RTC_TIMER
63 63
64endchoice 64endchoice
65 65
66choice
67 prompt "Select the DMA TX/RX descriptor operating modes"
68 depends on STMMAC_ETH
69 ---help---
70 This driver supports DMA descriptor to operate both in dual buffer
71 (RING) and linked-list(CHAINED) mode. In RING mode each descriptor
72 points to two data buffer pointers whereas in CHAINED mode they
73 points to only one data buffer pointer.
74
75config STMMAC_RING
76 bool "Enable Descriptor Ring Mode"
77
78config STMMAC_CHAINED
79 bool "Enable Descriptor Chained Mode"
80
81endchoice
82
83
66endif 84endif
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index 0f23d95746b7..d7c45164ea79 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -1,5 +1,7 @@
1obj-$(CONFIG_STMMAC_ETH) += stmmac.o 1obj-$(CONFIG_STMMAC_ETH) += stmmac.o
2stmmac-$(CONFIG_STMMAC_TIMER) += stmmac_timer.o 2stmmac-$(CONFIG_STMMAC_TIMER) += stmmac_timer.o
3stmmac-$(CONFIG_STMMAC_RING) += ring_mode.o
4stmmac-$(CONFIG_STMMAC_CHAINED) += chain_mode.o
3stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o \ 5stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o \
4 dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \ 6 dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \
5 dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \ 7 dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \
diff --git a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
new file mode 100644
index 000000000000..0668659803ed
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
@@ -0,0 +1,137 @@
1/*******************************************************************************
2 Specialised functions for managing Chained mode
3
4 Copyright(C) 2011 STMicroelectronics Ltd
5
6 It defines all the functions used to handle the normal/enhanced
7 descriptors in case of the DMA is configured to work in chained or
8 in ring mode.
9
10 This program is free software; you can redistribute it and/or modify it
11 under the terms and conditions of the GNU General Public License,
12 version 2, as published by the Free Software Foundation.
13
14 This program is distributed in the hope it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 more details.
18
19 You should have received a copy of the GNU General Public License along with
20 this program; if not, write to the Free Software Foundation, Inc.,
21 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
22
23 The full GNU General Public License is included in this distribution in
24 the file called "COPYING".
25
26 Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
27*******************************************************************************/
28
29#include "stmmac.h"
30
31unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
32{
33 struct stmmac_priv *priv = (struct stmmac_priv *) p;
34 unsigned int txsize = priv->dma_tx_size;
35 unsigned int entry = priv->cur_tx % txsize;
36 struct dma_desc *desc = priv->dma_tx + entry;
37 unsigned int nopaged_len = skb_headlen(skb);
38 unsigned int bmax;
39 unsigned int i = 1, len;
40
41 if (priv->plat->enh_desc)
42 bmax = BUF_SIZE_8KiB;
43 else
44 bmax = BUF_SIZE_2KiB;
45
46 len = nopaged_len - bmax;
47
48 desc->des2 = dma_map_single(priv->device, skb->data,
49 bmax, DMA_TO_DEVICE);
50 priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum);
51
52 while (len != 0) {
53 entry = (++priv->cur_tx) % txsize;
54 desc = priv->dma_tx + entry;
55
56 if (len > bmax) {
57 desc->des2 = dma_map_single(priv->device,
58 (skb->data + bmax * i),
59 bmax, DMA_TO_DEVICE);
60 priv->hw->desc->prepare_tx_desc(desc, 0, bmax,
61 csum);
62 priv->hw->desc->set_tx_owner(desc);
63 priv->tx_skbuff[entry] = NULL;
64 len -= bmax;
65 i++;
66 } else {
67 desc->des2 = dma_map_single(priv->device,
68 (skb->data + bmax * i), len,
69 DMA_TO_DEVICE);
70 priv->hw->desc->prepare_tx_desc(desc, 0, len,
71 csum);
72 priv->hw->desc->set_tx_owner(desc);
73 priv->tx_skbuff[entry] = NULL;
74 len = 0;
75 }
76 }
77 return entry;
78}
79
80static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc)
81{
82 unsigned int ret = 0;
83
84 if ((enh_desc && (len > BUF_SIZE_8KiB)) ||
85 (!enh_desc && (len > BUF_SIZE_2KiB))) {
86 ret = 1;
87 }
88
89 return ret;
90}
91
92static void stmmac_refill_desc3(int bfsize, struct dma_desc *p)
93{
94}
95
96static void stmmac_init_desc3(int des3_as_data_buf, struct dma_desc *p)
97{
98}
99
100static void stmmac_clean_desc3(struct dma_desc *p)
101{
102}
103
104static void stmmac_init_dma_chain(struct dma_desc *des, dma_addr_t phy_addr,
105 unsigned int size)
106{
107 /*
108 * In chained mode the des3 points to the next element in the ring.
109 * The latest element has to point to the head.
110 */
111 int i;
112 struct dma_desc *p = des;
113 dma_addr_t dma_phy = phy_addr;
114
115 for (i = 0; i < (size - 1); i++) {
116 dma_phy += sizeof(struct dma_desc);
117 p->des3 = (unsigned int)dma_phy;
118 p++;
119 }
120 p->des3 = (unsigned int)phy_addr;
121}
122
123static int stmmac_set_16kib_bfsize(int mtu)
124{
125 /* Not supported */
126 return 0;
127}
128
129const struct stmmac_ring_mode_ops ring_mode_ops = {
130 .is_jumbo_frm = stmmac_is_jumbo_frm,
131 .jumbo_frm = stmmac_jumbo_frm,
132 .refill_desc3 = stmmac_refill_desc3,
133 .init_desc3 = stmmac_init_desc3,
134 .init_dma_chain = stmmac_init_dma_chain,
135 .clean_desc3 = stmmac_clean_desc3,
136 .set_16kib_bfsize = stmmac_set_16kib_bfsize,
137};
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index ffba0144fa38..9100c100d295 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -287,10 +287,22 @@ struct mii_regs {
287 unsigned int data; /* MII Data */ 287 unsigned int data; /* MII Data */
288}; 288};
289 289
290struct stmmac_ring_mode_ops {
291 unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
292 unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
293 void (*refill_desc3) (int bfsize, struct dma_desc *p);
294 void (*init_desc3) (int des3_as_data_buf, struct dma_desc *p);
295 void (*init_dma_chain) (struct dma_desc *des, dma_addr_t phy_addr,
296 unsigned int size);
297 void (*clean_desc3) (struct dma_desc *p);
298 int (*set_16kib_bfsize) (int mtu);
299};
300
290struct mac_device_info { 301struct mac_device_info {
291 const struct stmmac_ops *mac; 302 const struct stmmac_ops *mac;
292 const struct stmmac_desc_ops *desc; 303 const struct stmmac_desc_ops *desc;
293 const struct stmmac_dma_ops *dma; 304 const struct stmmac_dma_ops *dma;
305 const struct stmmac_ring_mode_ops *ring;
294 struct mii_regs mii; /* MII register Addresses */ 306 struct mii_regs mii; /* MII register Addresses */
295 struct mac_link link; 307 struct mac_link link;
296 unsigned int synopsys_uid; 308 unsigned int synopsys_uid;
@@ -304,3 +316,4 @@ extern void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6],
304extern void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr, 316extern void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
305 unsigned int high, unsigned int low); 317 unsigned int high, unsigned int low);
306extern void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr); 318extern void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);
319extern const struct stmmac_ring_mode_ops ring_mode_ops;
diff --git a/drivers/net/ethernet/stmicro/stmmac/descs_com.h b/drivers/net/ethernet/stmicro/stmmac/descs_com.h
new file mode 100644
index 000000000000..dd8d6e19dff6
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/descs_com.h
@@ -0,0 +1,126 @@
1/*******************************************************************************
2 Header File to describe Normal/enhanced descriptor functions used for RING
3 and CHAINED modes.
4
5 Copyright(C) 2011 STMicroelectronics Ltd
6
7 It defines all the functions used to handle the normal/enhanced
8 descriptors in case of the DMA is configured to work in chained or
9 in ring mode.
10
11 This program is free software; you can redistribute it and/or modify it
12 under the terms and conditions of the GNU General Public License,
13 version 2, as published by the Free Software Foundation.
14
15 This program is distributed in the hope it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 more details.
19
20 You should have received a copy of the GNU General Public License along with
21 this program; if not, write to the Free Software Foundation, Inc.,
22 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
23
24 The full GNU General Public License is included in this distribution in
25 the file called "COPYING".
26
27 Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
28*******************************************************************************/
29
30#if defined(CONFIG_STMMAC_RING)
31static inline void ehn_desc_rx_set_on_ring_chain(struct dma_desc *p, int end)
32{
33 p->des01.erx.buffer2_size = BUF_SIZE_8KiB - 1;
34 if (end)
35 p->des01.erx.end_ring = 1;
36}
37
38static inline void ehn_desc_tx_set_on_ring_chain(struct dma_desc *p, int end)
39{
40 if (end)
41 p->des01.etx.end_ring = 1;
42}
43
44static inline void enh_desc_end_tx_desc(struct dma_desc *p, int ter)
45{
46 p->des01.etx.end_ring = ter;
47}
48
49static inline void enh_set_tx_desc_len(struct dma_desc *p, int len)
50{
51 if (unlikely(len > BUF_SIZE_4KiB)) {
52 p->des01.etx.buffer1_size = BUF_SIZE_4KiB;
53 p->des01.etx.buffer2_size = len - BUF_SIZE_4KiB;
54 } else
55 p->des01.etx.buffer1_size = len;
56}
57
58static inline void ndesc_rx_set_on_ring_chain(struct dma_desc *p, int end)
59{
60 p->des01.rx.buffer2_size = BUF_SIZE_2KiB - 1;
61 if (end)
62 p->des01.rx.end_ring = 1;
63}
64
65static inline void ndesc_tx_set_on_ring_chain(struct dma_desc *p, int end)
66{
67 if (end)
68 p->des01.tx.end_ring = 1;
69}
70
71static inline void ndesc_end_tx_desc(struct dma_desc *p, int ter)
72{
73 p->des01.tx.end_ring = ter;
74}
75
76static inline void norm_set_tx_desc_len(struct dma_desc *p, int len)
77{
78 if (unlikely(len > BUF_SIZE_2KiB)) {
79 p->des01.etx.buffer1_size = BUF_SIZE_2KiB - 1;
80 p->des01.etx.buffer2_size = len - p->des01.etx.buffer1_size;
81 } else
82 p->des01.tx.buffer1_size = len;
83}
84
85#else
86
87static inline void ehn_desc_rx_set_on_ring_chain(struct dma_desc *p, int end)
88{
89 p->des01.erx.second_address_chained = 1;
90}
91
92static inline void ehn_desc_tx_set_on_ring_chain(struct dma_desc *p, int end)
93{
94 p->des01.etx.second_address_chained = 1;
95}
96
97static inline void enh_desc_end_tx_desc(struct dma_desc *p, int ter)
98{
99 p->des01.etx.second_address_chained = 1;
100}
101
102static inline void enh_set_tx_desc_len(struct dma_desc *p, int len)
103{
104 p->des01.etx.buffer1_size = len;
105}
106
107static inline void ndesc_rx_set_on_ring_chain(struct dma_desc *p, int end)
108{
109 p->des01.rx.second_address_chained = 1;
110}
111
112static inline void ndesc_tx_set_on_ring_chain(struct dma_desc *p, int ring_size)
113{
114 p->des01.tx.second_address_chained = 1;
115}
116
117static inline void ndesc_end_tx_desc(struct dma_desc *p, int ter)
118{
119 p->des01.tx.second_address_chained = 1;
120}
121
122static inline void norm_set_tx_desc_len(struct dma_desc *p, int len)
123{
124 p->des01.tx.buffer1_size = len;
125}
126#endif
diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
index e5dfb6a30182..d87976364ec5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
@@ -23,6 +23,7 @@
23*******************************************************************************/ 23*******************************************************************************/
24 24
25#include "common.h" 25#include "common.h"
26#include "descs_com.h"
26 27
27static int enh_desc_get_tx_status(void *data, struct stmmac_extra_stats *x, 28static int enh_desc_get_tx_status(void *data, struct stmmac_extra_stats *x,
28 struct dma_desc *p, void __iomem *ioaddr) 29 struct dma_desc *p, void __iomem *ioaddr)
@@ -233,10 +234,9 @@ static void enh_desc_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
233 for (i = 0; i < ring_size; i++) { 234 for (i = 0; i < ring_size; i++) {
234 p->des01.erx.own = 1; 235 p->des01.erx.own = 1;
235 p->des01.erx.buffer1_size = BUF_SIZE_8KiB - 1; 236 p->des01.erx.buffer1_size = BUF_SIZE_8KiB - 1;
236 /* To support jumbo frames */ 237
237 p->des01.erx.buffer2_size = BUF_SIZE_8KiB - 1; 238 ehn_desc_rx_set_on_ring_chain(p, (i == ring_size - 1));
238 if (i == ring_size - 1) 239
239 p->des01.erx.end_ring = 1;
240 if (disable_rx_ic) 240 if (disable_rx_ic)
241 p->des01.erx.disable_ic = 1; 241 p->des01.erx.disable_ic = 1;
242 p++; 242 p++;
@@ -249,8 +249,7 @@ static void enh_desc_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
249 249
250 for (i = 0; i < ring_size; i++) { 250 for (i = 0; i < ring_size; i++) {
251 p->des01.etx.own = 0; 251 p->des01.etx.own = 0;
252 if (i == ring_size - 1) 252 ehn_desc_tx_set_on_ring_chain(p, (i == ring_size - 1));
253 p->des01.etx.end_ring = 1;
254 p++; 253 p++;
255 } 254 }
256} 255}
@@ -285,19 +284,16 @@ static void enh_desc_release_tx_desc(struct dma_desc *p)
285 int ter = p->des01.etx.end_ring; 284 int ter = p->des01.etx.end_ring;
286 285
287 memset(p, 0, offsetof(struct dma_desc, des2)); 286 memset(p, 0, offsetof(struct dma_desc, des2));
288 p->des01.etx.end_ring = ter; 287 enh_desc_end_tx_desc(p, ter);
289} 288}
290 289
291static void enh_desc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len, 290static void enh_desc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
292 int csum_flag) 291 int csum_flag)
293{ 292{
294 p->des01.etx.first_segment = is_fs; 293 p->des01.etx.first_segment = is_fs;
295 if (unlikely(len > BUF_SIZE_4KiB)) { 294
296 p->des01.etx.buffer1_size = BUF_SIZE_4KiB; 295 enh_set_tx_desc_len(p, len);
297 p->des01.etx.buffer2_size = len - BUF_SIZE_4KiB; 296
298 } else {
299 p->des01.etx.buffer1_size = len;
300 }
301 if (likely(csum_flag)) 297 if (likely(csum_flag))
302 p->des01.etx.checksum_insertion = cic_full; 298 p->des01.etx.checksum_insertion = cic_full;
303} 299}
diff --git a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
index e13226b80d47..f7e8ba7f501a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
@@ -23,6 +23,7 @@
23*******************************************************************************/ 23*******************************************************************************/
24 24
25#include "common.h" 25#include "common.h"
26#include "descs_com.h"
26 27
27static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x, 28static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x,
28 struct dma_desc *p, void __iomem *ioaddr) 29 struct dma_desc *p, void __iomem *ioaddr)
@@ -126,9 +127,9 @@ static void ndesc_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
126 for (i = 0; i < ring_size; i++) { 127 for (i = 0; i < ring_size; i++) {
127 p->des01.rx.own = 1; 128 p->des01.rx.own = 1;
128 p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1; 129 p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;
129 p->des01.rx.buffer2_size = BUF_SIZE_2KiB - 1; 130
130 if (i == ring_size - 1) 131 ndesc_rx_set_on_ring_chain(p, (i == ring_size - 1));
131 p->des01.rx.end_ring = 1; 132
132 if (disable_rx_ic) 133 if (disable_rx_ic)
133 p->des01.rx.disable_ic = 1; 134 p->des01.rx.disable_ic = 1;
134 p++; 135 p++;
@@ -140,8 +141,7 @@ static void ndesc_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
140 int i; 141 int i;
141 for (i = 0; i < ring_size; i++) { 142 for (i = 0; i < ring_size; i++) {
142 p->des01.tx.own = 0; 143 p->des01.tx.own = 0;
143 if (i == ring_size - 1) 144 ndesc_tx_set_on_ring_chain(p, (i == (ring_size - 1)));
144 p->des01.tx.end_ring = 1;
145 p++; 145 p++;
146 } 146 }
147} 147}
@@ -176,20 +176,14 @@ static void ndesc_release_tx_desc(struct dma_desc *p)
176 int ter = p->des01.tx.end_ring; 176 int ter = p->des01.tx.end_ring;
177 177
178 memset(p, 0, offsetof(struct dma_desc, des2)); 178 memset(p, 0, offsetof(struct dma_desc, des2));
179 /* set termination field */ 179 ndesc_end_tx_desc(p, ter);
180 p->des01.tx.end_ring = ter;
181} 180}
182 181
183static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len, 182static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
184 int csum_flag) 183 int csum_flag)
185{ 184{
186 p->des01.tx.first_segment = is_fs; 185 p->des01.tx.first_segment = is_fs;
187 186 norm_set_tx_desc_len(p, len);
188 if (unlikely(len > BUF_SIZE_2KiB)) {
189 p->des01.etx.buffer1_size = BUF_SIZE_2KiB - 1;
190 p->des01.etx.buffer2_size = len - p->des01.etx.buffer1_size;
191 } else
192 p->des01.tx.buffer1_size = len;
193} 187}
194 188
195static void ndesc_clear_tx_ic(struct dma_desc *p) 189static void ndesc_clear_tx_ic(struct dma_desc *p)
diff --git a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
new file mode 100644
index 000000000000..fb8377da1687
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
@@ -0,0 +1,126 @@
1/*******************************************************************************
2 Specialised functions for managing Ring mode
3
4 Copyright(C) 2011 STMicroelectronics Ltd
5
6 It defines all the functions used to handle the normal/enhanced
7 descriptors in case of the DMA is configured to work in chained or
8 in ring mode.
9
10 This program is free software; you can redistribute it and/or modify it
11 under the terms and conditions of the GNU General Public License,
12 version 2, as published by the Free Software Foundation.
13
14 This program is distributed in the hope it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 more details.
18
19 You should have received a copy of the GNU General Public License along with
20 this program; if not, write to the Free Software Foundation, Inc.,
21 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
22
23 The full GNU General Public License is included in this distribution in
24 the file called "COPYING".
25
26 Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
27*******************************************************************************/
28
29#include "stmmac.h"
30
31static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
32{
33 struct stmmac_priv *priv = (struct stmmac_priv *) p;
34 unsigned int txsize = priv->dma_tx_size;
35 unsigned int entry = priv->cur_tx % txsize;
36 struct dma_desc *desc = priv->dma_tx + entry;
37 unsigned int nopaged_len = skb_headlen(skb);
38 unsigned int bmax, len;
39
40 if (priv->plat->enh_desc)
41 bmax = BUF_SIZE_8KiB;
42 else
43 bmax = BUF_SIZE_2KiB;
44
45 len = nopaged_len - bmax;
46
47 if (nopaged_len > BUF_SIZE_8KiB) {
48
49 desc->des2 = dma_map_single(priv->device, skb->data,
50 bmax, DMA_TO_DEVICE);
51 desc->des3 = desc->des2 + BUF_SIZE_4KiB;
52 priv->hw->desc->prepare_tx_desc(desc, 1, bmax,
53 csum);
54
55 entry = (++priv->cur_tx) % txsize;
56 desc = priv->dma_tx + entry;
57
58 desc->des2 = dma_map_single(priv->device, skb->data + bmax,
59 len, DMA_TO_DEVICE);
60 desc->des3 = desc->des2 + BUF_SIZE_4KiB;
61 priv->hw->desc->prepare_tx_desc(desc, 0, len, csum);
62 priv->hw->desc->set_tx_owner(desc);
63 priv->tx_skbuff[entry] = NULL;
64 } else {
65 desc->des2 = dma_map_single(priv->device, skb->data,
66 nopaged_len, DMA_TO_DEVICE);
67 desc->des3 = desc->des2 + BUF_SIZE_4KiB;
68 priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len, csum);
69 }
70
71 return entry;
72}
73
74static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc)
75{
76 unsigned int ret = 0;
77
78 if (len >= BUF_SIZE_4KiB)
79 ret = 1;
80
81 return ret;
82}
83
84static void stmmac_refill_desc3(int bfsize, struct dma_desc *p)
85{
86 /* Fill DES3 in case of RING mode */
87 if (bfsize >= BUF_SIZE_8KiB)
88 p->des3 = p->des2 + BUF_SIZE_8KiB;
89}
90
91/* In ring mode we need to fill the desc3 because it is used
92 * as buffer */
93static void stmmac_init_desc3(int des3_as_data_buf, struct dma_desc *p)
94{
95 if (unlikely(des3_as_data_buf))
96 p->des3 = p->des2 + BUF_SIZE_8KiB;
97}
98
99static void stmmac_init_dma_chain(struct dma_desc *des, dma_addr_t phy_addr,
100 unsigned int size)
101{
102}
103
104static void stmmac_clean_desc3(struct dma_desc *p)
105{
106 if (unlikely(p->des3))
107 p->des3 = 0;
108}
109
110static int stmmac_set_16kib_bfsize(int mtu)
111{
112 int ret = 0;
113 if (unlikely(mtu >= BUF_SIZE_8KiB))
114 ret = BUF_SIZE_16KiB;
115 return ret;
116}
117
118const struct stmmac_ring_mode_ops ring_mode_ops = {
119 .is_jumbo_frm = stmmac_is_jumbo_frm,
120 .jumbo_frm = stmmac_jumbo_frm,
121 .refill_desc3 = stmmac_refill_desc3,
122 .init_desc3 = stmmac_init_desc3,
123 .init_dma_chain = stmmac_init_dma_chain,
124 .clean_desc3 = stmmac_clean_desc3,
125 .set_16kib_bfsize = stmmac_set_16kib_bfsize,
126};
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 49a4af3ce3a8..9bafa6cf9e8b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -22,7 +22,7 @@
22 22
23#define DRV_MODULE_VERSION "Oct_2011" 23#define DRV_MODULE_VERSION "Oct_2011"
24#include <linux/stmmac.h> 24#include <linux/stmmac.h>
25 25#include <linux/phy.h>
26#include "common.h" 26#include "common.h"
27#ifdef CONFIG_STMMAC_TIMER 27#ifdef CONFIG_STMMAC_TIMER
28#include "stmmac_timer.h" 28#include "stmmac_timer.h"
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index bf895cb75785..5eccd996cde0 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -2,7 +2,7 @@
2 This is the driver for the ST MAC 10/100/1000 on-chip Ethernet controllers. 2 This is the driver for the ST MAC 10/100/1000 on-chip Ethernet controllers.
3 ST Ethernet IPs are built around a Synopsys IP Core. 3 ST Ethernet IPs are built around a Synopsys IP Core.
4 4
5 Copyright (C) 2007-2009 STMicroelectronics Ltd 5 Copyright(C) 2007-2011 STMicroelectronics Ltd
6 6
7 This program is free software; you can redistribute it and/or modify it 7 This program is free software; you can redistribute it and/or modify it
8 under the terms and conditions of the GNU General Public License, 8 under the terms and conditions of the GNU General Public License,
@@ -41,17 +41,16 @@
41#include <linux/if_ether.h> 41#include <linux/if_ether.h>
42#include <linux/crc32.h> 42#include <linux/crc32.h>
43#include <linux/mii.h> 43#include <linux/mii.h>
44#include <linux/phy.h>
45#include <linux/if.h> 44#include <linux/if.h>
46#include <linux/if_vlan.h> 45#include <linux/if_vlan.h>
47#include <linux/dma-mapping.h> 46#include <linux/dma-mapping.h>
48#include <linux/slab.h> 47#include <linux/slab.h>
49#include <linux/prefetch.h> 48#include <linux/prefetch.h>
50#include "stmmac.h"
51#ifdef CONFIG_STMMAC_DEBUG_FS 49#ifdef CONFIG_STMMAC_DEBUG_FS
52#include <linux/debugfs.h> 50#include <linux/debugfs.h>
53#include <linux/seq_file.h> 51#include <linux/seq_file.h>
54#endif 52#endif
53#include "stmmac.h"
55 54
56#define STMMAC_RESOURCE_NAME "stmmaceth" 55#define STMMAC_RESOURCE_NAME "stmmaceth"
57 56
@@ -388,11 +387,28 @@ static void display_ring(struct dma_desc *p, int size)
388 } 387 }
389} 388}
390 389
390static int stmmac_set_bfsize(int mtu, int bufsize)
391{
392 int ret = bufsize;
393
394 if (mtu >= BUF_SIZE_4KiB)
395 ret = BUF_SIZE_8KiB;
396 else if (mtu >= BUF_SIZE_2KiB)
397 ret = BUF_SIZE_4KiB;
398 else if (mtu >= DMA_BUFFER_SIZE)
399 ret = BUF_SIZE_2KiB;
400 else
401 ret = DMA_BUFFER_SIZE;
402
403 return ret;
404}
405
391/** 406/**
392 * init_dma_desc_rings - init the RX/TX descriptor rings 407 * init_dma_desc_rings - init the RX/TX descriptor rings
393 * @dev: net device structure 408 * @dev: net device structure
394 * Description: this function initializes the DMA RX/TX descriptors 409 * Description: this function initializes the DMA RX/TX descriptors
395 * and allocates the socket buffers. 410 * and allocates the socket buffers. It suppors the chained and ring
411 * modes.
396 */ 412 */
397static void init_dma_desc_rings(struct net_device *dev) 413static void init_dma_desc_rings(struct net_device *dev)
398{ 414{
@@ -401,31 +417,24 @@ static void init_dma_desc_rings(struct net_device *dev)
401 struct sk_buff *skb; 417 struct sk_buff *skb;
402 unsigned int txsize = priv->dma_tx_size; 418 unsigned int txsize = priv->dma_tx_size;
403 unsigned int rxsize = priv->dma_rx_size; 419 unsigned int rxsize = priv->dma_rx_size;
404 unsigned int bfsize = priv->dma_buf_sz; 420 unsigned int bfsize;
405 int buff2_needed = 0, dis_ic = 0; 421 int dis_ic = 0;
422 int des3_as_data_buf = 0;
406 423
407 /* Set the Buffer size according to the MTU; 424 /* Set the max buffer size according to the DESC mode
408 * indeed, in case of jumbo we need to bump-up the buffer sizes. 425 * and the MTU. Note that RING mode allows 16KiB bsize. */
409 */ 426 bfsize = priv->hw->ring->set_16kib_bfsize(dev->mtu);
410 if (unlikely(dev->mtu >= BUF_SIZE_8KiB)) 427
411 bfsize = BUF_SIZE_16KiB; 428 if (bfsize == BUF_SIZE_16KiB)
412 else if (unlikely(dev->mtu >= BUF_SIZE_4KiB)) 429 des3_as_data_buf = 1;
413 bfsize = BUF_SIZE_8KiB;
414 else if (unlikely(dev->mtu >= BUF_SIZE_2KiB))
415 bfsize = BUF_SIZE_4KiB;
416 else if (unlikely(dev->mtu >= DMA_BUFFER_SIZE))
417 bfsize = BUF_SIZE_2KiB;
418 else 430 else
419 bfsize = DMA_BUFFER_SIZE; 431 bfsize = stmmac_set_bfsize(dev->mtu, priv->dma_buf_sz);
420 432
421#ifdef CONFIG_STMMAC_TIMER 433#ifdef CONFIG_STMMAC_TIMER
422 /* Disable interrupts on completion for the reception if timer is on */ 434 /* Disable interrupts on completion for the reception if timer is on */
423 if (likely(priv->tm->enable)) 435 if (likely(priv->tm->enable))
424 dis_ic = 1; 436 dis_ic = 1;
425#endif 437#endif
426 /* If the MTU exceeds 8k so use the second buffer in the chain */
427 if (bfsize >= BUF_SIZE_8KiB)
428 buff2_needed = 1;
429 438
430 DBG(probe, INFO, "stmmac: txsize %d, rxsize %d, bfsize %d\n", 439 DBG(probe, INFO, "stmmac: txsize %d, rxsize %d, bfsize %d\n",
431 txsize, rxsize, bfsize); 440 txsize, rxsize, bfsize);
@@ -453,7 +462,7 @@ static void init_dma_desc_rings(struct net_device *dev)
453 return; 462 return;
454 } 463 }
455 464
456 DBG(probe, INFO, "stmmac (%s) DMA desc rings: virt addr (Rx %p, " 465 DBG(probe, INFO, "stmmac (%s) DMA desc: virt addr (Rx %p, "
457 "Tx %p)\n\tDMA phy addr (Rx 0x%08x, Tx 0x%08x)\n", 466 "Tx %p)\n\tDMA phy addr (Rx 0x%08x, Tx 0x%08x)\n",
458 dev->name, priv->dma_rx, priv->dma_tx, 467 dev->name, priv->dma_rx, priv->dma_tx,
459 (unsigned int)priv->dma_rx_phy, (unsigned int)priv->dma_tx_phy); 468 (unsigned int)priv->dma_rx_phy, (unsigned int)priv->dma_tx_phy);
@@ -475,8 +484,9 @@ static void init_dma_desc_rings(struct net_device *dev)
475 bfsize, DMA_FROM_DEVICE); 484 bfsize, DMA_FROM_DEVICE);
476 485
477 p->des2 = priv->rx_skbuff_dma[i]; 486 p->des2 = priv->rx_skbuff_dma[i];
478 if (unlikely(buff2_needed)) 487
479 p->des3 = p->des2 + BUF_SIZE_8KiB; 488 priv->hw->ring->init_desc3(des3_as_data_buf, p);
489
480 DBG(probe, INFO, "[%p]\t[%p]\t[%x]\n", priv->rx_skbuff[i], 490 DBG(probe, INFO, "[%p]\t[%p]\t[%x]\n", priv->rx_skbuff[i],
481 priv->rx_skbuff[i]->data, priv->rx_skbuff_dma[i]); 491 priv->rx_skbuff[i]->data, priv->rx_skbuff_dma[i]);
482 } 492 }
@@ -490,6 +500,12 @@ static void init_dma_desc_rings(struct net_device *dev)
490 priv->tx_skbuff[i] = NULL; 500 priv->tx_skbuff[i] = NULL;
491 priv->dma_tx[i].des2 = 0; 501 priv->dma_tx[i].des2 = 0;
492 } 502 }
503
504 /* In case of Chained mode this sets the des3 to the next
505 * element in the chain */
506 priv->hw->ring->init_dma_chain(priv->dma_rx, priv->dma_rx_phy, rxsize);
507 priv->hw->ring->init_dma_chain(priv->dma_tx, priv->dma_tx_phy, txsize);
508
493 priv->dirty_tx = 0; 509 priv->dirty_tx = 0;
494 priv->cur_tx = 0; 510 priv->cur_tx = 0;
495 511
@@ -620,8 +636,7 @@ static void stmmac_tx(struct stmmac_priv *priv)
620 dma_unmap_single(priv->device, p->des2, 636 dma_unmap_single(priv->device, p->des2,
621 priv->hw->desc->get_tx_len(p), 637 priv->hw->desc->get_tx_len(p),
622 DMA_TO_DEVICE); 638 DMA_TO_DEVICE);
623 if (unlikely(p->des3)) 639 priv->hw->ring->clean_desc3(p);
624 p->des3 = 0;
625 640
626 if (likely(skb != NULL)) { 641 if (likely(skb != NULL)) {
627 /* 642 /*
@@ -728,7 +743,6 @@ static void stmmac_no_timer_stopped(void)
728 */ 743 */
729static void stmmac_tx_err(struct stmmac_priv *priv) 744static void stmmac_tx_err(struct stmmac_priv *priv)
730{ 745{
731
732 netif_stop_queue(priv->dev); 746 netif_stop_queue(priv->dev);
733 747
734 priv->hw->dma->stop_tx(priv->ioaddr); 748 priv->hw->dma->stop_tx(priv->ioaddr);
@@ -1028,47 +1042,6 @@ static int stmmac_release(struct net_device *dev)
1028 return 0; 1042 return 0;
1029} 1043}
1030 1044
1031static unsigned int stmmac_handle_jumbo_frames(struct sk_buff *skb,
1032 struct net_device *dev,
1033 int csum_insertion)
1034{
1035 struct stmmac_priv *priv = netdev_priv(dev);
1036 unsigned int nopaged_len = skb_headlen(skb);
1037 unsigned int txsize = priv->dma_tx_size;
1038 unsigned int entry = priv->cur_tx % txsize;
1039 struct dma_desc *desc = priv->dma_tx + entry;
1040
1041 if (nopaged_len > BUF_SIZE_8KiB) {
1042
1043 int buf2_size = nopaged_len - BUF_SIZE_8KiB;
1044
1045 desc->des2 = dma_map_single(priv->device, skb->data,
1046 BUF_SIZE_8KiB, DMA_TO_DEVICE);
1047 desc->des3 = desc->des2 + BUF_SIZE_4KiB;
1048 priv->hw->desc->prepare_tx_desc(desc, 1, BUF_SIZE_8KiB,
1049 csum_insertion);
1050
1051 entry = (++priv->cur_tx) % txsize;
1052 desc = priv->dma_tx + entry;
1053
1054 desc->des2 = dma_map_single(priv->device,
1055 skb->data + BUF_SIZE_8KiB,
1056 buf2_size, DMA_TO_DEVICE);
1057 desc->des3 = desc->des2 + BUF_SIZE_4KiB;
1058 priv->hw->desc->prepare_tx_desc(desc, 0, buf2_size,
1059 csum_insertion);
1060 priv->hw->desc->set_tx_owner(desc);
1061 priv->tx_skbuff[entry] = NULL;
1062 } else {
1063 desc->des2 = dma_map_single(priv->device, skb->data,
1064 nopaged_len, DMA_TO_DEVICE);
1065 desc->des3 = desc->des2 + BUF_SIZE_4KiB;
1066 priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len,
1067 csum_insertion);
1068 }
1069 return entry;
1070}
1071
1072/** 1045/**
1073 * stmmac_xmit: 1046 * stmmac_xmit:
1074 * @skb : the socket buffer 1047 * @skb : the socket buffer
@@ -1083,6 +1056,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
1083 int i, csum_insertion = 0; 1056 int i, csum_insertion = 0;
1084 int nfrags = skb_shinfo(skb)->nr_frags; 1057 int nfrags = skb_shinfo(skb)->nr_frags;
1085 struct dma_desc *desc, *first; 1058 struct dma_desc *desc, *first;
1059 unsigned int nopaged_len = skb_headlen(skb);
1086 1060
1087 if (unlikely(stmmac_tx_avail(priv) < nfrags + 1)) { 1061 if (unlikely(stmmac_tx_avail(priv) < nfrags + 1)) {
1088 if (!netif_queue_stopped(dev)) { 1062 if (!netif_queue_stopped(dev)) {
@@ -1103,7 +1077,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
1103 pr_info("stmmac xmit:\n" 1077 pr_info("stmmac xmit:\n"
1104 "\tskb addr %p - len: %d - nopaged_len: %d\n" 1078 "\tskb addr %p - len: %d - nopaged_len: %d\n"
1105 "\tn_frags: %d - ip_summed: %d - %s gso\n", 1079 "\tn_frags: %d - ip_summed: %d - %s gso\n",
1106 skb, skb->len, skb_headlen(skb), nfrags, skb->ip_summed, 1080 skb, skb->len, nopaged_len, nfrags, skb->ip_summed,
1107 !skb_is_gso(skb) ? "isn't" : "is"); 1081 !skb_is_gso(skb) ? "isn't" : "is");
1108#endif 1082#endif
1109 1083
@@ -1116,14 +1090,14 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
1116 if ((nfrags > 0) || (skb->len > ETH_FRAME_LEN)) 1090 if ((nfrags > 0) || (skb->len > ETH_FRAME_LEN))
1117 pr_debug("stmmac xmit: skb len: %d, nopaged_len: %d,\n" 1091 pr_debug("stmmac xmit: skb len: %d, nopaged_len: %d,\n"
1118 "\t\tn_frags: %d, ip_summed: %d\n", 1092 "\t\tn_frags: %d, ip_summed: %d\n",
1119 skb->len, skb_headlen(skb), nfrags, skb->ip_summed); 1093 skb->len, nopaged_len, nfrags, skb->ip_summed);
1120#endif 1094#endif
1121 priv->tx_skbuff[entry] = skb; 1095 priv->tx_skbuff[entry] = skb;
1122 if (unlikely(skb->len >= BUF_SIZE_4KiB)) { 1096
1123 entry = stmmac_handle_jumbo_frames(skb, dev, csum_insertion); 1097 if (priv->hw->ring->is_jumbo_frm(skb->len, priv->plat->enh_desc)) {
1098 entry = priv->hw->ring->jumbo_frm(priv, skb, csum_insertion);
1124 desc = priv->dma_tx + entry; 1099 desc = priv->dma_tx + entry;
1125 } else { 1100 } else {
1126 unsigned int nopaged_len = skb_headlen(skb);
1127 desc->des2 = dma_map_single(priv->device, skb->data, 1101 desc->des2 = dma_map_single(priv->device, skb->data,
1128 nopaged_len, DMA_TO_DEVICE); 1102 nopaged_len, DMA_TO_DEVICE);
1129 priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len, 1103 priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len,
@@ -1214,11 +1188,10 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
1214 DMA_FROM_DEVICE); 1188 DMA_FROM_DEVICE);
1215 1189
1216 (p + entry)->des2 = priv->rx_skbuff_dma[entry]; 1190 (p + entry)->des2 = priv->rx_skbuff_dma[entry];
1217 if (unlikely(priv->plat->has_gmac)) { 1191
1218 if (bfsize >= BUF_SIZE_8KiB) 1192 if (unlikely(priv->plat->has_gmac))
1219 (p + entry)->des3 = 1193 priv->hw->ring->refill_desc3(bfsize, p + entry);
1220 (p + entry)->des2 + BUF_SIZE_8KiB; 1194
1221 }
1222 RX_DBG(KERN_INFO "\trefill entry #%d\n", entry); 1195 RX_DBG(KERN_INFO "\trefill entry #%d\n", entry);
1223 } 1196 }
1224 wmb(); 1197 wmb();
@@ -1795,6 +1768,7 @@ static int stmmac_mac_device_setup(struct net_device *dev)
1795 device->desc = &ndesc_ops; 1768 device->desc = &ndesc_ops;
1796 1769
1797 priv->hw = device; 1770 priv->hw = device;
1771 priv->hw->ring = &ring_mode_ops;
1798 1772
1799 if (device_can_wakeup(priv->device)) { 1773 if (device_can_wakeup(priv->device)) {
1800 priv->wolopts = WAKE_MAGIC; /* Magic Frame as default */ 1774 priv->wolopts = WAKE_MAGIC; /* Magic Frame as default */