[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <4E9D4C3C.2030105@st.com>
Date: Tue, 18 Oct 2011 11:51:56 +0200
From: Giuseppe CAVALLARO <peppe.cavallaro@...com>
To: netdev@...r.kernel.org
Cc: davem@...emloft.net, Rayagond Kokatanur <rayagond@...avyalabs.com>,
Eric Dumazet <eric.dumazet@...il.com>
Subject: Re: [net-next 7/7] stmmac: add CHAINED descriptor mode support (V3)
Please discard these. I'm sending the V4 (with the Eric patch for mtu
and dma_init).
Peppe
On 10/18/2011 10:42 AM, Giuseppe CAVALLARO wrote:
> 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@...avyalabs.com>
> Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@...com>
> ---
> drivers/net/ethernet/stmicro/stmmac/Kconfig | 18 +++
> drivers/net/ethernet/stmicro/stmmac/Makefile | 2 +
> drivers/net/ethernet/stmicro/stmmac/chain_mode.c | 137 +++++++++++++++++++++
> drivers/net/ethernet/stmicro/stmmac/common.h | 13 ++
> drivers/net/ethernet/stmicro/stmmac/descs_com.h | 126 +++++++++++++++++++
> drivers/net/ethernet/stmicro/stmmac/enh_desc.c | 22 ++--
> drivers/net/ethernet/stmicro/stmmac/norm_desc.c | 20 +--
> drivers/net/ethernet/stmicro/stmmac/ring_mode.c | 126 +++++++++++++++++++
> drivers/net/ethernet/stmicro/stmmac/stmmac.h | 2 +-
> drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 130 ++++++++------------
> 10 files changed, 491 insertions(+), 105 deletions(-)
> create mode 100644 drivers/net/ethernet/stmicro/stmmac/chain_mode.c
> create mode 100644 drivers/net/ethernet/stmicro/stmmac/descs_com.h
> create mode 100644 drivers/net/ethernet/stmicro/stmmac/ring_mode.c
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
> index 8cd9dde..ac6f190 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
> +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
> @@ -63,4 +63,22 @@ config STMMAC_RTC_TIMER
>
> endchoice
>
> +choice
> + prompt "Select the DMA TX/RX descriptor operating modes"
> + depends on STMMAC_ETH
> + ---help---
> + This driver supports DMA descriptor to operate both in dual buffer
> + (RING) and linked-list(CHAINED) mode. In RING mode each descriptor
> + points to two data buffer pointers whereas in CHAINED mode they
> + points to only one data buffer pointer.
> +
> +config STMMAC_RING
> + bool "Enable Descriptor Ring Mode"
> +
> +config STMMAC_CHAINED
> + bool "Enable Descriptor Chained Mode"
> +
> +endchoice
> +
> +
> endif
> diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
> index 0f23d95..d7c4516 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/Makefile
> +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
> @@ -1,5 +1,7 @@
> obj-$(CONFIG_STMMAC_ETH) += stmmac.o
> stmmac-$(CONFIG_STMMAC_TIMER) += stmmac_timer.o
> +stmmac-$(CONFIG_STMMAC_RING) += ring_mode.o
> +stmmac-$(CONFIG_STMMAC_CHAINED) += chain_mode.o
> stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o \
> dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \
> 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 0000000..0668659
> --- /dev/null
> +++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
> @@ -0,0 +1,137 @@
> +/*******************************************************************************
> + Specialised functions for managing Chained mode
> +
> + Copyright(C) 2011 STMicroelectronics Ltd
> +
> + It defines all the functions used to handle the normal/enhanced
> + descriptors in case of the DMA is configured to work in chained or
> + in ring mode.
> +
> + This program is free software; you can redistribute it and/or modify it
> + under the terms and conditions of the GNU General Public License,
> + version 2, as published by the Free Software Foundation.
> +
> + This program is distributed in the hope it will be useful, but WITHOUT
> + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + more details.
> +
> + You should have received a copy of the GNU General Public License along with
> + this program; if not, write to the Free Software Foundation, Inc.,
> + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> +
> + The full GNU General Public License is included in this distribution in
> + the file called "COPYING".
> +
> + Author: Giuseppe Cavallaro <peppe.cavallaro@...com>
> +*******************************************************************************/
> +
> +#include "stmmac.h"
> +
> +unsigned 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;
> + struct dma_desc *desc = priv->dma_tx + entry;
> + unsigned int nopaged_len = skb_headlen(skb);
> + unsigned int bmax;
> + unsigned int i = 1, len;
> +
> + if (priv->plat->enh_desc)
> + bmax = BUF_SIZE_8KiB;
> + else
> + bmax = BUF_SIZE_2KiB;
> +
> + len = nopaged_len - bmax;
> +
> + desc->des2 = dma_map_single(priv->device, skb->data,
> + bmax, DMA_TO_DEVICE);
> + priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum);
> +
> + while (len != 0) {
> + entry = (++priv->cur_tx) % txsize;
> + desc = priv->dma_tx + entry;
> +
> + if (len > bmax) {
> + desc->des2 = dma_map_single(priv->device,
> + (skb->data + bmax * i),
> + bmax, DMA_TO_DEVICE);
> + priv->hw->desc->prepare_tx_desc(desc, 0, bmax,
> + csum);
> + priv->hw->desc->set_tx_owner(desc);
> + priv->tx_skbuff[entry] = NULL;
> + len -= bmax;
> + i++;
> + } else {
> + desc->des2 = dma_map_single(priv->device,
> + (skb->data + bmax * i), len,
> + DMA_TO_DEVICE);
> + priv->hw->desc->prepare_tx_desc(desc, 0, len,
> + csum);
> + priv->hw->desc->set_tx_owner(desc);
> + priv->tx_skbuff[entry] = NULL;
> + len = 0;
> + }
> + }
> + return entry;
> +}
> +
> +static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc)
> +{
> + unsigned int ret = 0;
> +
> + if ((enh_desc && (len > BUF_SIZE_8KiB)) ||
> + (!enh_desc && (len > BUF_SIZE_2KiB))) {
> + ret = 1;
> + }
> +
> + return ret;
> +}
> +
> +static void stmmac_refill_desc3(int bfsize, struct dma_desc *p)
> +{
> +}
> +
> +static void stmmac_init_desc3(int des3_as_data_buf, struct dma_desc *p)
> +{
> +}
> +
> +static void stmmac_clean_desc3(struct dma_desc *p)
> +{
> +}
> +
> +static void stmmac_init_dma_chain(struct dma_desc *des, dma_addr_t phy_addr,
> + unsigned int size)
> +{
> + /*
> + * 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++;
> + }
> + p->des3 = (unsigned int)phy_addr;
> +}
> +
> +static int stmmac_set_16kib_bfsize(int mtu)
> +{
> + /* Not supported */
> + return 0;
> +}
> +
> +const struct stmmac_ring_mode_ops ring_mode_ops = {
> + .is_jumbo_frm = stmmac_is_jumbo_frm,
> + .jumbo_frm = stmmac_jumbo_frm,
> + .refill_desc3 = stmmac_refill_desc3,
> + .init_desc3 = stmmac_init_desc3,
> + .init_dma_chain = stmmac_init_dma_chain,
> + .clean_desc3 = stmmac_clean_desc3,
> + .set_16kib_bfsize = stmmac_set_16kib_bfsize,
> +};
> diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
> index ffba014..9100c10 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/common.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/common.h
> @@ -287,10 +287,22 @@ struct mii_regs {
> unsigned int data; /* MII Data */
> };
>
> +struct stmmac_ring_mode_ops {
> + unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
> + unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
> + void (*refill_desc3) (int bfsize, struct dma_desc *p);
> + void (*init_desc3) (int des3_as_data_buf, struct dma_desc *p);
> + void (*init_dma_chain) (struct dma_desc *des, dma_addr_t phy_addr,
> + unsigned int size);
> + void (*clean_desc3) (struct dma_desc *p);
> + int (*set_16kib_bfsize) (int mtu);
> +};
> +
> struct mac_device_info {
> const struct stmmac_ops *mac;
> const struct stmmac_desc_ops *desc;
> const struct stmmac_dma_ops *dma;
> + const struct stmmac_ring_mode_ops *ring;
> struct mii_regs mii; /* MII register Addresses */
> struct mac_link link;
> unsigned int synopsys_uid;
> @@ -304,3 +316,4 @@ extern void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6],
> extern void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
> unsigned int high, unsigned int low);
> extern void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);
> +extern 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 0000000..1652c86
> --- /dev/null
> +++ b/drivers/net/ethernet/stmicro/stmmac/descs_com.h
> @@ -0,0 +1,126 @@
> +/*******************************************************************************
> + Header File to describe Normal/enhanced descriptor functions used for RING
> + and CHAINED modes.
> +
> + Copyright(C) 2011 STMicroelectronics Ltd
> +
> + It defines all the functions used to handle the normal/enhanced
> + descriptors in case of the DMA is configured to work in chained or
> + in ring mode.
> +
> + This program is free software; you can redistribute it and/or modify it
> + under the terms and conditions of the GNU General Public License,
> + version 2, as published by the Free Software Foundation.
> +
> + This program is distributed in the hope it will be useful, but WITHOUT
> + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + more details.
> +
> + You should have received a copy of the GNU General Public License along with
> + this program; if not, write to the Free Software Foundation, Inc.,
> + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> +
> + The full GNU General Public License is included in this distribution in
> + the file called "COPYING".
> +
> + Author: Giuseppe Cavallaro <peppe.cavallaro@...com>
> +*******************************************************************************/
> +
> +#if defined(CONFIG_STMMAC_RING)
> +static inline void ehn_desc_rx_set_on_ring_chain(struct dma_desc *p, int end)
> +{
> + p->des01.erx.buffer2_size = BUF_SIZE_8KiB - 1;
> + if (end)
> + p->des01.erx.end = 1;
> +}
> +
> +static inline void ehn_desc_tx_set_on_ring_chain(struct dma_desc *p, int end)
> +{
> + if (end)
> + p->des01.etx.end = 1;
> +}
> +
> +static inline void enh_desc_end_tx_desc(struct dma_desc *p, int ter)
> +{
> + p->des01.etx.end = ter;
> +}
> +
> +static inline void enh_set_tx_desc_len(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;
> + } else
> + p->des01.etx.buffer1_size = len;
> +}
> +
> +static inline void ndesc_rx_set_on_ring_chain(struct dma_desc *p, int end)
> +{
> + p->des01.rx.buffer2_size = BUF_SIZE_2KiB - 1;
> + if (end)
> + p->des01.rx.end = 1;
> +}
> +
> +static inline void ndesc_tx_set_on_ring_chain(struct dma_desc *p, int end)
> +{
> + if (end)
> + p->des01.tx.end = 1;
> +}
> +
> +static inline void ndesc_end_tx_desc(struct dma_desc *p, int ter)
> +{
> + p->des01.tx.end = ter;
> +}
> +
> +static inline void norm_set_tx_desc_len(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;
> + } else
> + p->des01.tx.buffer1_size = len;
> +}
> +
> +#else
> +
> +static inline void ehn_desc_rx_set_on_ring_chain(struct dma_desc *p, int end)
> +{
> + p->des01.erx.second_address_chained = 1;
> +}
> +
> +static inline void ehn_desc_tx_set_on_ring_chain(struct dma_desc *p, int end)
> +{
> + p->des01.etx.second_address_chained = 1;
> +}
> +
> +static inline void enh_desc_end_tx_desc(struct dma_desc *p, int ter)
> +{
> + p->des01.etx.second_address_chained = 1;
> +}
> +
> +static inline void enh_set_tx_desc_len(struct dma_desc *p, int len)
> +{
> + p->des01.etx.buffer1_size = len;
> +}
> +
> +static inline void ndesc_rx_set_on_ring_chain(struct dma_desc *p, int end)
> +{
> + p->des01.rx.second_address_chained = 1;
> +}
> +
> +static inline void ndesc_tx_set_on_ring_chain(struct dma_desc *p, int ring_size)
> +{
> + p->des01.tx.second_address_chained = 1;
> +}
> +
> +static inline void ndesc_end_tx_desc(struct dma_desc *p, int ter)
> +{
> + p->des01.tx.second_address_chained = 1;
> +}
> +
> +static inline void norm_set_tx_desc_len(struct dma_desc *p, int len)
> +{
> + p->des01.tx.buffer1_size = len;
> +}
> +#endif
> diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
> index e5dfb6a..d879763 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
> @@ -23,6 +23,7 @@
> *******************************************************************************/
>
> #include "common.h"
> +#include "descs_com.h"
>
> static int enh_desc_get_tx_status(void *data, struct stmmac_extra_stats *x,
> 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,
> for (i = 0; i < ring_size; i++) {
> p->des01.erx.own = 1;
> p->des01.erx.buffer1_size = BUF_SIZE_8KiB - 1;
> - /* To support jumbo frames */
> - p->des01.erx.buffer2_size = BUF_SIZE_8KiB - 1;
> - if (i == ring_size - 1)
> - p->des01.erx.end_ring = 1;
> +
> + ehn_desc_rx_set_on_ring_chain(p, (i == ring_size - 1));
> +
> if (disable_rx_ic)
> p->des01.erx.disable_ic = 1;
> p++;
> @@ -249,8 +249,7 @@ static void enh_desc_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
>
> for (i = 0; i < ring_size; i++) {
> p->des01.etx.own = 0;
> - if (i == ring_size - 1)
> - p->des01.etx.end_ring = 1;
> + ehn_desc_tx_set_on_ring_chain(p, (i == ring_size - 1));
> p++;
> }
> }
> @@ -285,19 +284,16 @@ static void enh_desc_release_tx_desc(struct dma_desc *p)
> int ter = p->des01.etx.end_ring;
>
> memset(p, 0, offsetof(struct dma_desc, des2));
> - p->des01.etx.end_ring = ter;
> + enh_desc_end_tx_desc(p, ter);
> }
>
> static void enh_desc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
> int csum_flag)
> {
> p->des01.etx.first_segment = is_fs;
> - if (unlikely(len > BUF_SIZE_4KiB)) {
> - p->des01.etx.buffer1_size = BUF_SIZE_4KiB;
> - p->des01.etx.buffer2_size = len - BUF_SIZE_4KiB;
> - } else {
> - p->des01.etx.buffer1_size = len;
> - }
> +
> + enh_set_tx_desc_len(p, len);
> +
> if (likely(csum_flag))
> p->des01.etx.checksum_insertion = cic_full;
> }
> diff --git a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
> index e13226b..f7e8ba7 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
> @@ -23,6 +23,7 @@
> *******************************************************************************/
>
> #include "common.h"
> +#include "descs_com.h"
>
> static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x,
> 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,
> for (i = 0; i < ring_size; i++) {
> p->des01.rx.own = 1;
> p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;
> - p->des01.rx.buffer2_size = BUF_SIZE_2KiB - 1;
> - if (i == ring_size - 1)
> - p->des01.rx.end_ring = 1;
> +
> + ndesc_rx_set_on_ring_chain(p, (i == ring_size - 1));
> +
> if (disable_rx_ic)
> p->des01.rx.disable_ic = 1;
> p++;
> @@ -140,8 +141,7 @@ static void ndesc_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
> int i;
> for (i = 0; i < ring_size; i++) {
> p->des01.tx.own = 0;
> - if (i == ring_size - 1)
> - p->des01.tx.end_ring = 1;
> + ndesc_tx_set_on_ring_chain(p, (i == (ring_size - 1)));
> p++;
> }
> }
> @@ -176,20 +176,14 @@ static void ndesc_release_tx_desc(struct dma_desc *p)
> int ter = p->des01.tx.end_ring;
>
> memset(p, 0, offsetof(struct dma_desc, des2));
> - /* set termination field */
> - p->des01.tx.end_ring = ter;
> + ndesc_end_tx_desc(p, ter);
> }
>
> static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
> int csum_flag)
> {
> p->des01.tx.first_segment = is_fs;
> -
> - 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;
> - } else
> - p->des01.tx.buffer1_size = len;
> + norm_set_tx_desc_len(p, len);
> }
>
> static 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 0000000..fb8377d
> --- /dev/null
> +++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
> @@ -0,0 +1,126 @@
> +/*******************************************************************************
> + Specialised functions for managing Ring mode
> +
> + Copyright(C) 2011 STMicroelectronics Ltd
> +
> + It defines all the functions used to handle the normal/enhanced
> + descriptors in case of the DMA is configured to work in chained or
> + in ring mode.
> +
> + This program is free software; you can redistribute it and/or modify it
> + under the terms and conditions of the GNU General Public License,
> + version 2, as published by the Free Software Foundation.
> +
> + This program is distributed in the hope it will be useful, but WITHOUT
> + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + more details.
> +
> + You should have received a copy of the GNU General Public License along with
> + this program; if not, write to the Free Software Foundation, Inc.,
> + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> +
> + The full GNU General Public License is included in this distribution in
> + the file called "COPYING".
> +
> + Author: Giuseppe Cavallaro <peppe.cavallaro@...com>
> +*******************************************************************************/
> +
> +#include "stmmac.h"
> +
> +static unsigned 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;
> + struct dma_desc *desc = priv->dma_tx + entry;
> + unsigned int nopaged_len = skb_headlen(skb);
> + unsigned int bmax, len;
> +
> + if (priv->plat->enh_desc)
> + bmax = BUF_SIZE_8KiB;
> + else
> + bmax = BUF_SIZE_2KiB;
> +
> + len = nopaged_len - bmax;
> +
> + if (nopaged_len > BUF_SIZE_8KiB) {
> +
> + desc->des2 = dma_map_single(priv->device, skb->data,
> + bmax, DMA_TO_DEVICE);
> + desc->des3 = desc->des2 + BUF_SIZE_4KiB;
> + priv->hw->desc->prepare_tx_desc(desc, 1, bmax,
> + csum);
> +
> + entry = (++priv->cur_tx) % txsize;
> + desc = priv->dma_tx + entry;
> +
> + desc->des2 = dma_map_single(priv->device, skb->data + bmax,
> + len, DMA_TO_DEVICE);
> + desc->des3 = desc->des2 + BUF_SIZE_4KiB;
> + priv->hw->desc->prepare_tx_desc(desc, 0, len, csum);
> + priv->hw->desc->set_tx_owner(desc);
> + priv->tx_skbuff[entry] = NULL;
> + } else {
> + desc->des2 = dma_map_single(priv->device, skb->data,
> + nopaged_len, DMA_TO_DEVICE);
> + desc->des3 = desc->des2 + BUF_SIZE_4KiB;
> + priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len, csum);
> + }
> +
> + return entry;
> +}
> +
> +static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc)
> +{
> + unsigned int ret = 0;
> +
> + if (len >= BUF_SIZE_4KiB)
> + ret = 1;
> +
> + return ret;
> +}
> +
> +static void stmmac_refill_desc3(int bfsize, struct dma_desc *p)
> +{
> + /* Fill DES3 in case of RING mode */
> + if (bfsize >= BUF_SIZE_8KiB)
> + p->des3 = p->des2 + BUF_SIZE_8KiB;
> +}
> +
> +/* In ring mode we need to fill the desc3 because it is used
> + * as buffer */
> +static void stmmac_init_desc3(int des3_as_data_buf, struct dma_desc *p)
> +{
> + if (unlikely(des3_as_data_buf))
> + p->des3 = p->des2 + BUF_SIZE_8KiB;
> +}
> +
> +static void stmmac_init_dma_chain(struct dma_desc *des, dma_addr_t phy_addr,
> + unsigned int size)
> +{
> +}
> +
> +static void stmmac_clean_desc3(struct dma_desc *p)
> +{
> + if (unlikely(p->des3))
> + p->des3 = 0;
> +}
> +
> +static int stmmac_set_16kib_bfsize(int mtu)
> +{
> + int ret = 0;
> + if (unlikely(mtu >= BUF_SIZE_8KiB))
> + ret = BUF_SIZE_16KiB;
> + return ret;
> +}
> +
> +const struct stmmac_ring_mode_ops ring_mode_ops = {
> + .is_jumbo_frm = stmmac_is_jumbo_frm,
> + .jumbo_frm = stmmac_jumbo_frm,
> + .refill_desc3 = stmmac_refill_desc3,
> + .init_desc3 = stmmac_init_desc3,
> + .init_dma_chain = stmmac_init_dma_chain,
> + .clean_desc3 = stmmac_clean_desc3,
> + .set_16kib_bfsize = stmmac_set_16kib_bfsize,
> +};
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
> index 49a4af3..9bafa6c 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
> @@ -22,7 +22,7 @@
>
> #define DRV_MODULE_VERSION "Oct_2011"
> #include <linux/stmmac.h>
> -
> +#include <linux/phy.h>
> #include "common.h"
> #ifdef CONFIG_STMMAC_TIMER
> #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 7325256..1848a16 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -2,7 +2,7 @@
> This is the driver for the ST MAC 10/100/1000 on-chip Ethernet controllers.
> ST Ethernet IPs are built around a Synopsys IP Core.
>
> - Copyright (C) 2007-2009 STMicroelectronics Ltd
> + Copyright(C) 2007-2011 STMicroelectronics Ltd
>
> This program is free software; you can redistribute it and/or modify it
> under the terms and conditions of the GNU General Public License,
> @@ -41,17 +41,16 @@
> #include <linux/if_ether.h>
> #include <linux/crc32.h>
> #include <linux/mii.h>
> -#include <linux/phy.h>
> #include <linux/if.h>
> #include <linux/if_vlan.h>
> #include <linux/dma-mapping.h>
> #include <linux/slab.h>
> #include <linux/prefetch.h>
> -#include "stmmac.h"
> #ifdef CONFIG_STMMAC_DEBUG_FS
> #include <linux/debugfs.h>
> #include <linux/seq_file.h>
> #endif
> +#include "stmmac.h"
>
> #define STMMAC_RESOURCE_NAME "stmmaceth"
>
> @@ -388,11 +387,28 @@ static void display_ring(struct dma_desc *p, int size)
> }
> }
>
> +static int stmmac_set_bfsize(int mtu, int bufsize)
> +{
> + int ret = bufsize;
> +
> + if (mtu >= BUF_SIZE_4KiB)
> + ret = BUF_SIZE_8KiB;
> + else if (mtu >= BUF_SIZE_2KiB)
> + ret = BUF_SIZE_4KiB;
> + else if (mtu >= DMA_BUFFER_SIZE)
> + ret = BUF_SIZE_2KiB;
> + else
> + ret = DMA_BUFFER_SIZE;
> +
> + return ret;
> +}
> +
> /**
> * init_dma_desc_rings - init the RX/TX descriptor rings
> * @dev: net device structure
> * Description: this function initializes the DMA RX/TX descriptors
> - * and allocates the socket buffers.
> + * and allocates the socket buffers. It suppors the chained and ring
> + * modes.
> */
> static void init_dma_desc_rings(struct net_device *dev)
> {
> @@ -401,31 +417,24 @@ static void init_dma_desc_rings(struct net_device *dev)
> struct sk_buff *skb;
> unsigned int txsize = priv->dma_tx_size;
> unsigned int rxsize = priv->dma_rx_size;
> - unsigned int bfsize = priv->dma_buf_sz;
> - int buff2_needed = 0, dis_ic = 0;
> + unsigned int bfsize;
> + int dis_ic = 0;
> + int des3_as_data_buf = 0;
>
> - /* Set the Buffer size according to the MTU;
> - * indeed, in case of jumbo we need to bump-up the buffer sizes.
> - */
> - if (unlikely(dev->mtu >= BUF_SIZE_8KiB))
> - bfsize = BUF_SIZE_16KiB;
> - else if (unlikely(dev->mtu >= BUF_SIZE_4KiB))
> - bfsize = BUF_SIZE_8KiB;
> - else if (unlikely(dev->mtu >= BUF_SIZE_2KiB))
> - bfsize = BUF_SIZE_4KiB;
> - else if (unlikely(dev->mtu >= DMA_BUFFER_SIZE))
> - bfsize = BUF_SIZE_2KiB;
> + /* Set the max buffer size according to the DESC mode
> + * and the MTU. Note that RING mode allows 16KiB bsize. */
> + bfsize = priv->hw->ring->set_16kib_bfsize(dev->mtu);
> +
> + if (bfsize == BUF_SIZE_16KiB)
> + des3_as_data_buf = 1;
> else
> - bfsize = DMA_BUFFER_SIZE;
> + bfsize = stmmac_set_bfsize(dev->mtu, priv->dma_buf_sz);
>
> #ifdef CONFIG_STMMAC_TIMER
> /* Disable interrupts on completion for the reception if timer is on */
> if (likely(priv->tm->enable))
> dis_ic = 1;
> #endif
> - /* If the MTU exceeds 8k so use the second buffer in the chain */
> - if (bfsize >= BUF_SIZE_8KiB)
> - buff2_needed = 1;
>
> DBG(probe, INFO, "stmmac: txsize %d, rxsize %d, bfsize %d\n",
> txsize, rxsize, bfsize);
> @@ -453,7 +462,7 @@ static void init_dma_desc_rings(struct net_device *dev)
> return;
> }
>
> - DBG(probe, INFO, "stmmac (%s) DMA desc rings: virt addr (Rx %p, "
> + DBG(probe, INFO, "stmmac (%s) DMA desc: virt addr (Rx %p, "
> "Tx %p)\n\tDMA phy addr (Rx 0x%08x, Tx 0x%08x)\n",
> dev->name, priv->dma_rx, priv->dma_tx,
> (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)
> bfsize, DMA_FROM_DEVICE);
>
> p->des2 = priv->rx_skbuff_dma[i];
> - if (unlikely(buff2_needed))
> - p->des3 = p->des2 + BUF_SIZE_8KiB;
> +
> + priv->hw->ring->init_desc3(des3_as_data_buf, p);
> +
> DBG(probe, INFO, "[%p]\t[%p]\t[%x]\n", priv->rx_skbuff[i],
> priv->rx_skbuff[i]->data, priv->rx_skbuff_dma[i]);
> }
> @@ -490,6 +500,12 @@ static void init_dma_desc_rings(struct net_device *dev)
> priv->tx_skbuff[i] = NULL;
> priv->dma_tx[i].des2 = 0;
> }
> +
> + /* In case of Chained mode this sets the des3 to the next
> + * element in the chain */
> + priv->hw->ring->init_dma_chain(priv->dma_rx, priv->dma_rx_phy, rxsize);
> + priv->hw->ring->init_dma_chain(priv->dma_tx, priv->dma_tx_phy, txsize);
> +
> priv->dirty_tx = 0;
> priv->cur_tx = 0;
>
> @@ -620,8 +636,7 @@ static void stmmac_tx(struct stmmac_priv *priv)
> dma_unmap_single(priv->device, p->des2,
> priv->hw->desc->get_tx_len(p),
> DMA_TO_DEVICE);
> - if (unlikely(p->des3))
> - p->des3 = 0;
> + priv->hw->ring->clean_desc3(p);
>
> if (likely(skb != NULL)) {
> /*
> @@ -728,7 +743,6 @@ static void stmmac_no_timer_stopped(void)
> */
> static void stmmac_tx_err(struct stmmac_priv *priv)
> {
> -
> netif_stop_queue(priv->dev);
>
> priv->hw->dma->stop_tx(priv->ioaddr);
> @@ -1028,47 +1042,6 @@ static int stmmac_release(struct net_device *dev)
> return 0;
> }
>
> -static unsigned int stmmac_handle_jumbo_frames(struct sk_buff *skb,
> - struct net_device *dev,
> - int csum_insertion)
> -{
> - struct stmmac_priv *priv = netdev_priv(dev);
> - unsigned int nopaged_len = skb_headlen(skb);
> - unsigned int txsize = priv->dma_tx_size;
> - unsigned int entry = priv->cur_tx % txsize;
> - struct dma_desc *desc = priv->dma_tx + entry;
> -
> - if (nopaged_len > BUF_SIZE_8KiB) {
> -
> - int buf2_size = nopaged_len - BUF_SIZE_8KiB;
> -
> - desc->des2 = dma_map_single(priv->device, skb->data,
> - BUF_SIZE_8KiB, DMA_TO_DEVICE);
> - desc->des3 = desc->des2 + BUF_SIZE_4KiB;
> - priv->hw->desc->prepare_tx_desc(desc, 1, BUF_SIZE_8KiB,
> - csum_insertion);
> -
> - entry = (++priv->cur_tx) % txsize;
> - desc = priv->dma_tx + entry;
> -
> - desc->des2 = dma_map_single(priv->device,
> - skb->data + BUF_SIZE_8KiB,
> - buf2_size, DMA_TO_DEVICE);
> - desc->des3 = desc->des2 + BUF_SIZE_4KiB;
> - priv->hw->desc->prepare_tx_desc(desc, 0, buf2_size,
> - csum_insertion);
> - priv->hw->desc->set_tx_owner(desc);
> - priv->tx_skbuff[entry] = NULL;
> - } else {
> - desc->des2 = dma_map_single(priv->device, skb->data,
> - nopaged_len, DMA_TO_DEVICE);
> - desc->des3 = desc->des2 + BUF_SIZE_4KiB;
> - priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len,
> - csum_insertion);
> - }
> - return entry;
> -}
> -
> /**
> * stmmac_xmit:
> * @skb : the socket buffer
> @@ -1083,6 +1056,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
> int i, csum_insertion = 0;
> int nfrags = skb_shinfo(skb)->nr_frags;
> struct dma_desc *desc, *first;
> + unsigned int nopaged_len = skb_headlen(skb);
>
> if (unlikely(stmmac_tx_avail(priv) < nfrags + 1)) {
> if (!netif_queue_stopped(dev)) {
> @@ -1103,7 +1077,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
> pr_info("stmmac xmit:\n"
> "\tskb addr %p - len: %d - nopaged_len: %d\n"
> "\tn_frags: %d - ip_summed: %d - %s gso\n",
> - skb, skb->len, skb_headlen(skb), nfrags, skb->ip_summed,
> + skb, skb->len, nopaged_len, nfrags, skb->ip_summed,
> !skb_is_gso(skb) ? "isn't" : "is");
> #endif
>
> @@ -1116,14 +1090,14 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
> if ((nfrags > 0) || (skb->len > ETH_FRAME_LEN))
> pr_debug("stmmac xmit: skb len: %d, nopaged_len: %d,\n"
> "\t\tn_frags: %d, ip_summed: %d\n",
> - skb->len, skb_headlen(skb), nfrags, skb->ip_summed);
> + skb->len, nopaged_len, nfrags, skb->ip_summed);
> #endif
> priv->tx_skbuff[entry] = skb;
> - if (unlikely(skb->len >= BUF_SIZE_4KiB)) {
> - entry = stmmac_handle_jumbo_frames(skb, dev, csum_insertion);
> +
> + if (priv->hw->ring->is_jumbo_frm(skb->len, priv->plat->enh_desc)) {
> + entry = priv->hw->ring->jumbo_frm(priv, skb, csum_insertion);
> desc = priv->dma_tx + entry;
> } else {
> - unsigned int nopaged_len = skb_headlen(skb);
> desc->des2 = dma_map_single(priv->device, skb->data,
> nopaged_len, DMA_TO_DEVICE);
> priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len,
> @@ -1214,11 +1188,10 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
> DMA_FROM_DEVICE);
>
> (p + entry)->des2 = priv->rx_skbuff_dma[entry];
> - if (unlikely(priv->plat->has_gmac)) {
> - if (bfsize >= BUF_SIZE_8KiB)
> - (p + entry)->des3 =
> - (p + entry)->des2 + BUF_SIZE_8KiB;
> - }
> +
> + if (unlikely(priv->plat->has_gmac))
> + priv->hw->ring->refill_desc3(bfsize, p + entry);
> +
> RX_DBG(KERN_INFO "\trefill entry #%d\n", entry);
> }
> wmb();
> @@ -1795,6 +1768,7 @@ static int stmmac_mac_device_setup(struct net_device *dev)
> device->desc = &ndesc_ops;
>
> priv->hw = device;
> + priv->hw->ring = &ring_mode_ops;
>
> if (device_can_wakeup(priv->device)) {
> priv->wolopts = WAKE_MAGIC; /* Magic Frame as default */
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists