* [PATCH net] inet: frags: remove the WARN_ON from inet_evict_bucket
From: Nikolay Aleksandrov @ 2014-10-28 9:44 UTC (permalink / raw)
To: netdev; +Cc: Nikolay Aleksandrov, Florian Westphal, Eric Dumazet,
Patrick McLean
In-Reply-To: <1414455409.4845.1.camel@edumazet-glaptop2.roam.corp.google.com>
The WARN_ON in inet_evict_bucket can be triggered by a valid case:
inet_frag_kill and inet_evict_bucket can be running in parallel on the
same queue which means that there has been at least one more ref added
by a previous inet_frag_find call, but inet_frag_kill can delete the
timer before inet_evict_bucket which will cause the WARN_ON() there to
trigger since we'll have refcnt!=1. Now, this case is valid because the
queue is being "killed" for some reason (removed from the chain list and
its timer deleted) so it will get destroyed in the end by one of the
inet_frag_put() calls which reaches 0 i.e. refcnt is still valid.
CC: Florian Westphal <fw@strlen.de>
CC: Eric Dumazet <eric.dumazet@gmail.com>
CC: Patrick McLean <chutzpah@gentoo.org>
Fixes: b13d3cbfb8e8 ("inet: frag: move eviction of queues to work queue")
Reported-by: Patrick McLean <chutzpah@gentoo.org>
Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com>
---
I'm sending this as a separate patch so the race fix doesn't get blocked
in case I'm wrong and also it's a different issue.
net/ipv4/inet_fragment.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
index 894ec30c5896..19419b60cb37 100644
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -146,7 +146,6 @@ evict_again:
atomic_inc(&fq->refcnt);
spin_unlock(&hb->chain_lock);
del_timer_sync(&fq->timer);
- WARN_ON(atomic_read(&fq->refcnt) != 1);
inet_frag_put(fq, f);
goto evict_again;
}
--
1.9.3
^ permalink raw reply related
* Re: [PATCH net] inet: frags: fix a race between inet_evict_bucket and inet_frag_kill
From: Florian Westphal @ 2014-10-28 10:03 UTC (permalink / raw)
To: Nikolay Aleksandrov
Cc: netdev, Florian Westphal, Eric Dumazet, Patrick McLean
In-Reply-To: <1414488634-28412-1-git-send-email-nikolay@redhat.com>
Nikolay Aleksandrov <nikolay@redhat.com> wrote:
> When the evictor is running it adds some chosen frags to a local list to
> be evicted once the chain lock has been released but at the same time
> the *frag_queue can be running for some of the same queues and it
> may call inet_frag_kill which will wait on the chain lock and
> will then delete the queue from the wrong list since it was added in the
> eviction one.
I had to read that twice...
cpu1 cpu2
inet_evict_bucket inet_frag_kill
chain_lock() chain_lock() ..
for_each_frag_queue spin
set fragqueue INET_FRAG_EVICTED flag [A] .
hlist_del() spin
hlist_add (to private list) .
spin
chain_unlock .
chain_lock returns
for_each_frag_queue_on_private_list hlist_del() [B]
frag_expire(fq) // destroy/free queue
[B] we may delete entry on the evictors private list.
since [A] is only set with chainlock held, other cpus
killing an entry can use INET_FRAG_EVICTED to test if the
entry is about to be removed by the evictor.
> The fix is simple - check if the queue has the evict flag
> set under the chain lock before deleting it, this is safe because the
> evict flag is set only under that lock and having the flag set also means
> that the queue has been detached from the chain list, so no need to delete
> it again.
Right, thanks everyone.
> ---
> A few more eyes to confirm all of this would be much appreciated.
Looks correct,
Reviewed-by: Florian Westphal <fw@strlen.de>
^ permalink raw reply
* Re: netfilter: nf_conntrack: there maybe a bug in __nf_conntrack_confirm, when it race against get_next_corpse
From: Jesper Dangaard Brouer @ 2014-10-28 10:11 UTC (permalink / raw)
To: billbonaparte
Cc: linux-kernel, 'Netfilter Developer Mailing List',
'Pablo Neira Ayuso', 'Patrick McHardy', kadlec,
davem, 'Changli Gao', 'Andrey Vagin', brouer,
netdev@vger.kernel.org
In-Reply-To: <02f201cff260$8622e610$9268b230$@gmail.com>
On Tue, 28 Oct 2014 11:37:31 +0800 "billbonaparte" <programme110@gmail.com> wrote:
> Hi, all:
> sorry for sending this mail again, the last mail doesn't show text
> clearly.
This one also mangles the text, so I cannot follow the race you are
describing. I'll try to reconstruct...
> In function __nf_conntrack_confirm, we check the conntrack if it was
> already dead, before insert it into hash-table.
> We do this because if we insert an already 'dead' hash, it will
> block further use of that particular connection.
Have you run into this problem in practice, or is this based on a
theory?
> but we don't do that right.
> let's consider the following case:
>
[tried to reconstruct]
> cpu1 cpu2
> __nf_conntrack_confirm get_next_corpse
> lock corresponding hash-list ....
> check nf_ct_is_dying(ct) ....
> ..... for_each_possible_cpu(cpu) {
> ..... (processing &pcpu->unconfirmed)
> ..... spin_lock_bh(&pcpu->lock);
> ..... set_bit(IPS_DYING_BIT, &ct->status);
> ..... spin_unlock_bh(&pcpu_lock);
> spin_lock_bh(&pcpu->lock);
> nf_ct_del_from_dying_or_unconfirmed_list(ct);
> spin_unlock_bh(&pcpu_lock);
>
> add_timer(&ct->timeout);
> ct->status |= IPS_CONFIRMED;
> __nf_conntrack_hash_insert(ct);
> /* the conntrack has been seted as dying*/
Yes, I think you are correct. There is a race. As we are modifying
the ct->status, without holding the hash bucket lock.
> The above case reveal two problems:
> 1. we may insert a dead conntrack to hash-table, it will block
> further use of that particular connection.
> 2. operation on ct->status should be atomic, because it race aginst
> get_next_corpse.
> due to this reason, the operation on ct->status in
> nf_nat_setup_info should be atomic as well.
>
> if we want to resolve the first problem, we must delete the
> unconfirmed conntrack from unconfirmed-list first, then check if it is
> already dead.
Guess that would be one approach.
> Am I right to do this ?
> Appreciate any comments and reply.
Perhaps we could get rid of unconfirmed list handling in get_next_corpse?
--
Best regards,
Jesper Dangaard Brouer
MSc.CS, Sr. Network Kernel Developer at Red Hat
Author of http://www.iptv-analyzer.org
LinkedIn: http://www.linkedin.com/in/brouer
^ permalink raw reply
* Re: [net 1/2] sctp: add transport state in /proc/net/sctp/remaddr
From: Neil Horman @ 2014-10-28 10:27 UTC (permalink / raw)
To: David Miller; +Cc: michele, linux-sctp, vyasevich, netdev, dborkman
In-Reply-To: <20141027.185545.551457974536550723.davem@davemloft.net>
On Mon, Oct 27, 2014 at 06:55:45PM -0400, David Miller wrote:
> From: Michele Baldessari <michele@acksyn.org>
> Date: Thu, 23 Oct 2014 21:48:40 +0200
>
> > It is often quite helpful to be able to know the state of a transport
> > outside of the application itself (for troubleshooting purposes or for
> > monitoring purposes). Add it under /proc/net/sctp/remaddr.
> >
> > Signed-off-by: Michele Baldessari <michele@acksyn.org>
>
> You can't change the layout of procfs files, applications parse
> these files and any modification can potentially break such tools.
>
> Secondly, even if this change were acceptable, targetting this
> change at anything other than the net-next tree is not appropriate
> because it is a new feature.
>
Agree on the net-next submission, though there is precident for extending this
procfile, as we've done it a few times in the past to this, and other files in
the sctp area (see commits f406c8b9693f2f71ef2caeb0b68521a7d22d00f0 and
58fbbed4fbc0094fc808a568fe99a915f85402ee)
Neil
^ permalink raw reply
* [PATCHv2 0/6] net: fec: fix regression on i.MX28 introduced by rx_copybreak support
From: Lothar Waßmann @ 2014-10-28 11:01 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Russell King, Frank Li, Fabio Estevam,
linux-kernel, Lothar Waßmann, linux-arm-kernel
Changes wrt. v1:
- added some cleanup patches
- simplify handling of 'quirks' flags as suggested by Russell King.
- remove DIV_ROUND_UP() from byte swapping loop as suggested by
Eric Dumazet
Subject:
In-Reply-To:
^ permalink raw reply
* [PATCHv2 1/6] net: fec: indentation cleanup; no functional change
From: Lothar Waßmann @ 2014-10-28 11:01 UTC (permalink / raw)
To: netdev
Cc: Fabio Estevam, Frank Li, linux-kernel, Russell King,
David S. Miller, linux-arm-kernel, Lothar Waßmann
In-Reply-To: <1414494104-27943-1-git-send-email-LW@KARO-electronics.de>
Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de>
---
drivers/net/ethernet/freescale/fec_main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index e364d1f..decea57 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -101,7 +101,7 @@ static void fec_enet_itr_coal_init(struct net_device *ndev);
* frames not being transmitted until there is a 0-to-1 transition on
* ENET_TDAR[TDAR].
*/
-#define FEC_QUIRK_ERR006358 (1 << 7)
+#define FEC_QUIRK_ERR006358 (1 << 7)
/* ENET IP hw AVB
*
* i.MX6SX ENET IP add Audio Video Bridging (AVB) feature support.
--
1.7.10.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCHv2 2/6] net: fec: declare bufdesc_ex flag as bool
From: Lothar Waßmann @ 2014-10-28 11:01 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Russell King, Frank Li, Fabio Estevam,
linux-kernel, Lothar Waßmann, linux-arm-kernel
In-Reply-To: <1414494104-27943-1-git-send-email-LW@KARO-electronics.de>
fep->bufdesc_ex is used as boolean flag; thus declare it as such.
Also remove an unnecessary initialization to 0.
Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de>
---
drivers/net/ethernet/freescale/fec.h | 2 +-
drivers/net/ethernet/freescale/fec_main.c | 4 +---
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 1e65917..2634de2 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -451,7 +451,7 @@ struct fec_enet_private {
int speed;
struct completion mdio_done;
int irq[FEC_IRQ_NUM];
- int bufdesc_ex;
+ bool bufdesc_ex;
int pause_flag;
struct napi_struct napi;
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index decea57..f7d344f 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -3209,8 +3209,6 @@ fec_probe(struct platform_device *pdev)
fep->pdev = pdev;
fep->dev_id = dev_id++;
- fep->bufdesc_ex = 0;
-
platform_set_drvdata(pdev, ndev);
phy_node = of_parse_phandle(np, "phy-handle", 0);
@@ -3268,7 +3266,7 @@ fec_probe(struct platform_device *pdev)
pdev->id_entry->driver_data & FEC_QUIRK_HAS_BUFDESC_EX;
if (IS_ERR(fep->clk_ptp)) {
fep->clk_ptp = NULL;
- fep->bufdesc_ex = 0;
+ fep->bufdesc_ex = false;
}
ret = fec_enet_clk_enable(ndev, true);
--
1.7.10.4
^ permalink raw reply related
* [PATCHv2 3/6] net: fec: improve access to quirk flags by copying them into fec_enet_private struct
From: Lothar Waßmann @ 2014-10-28 11:01 UTC (permalink / raw)
To: netdev
Cc: Fabio Estevam, Frank Li, linux-kernel, Russell King,
David S. Miller, linux-arm-kernel, Lothar Waßmann
In-Reply-To: <1414494104-27943-1-git-send-email-LW@KARO-electronics.de>
Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de>
---
drivers/net/ethernet/freescale/fec.h | 1 +
drivers/net/ethernet/freescale/fec_main.c | 105 ++++++++++-------------------
2 files changed, 38 insertions(+), 68 deletions(-)
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 2634de2..d43c1d3 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -453,6 +453,7 @@ struct fec_enet_private {
int irq[FEC_IRQ_NUM];
bool bufdesc_ex;
int pause_flag;
+ u32 quirks;
struct napi_struct napi;
int csum_flags;
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index f7d344f..323ae2e 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -392,8 +392,6 @@ fec_enet_txq_submit_frag_skb(struct fec_enet_priv_tx_q *txq,
struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
struct bufdesc *bdp = txq->cur_tx;
struct bufdesc_ex *ebdp;
int nr_frags = skb_shinfo(skb)->nr_frags;
@@ -429,7 +427,7 @@ fec_enet_txq_submit_frag_skb(struct fec_enet_priv_tx_q *txq,
}
if (fep->bufdesc_ex) {
- if (id_entry->driver_data & FEC_QUIRK_HAS_AVB)
+ if (fep->quirks & FEC_QUIRK_HAS_AVB)
estatus |= FEC_TX_BD_FTYPE(queue);
if (skb->ip_summed == CHECKSUM_PARTIAL)
estatus |= BD_ENET_TX_PINS | BD_ENET_TX_IINS;
@@ -441,11 +439,11 @@ fec_enet_txq_submit_frag_skb(struct fec_enet_priv_tx_q *txq,
index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
if (((unsigned long) bufaddr) & fep->tx_align ||
- id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
+ fep->quirks & FEC_QUIRK_SWAP_FRAME) {
memcpy(txq->tx_bounce[index], bufaddr, frag_len);
bufaddr = txq->tx_bounce[index];
- if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
+ if (fep->quirks & FEC_QUIRK_SWAP_FRAME)
swap_buffer(bufaddr, frag_len);
}
@@ -481,8 +479,6 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq,
struct sk_buff *skb, struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
int nr_frags = skb_shinfo(skb)->nr_frags;
struct bufdesc *bdp, *last_bdp;
void *bufaddr;
@@ -521,11 +517,11 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq,
queue = skb_get_queue_mapping(skb);
index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
if (((unsigned long) bufaddr) & fep->tx_align ||
- id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
+ fep->quirks & FEC_QUIRK_SWAP_FRAME) {
memcpy(txq->tx_bounce[index], skb->data, buflen);
bufaddr = txq->tx_bounce[index];
- if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
+ if (fep->quirks & FEC_QUIRK_SWAP_FRAME)
swap_buffer(bufaddr, buflen);
}
@@ -560,7 +556,7 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq,
fep->hwts_tx_en))
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
- if (id_entry->driver_data & FEC_QUIRK_HAS_AVB)
+ if (fep->quirks & FEC_QUIRK_HAS_AVB)
estatus |= FEC_TX_BD_FTYPE(queue);
if (skb->ip_summed == CHECKSUM_PARTIAL)
@@ -604,8 +600,6 @@ fec_enet_txq_put_data_tso(struct fec_enet_priv_tx_q *txq, struct sk_buff *skb,
int size, bool last_tcp, bool is_last)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
struct bufdesc_ex *ebdp = container_of(bdp, struct bufdesc_ex, desc);
unsigned short queue = skb_get_queue_mapping(skb);
unsigned short status;
@@ -618,11 +612,11 @@ fec_enet_txq_put_data_tso(struct fec_enet_priv_tx_q *txq, struct sk_buff *skb,
status |= (BD_ENET_TX_TC | BD_ENET_TX_READY);
if (((unsigned long) data) & fep->tx_align ||
- id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
+ fep->quirks & FEC_QUIRK_SWAP_FRAME) {
memcpy(txq->tx_bounce[index], data, size);
data = txq->tx_bounce[index];
- if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
+ if (fep->quirks & FEC_QUIRK_SWAP_FRAME)
swap_buffer(data, size);
}
@@ -638,7 +632,7 @@ fec_enet_txq_put_data_tso(struct fec_enet_priv_tx_q *txq, struct sk_buff *skb,
bdp->cbd_bufaddr = addr;
if (fep->bufdesc_ex) {
- if (id_entry->driver_data & FEC_QUIRK_HAS_AVB)
+ if (fep->quirks & FEC_QUIRK_HAS_AVB)
estatus |= FEC_TX_BD_FTYPE(queue);
if (skb->ip_summed == CHECKSUM_PARTIAL)
estatus |= BD_ENET_TX_PINS | BD_ENET_TX_IINS;
@@ -666,8 +660,6 @@ fec_enet_txq_put_hdr_tso(struct fec_enet_priv_tx_q *txq,
struct bufdesc *bdp, int index)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
struct bufdesc_ex *ebdp = container_of(bdp, struct bufdesc_ex, desc);
unsigned short queue = skb_get_queue_mapping(skb);
@@ -683,11 +675,11 @@ fec_enet_txq_put_hdr_tso(struct fec_enet_priv_tx_q *txq,
bufaddr = txq->tso_hdrs + index * TSO_HEADER_SIZE;
dmabuf = txq->tso_hdrs_dma + index * TSO_HEADER_SIZE;
if (((unsigned long)bufaddr) & fep->tx_align ||
- id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
+ fep->quirks & FEC_QUIRK_SWAP_FRAME) {
memcpy(txq->tx_bounce[index], skb->data, hdr_len);
bufaddr = txq->tx_bounce[index];
- if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
+ if (fep->quirks & FEC_QUIRK_SWAP_FRAME)
swap_buffer(bufaddr, hdr_len);
dmabuf = dma_map_single(&fep->pdev->dev, bufaddr,
@@ -704,7 +696,7 @@ fec_enet_txq_put_hdr_tso(struct fec_enet_priv_tx_q *txq,
bdp->cbd_datlen = hdr_len;
if (fep->bufdesc_ex) {
- if (id_entry->driver_data & FEC_QUIRK_HAS_AVB)
+ if (fep->quirks & FEC_QUIRK_HAS_AVB)
estatus |= FEC_TX_BD_FTYPE(queue);
if (skb->ip_summed == CHECKSUM_PARTIAL)
estatus |= BD_ENET_TX_PINS | BD_ENET_TX_IINS;
@@ -729,8 +721,6 @@ static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq,
struct tso_t tso;
unsigned int index = 0;
int ret;
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
if (tso_count_descs(skb) >= fec_enet_get_free_txdesc_num(fep, txq)) {
dev_kfree_skb_any(skb);
@@ -792,7 +782,7 @@ static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq,
txq->cur_tx = bdp;
/* Trigger transmission start */
- if (!(id_entry->driver_data & FEC_QUIRK_ERR007885) ||
+ if (!(fep->quirks & FEC_QUIRK_ERR007885) ||
!readl(fep->hwp + FEC_X_DES_ACTIVE(queue)) ||
!readl(fep->hwp + FEC_X_DES_ACTIVE(queue)) ||
!readl(fep->hwp + FEC_X_DES_ACTIVE(queue)) ||
@@ -955,8 +945,6 @@ static void
fec_restart(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
u32 val;
u32 temp_mac[2];
u32 rcntl = OPT_FRAME_SIZE | 0x04;
@@ -966,7 +954,7 @@ fec_restart(struct net_device *ndev)
* For i.MX6SX SOC, enet use AXI bus, we use disable MAC
* instead of reset MAC itself.
*/
- if (id_entry && id_entry->driver_data & FEC_QUIRK_HAS_AVB) {
+ if (fep->quirks & FEC_QUIRK_HAS_AVB) {
writel(0, fep->hwp + FEC_ECNTRL);
} else {
writel(1, fep->hwp + FEC_ECNTRL);
@@ -977,7 +965,7 @@ fec_restart(struct net_device *ndev)
* enet-mac reset will reset mac address registers too,
* so need to reconfigure it.
*/
- if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
+ if (fep->quirks & FEC_QUIRK_ENET_MAC) {
memcpy(&temp_mac, ndev->dev_addr, ETH_ALEN);
writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW);
writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH);
@@ -1023,7 +1011,7 @@ fec_restart(struct net_device *ndev)
* The phy interface and speed need to get configured
* differently on enet-mac.
*/
- if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
+ if (fep->quirks & FEC_QUIRK_ENET_MAC) {
/* Enable flow control and length check */
rcntl |= 0x40000000 | 0x00000020;
@@ -1046,7 +1034,7 @@ fec_restart(struct net_device *ndev)
}
} else {
#ifdef FEC_MIIGSK_ENR
- if (id_entry->driver_data & FEC_QUIRK_USE_GASKET) {
+ if (fep->quirks & FEC_QUIRK_USE_GASKET) {
u32 cfgr;
/* disable the gasket and wait */
writel(0, fep->hwp + FEC_MIIGSK_ENR);
@@ -1099,7 +1087,7 @@ fec_restart(struct net_device *ndev)
writel(0, fep->hwp + FEC_HASH_TABLE_LOW);
#endif
- if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
+ if (fep->quirks & FEC_QUIRK_ENET_MAC) {
/* enable ENET endian swap */
ecntl |= (1 << 8);
/* enable ENET store and forward mode */
@@ -1133,8 +1121,6 @@ static void
fec_stop(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8);
/* We cannot expect a graceful transmit stop without link !!! */
@@ -1149,7 +1135,7 @@ fec_stop(struct net_device *ndev)
* For i.MX6SX SOC, enet use AXI bus, we use disable MAC
* instead of reset MAC itself.
*/
- if (id_entry && id_entry->driver_data & FEC_QUIRK_HAS_AVB) {
+ if (fep->quirks & FEC_QUIRK_HAS_AVB) {
writel(0, fep->hwp + FEC_ECNTRL);
} else {
writel(1, fep->hwp + FEC_ECNTRL);
@@ -1159,7 +1145,7 @@ fec_stop(struct net_device *ndev)
writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
/* We have to keep ENET enabled to have MII interrupt stay working */
- if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
+ if (fep->quirks & FEC_QUIRK_ENET_MAC) {
writel(2, fep->hwp + FEC_ECNTRL);
writel(rmii_mode, fep->hwp + FEC_R_CNTRL);
}
@@ -1378,8 +1364,6 @@ static int
fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
struct fec_enet_priv_rx_q *rxq;
struct bufdesc *bdp;
unsigned short status;
@@ -1471,7 +1455,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
prefetch(skb->data - NET_IP_ALIGN);
skb_put(skb, pkt_len - 4);
data = skb->data;
- if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
+ if (fep->quirks & FEC_QUIRK_SWAP_FRAME)
swap_buffer(data, pkt_len);
/* Extract the enhanced buffer descriptor */
@@ -1905,8 +1889,6 @@ failed_clk_ipg:
static int fec_enet_mii_probe(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
struct phy_device *phy_dev = NULL;
char mdio_bus_id[MII_BUS_ID_SIZE];
char phy_name[MII_BUS_ID_SIZE + 3];
@@ -1952,7 +1934,7 @@ static int fec_enet_mii_probe(struct net_device *ndev)
}
/* mask with MAC supported features */
- if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT) {
+ if (fep->quirks & FEC_QUIRK_HAS_GBIT) {
phy_dev->supported &= PHY_GBIT_FEATURES;
phy_dev->supported &= ~SUPPORTED_1000baseT_Half;
#if !defined(CONFIG_M5272)
@@ -1980,8 +1962,6 @@ static int fec_enet_mii_init(struct platform_device *pdev)
static struct mii_bus *fec0_mii_bus;
struct net_device *ndev = platform_get_drvdata(pdev);
struct fec_enet_private *fep = netdev_priv(ndev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
struct device_node *node;
int err = -ENXIO, i;
@@ -2001,7 +1981,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)
* mdio interface in board design, and need to be configured by
* fec0 mii_bus.
*/
- if ((id_entry->driver_data & FEC_QUIRK_ENET_MAC) && fep->dev_id > 0) {
+ if ((fep->quirks & FEC_QUIRK_ENET_MAC) && fep->dev_id > 0) {
/* fec1 uses fec0 mii_bus */
if (mii_cnt && fec0_mii_bus) {
fep->mii_bus = fec0_mii_bus;
@@ -2022,7 +2002,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)
* document.
*/
fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 5000000);
- if (id_entry->driver_data & FEC_QUIRK_ENET_MAC)
+ if (fep->quirks & FEC_QUIRK_ENET_MAC)
fep->phy_speed--;
fep->phy_speed <<= 1;
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
@@ -2064,7 +2044,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)
mii_cnt++;
/* save fec0 mii_bus */
- if (id_entry->driver_data & FEC_QUIRK_ENET_MAC)
+ if (fep->quirks & FEC_QUIRK_ENET_MAC)
fec0_mii_bus = fep->mii_bus;
return 0;
@@ -2333,11 +2313,9 @@ static int fec_enet_us_to_itr_clock(struct net_device *ndev, int us)
static void fec_enet_itr_coal_set(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
int rx_itr, tx_itr;
- if (!(id_entry->driver_data & FEC_QUIRK_HAS_AVB))
+ if (!(fep->quirks & FEC_QUIRK_HAS_AVB))
return;
/* Must be greater than zero to avoid unpredictable behavior */
@@ -2372,10 +2350,8 @@ static int
fec_enet_get_coalesce(struct net_device *ndev, struct ethtool_coalesce *ec)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
- if (!(id_entry->driver_data & FEC_QUIRK_HAS_AVB))
+ if (!(fep->quirks & FEC_QUIRK_HAS_AVB))
return -EOPNOTSUPP;
ec->rx_coalesce_usecs = fep->rx_time_itr;
@@ -2391,12 +2367,9 @@ static int
fec_enet_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *ec)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
-
unsigned int cycle;
- if (!(id_entry->driver_data & FEC_QUIRK_HAS_AVB))
+ if (!(fep->quirks & FEC_QUIRK_HAS_AVB))
return -EOPNOTSUPP;
if (ec->rx_max_coalesced_frames > 255) {
@@ -2976,8 +2949,6 @@ static const struct net_device_ops fec_netdev_ops = {
static int fec_enet_init(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
struct fec_enet_priv_tx_q *txq;
struct fec_enet_priv_rx_q *rxq;
struct bufdesc *cbd_base;
@@ -3056,11 +3027,11 @@ static int fec_enet_init(struct net_device *ndev)
writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK);
netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, NAPI_POLL_WEIGHT);
- if (id_entry->driver_data & FEC_QUIRK_HAS_VLAN)
+ if (fep->quirks & FEC_QUIRK_HAS_VLAN)
/* enable hw VLAN support */
ndev->features |= NETIF_F_HW_VLAN_CTAG_RX;
- if (id_entry->driver_data & FEC_QUIRK_HAS_CSUM) {
+ if (fep->quirks & FEC_QUIRK_HAS_CSUM) {
ndev->gso_max_segs = FEC_MAX_TSO_SEGS;
/* enable hw accelerator */
@@ -3069,7 +3040,7 @@ static int fec_enet_init(struct net_device *ndev)
fep->csum_flags |= FLAG_RX_CSUM_ENABLED;
}
- if (id_entry->driver_data & FEC_QUIRK_HAS_AVB) {
+ if (fep->quirks & FEC_QUIRK_HAS_AVB) {
fep->tx_align = 0;
fep->rx_align = 0x3f;
}
@@ -3169,10 +3140,6 @@ fec_probe(struct platform_device *pdev)
int num_tx_qs;
int num_rx_qs;
- of_id = of_match_device(fec_dt_ids, &pdev->dev);
- if (of_id)
- pdev->id_entry = of_id->data;
-
fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs);
/* Init network device */
@@ -3186,13 +3153,16 @@ fec_probe(struct platform_device *pdev)
/* setup board info structure */
fep = netdev_priv(ndev);
+ of_id = of_match_device(fec_dt_ids, &pdev->dev);
+ if (of_id)
+ fep->quirks = (u32)of_id->data;
+
fep->num_rx_queues = num_rx_qs;
fep->num_tx_queues = num_tx_qs;
#if !defined(CONFIG_M5272)
/* default enable pause frame auto negotiation */
- if (pdev->id_entry &&
- (pdev->id_entry->driver_data & FEC_QUIRK_HAS_GBIT))
+ if (fep->quirks & FEC_QUIRK_HAS_GBIT)
fep->pause_flag |= FEC_PAUSE_FLAG_AUTONEG;
#endif
@@ -3261,9 +3231,8 @@ fec_probe(struct platform_device *pdev)
if (IS_ERR(fep->clk_ref))
fep->clk_ref = NULL;
+ fep->bufdesc_ex = fep->quirks & FEC_QUIRK_HAS_BUFDESC_EX;
fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp");
- fep->bufdesc_ex =
- pdev->id_entry->driver_data & FEC_QUIRK_HAS_BUFDESC_EX;
if (IS_ERR(fep->clk_ptp)) {
fep->clk_ptp = NULL;
fep->bufdesc_ex = false;
--
1.7.10.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCHv2 4/6] net: fec: use swab32s() instead of cpu_to_be32()
From: Lothar Waßmann @ 2014-10-28 11:01 UTC (permalink / raw)
To: netdev
Cc: Fabio Estevam, Frank Li, linux-kernel, Russell King,
David S. Miller, linux-arm-kernel, Lothar Waßmann
In-Reply-To: <1414494104-27943-1-git-send-email-LW@KARO-electronics.de>
when swap_buffer() is being called, we know for sure, that we need to
byte swap the data. Also this function is called for swapping data in
both directions. Thus cpu_to_be32() is semantically not correct for
all use cases. Use swab32s() to reflect this.
Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de>
---
drivers/net/ethernet/freescale/fec_main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 323ae2e..3a103e9 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -334,7 +334,7 @@ static void *swap_buffer(void *bufaddr, int len)
unsigned int *buf = bufaddr;
for (i = 0; i < DIV_ROUND_UP(len, 4); i++, buf++)
- *buf = cpu_to_be32(*buf);
+ swab32s(buf);
return bufaddr;
}
--
1.7.10.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCHv2 5/6] net: fec: simplify loop counter handling in swap_buffer()
From: Lothar Waßmann @ 2014-10-28 11:01 UTC (permalink / raw)
To: netdev
Cc: Fabio Estevam, Frank Li, linux-kernel, Russell King,
David S. Miller, linux-arm-kernel, Lothar Waßmann
In-Reply-To: <1414494104-27943-1-git-send-email-LW@KARO-electronics.de>
Eliminate the DIV_ROUND_UP() and change the loop counter increment to
4 instead. This results in saving 6 instructions in the functions
assembly code.
Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de>
---
drivers/net/ethernet/freescale/fec_main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 3a103e9..404fb9d 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -333,7 +333,7 @@ static void *swap_buffer(void *bufaddr, int len)
int i;
unsigned int *buf = bufaddr;
- for (i = 0; i < DIV_ROUND_UP(len, 4); i++, buf++)
+ for (i = 0; i < len; i += 4, buf++)
swab32s(buf);
return bufaddr;
--
1.7.10.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCHv2 6/6] net: fec: fix regression on i.MX28 introduced by rx_copybreak support
From: Lothar Waßmann @ 2014-10-28 11:01 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Russell King, Frank Li, Fabio Estevam,
linux-kernel, Lothar Waßmann, linux-arm-kernel
In-Reply-To: <1414494104-27943-1-git-send-email-LW@KARO-electronics.de>
commit 1b7bde6d659d ("net: fec: implement rx_copybreak to improve rx performance")
introduced a regression for i.MX28. The swap_buffer() function doing
the endian conversion of the received data on i.MX28 may access memory
beyond the actual packet size in the DMA buffer. fec_enet_copybreak()
does not copy those bytes, so that the last bytes of a packet may be
filled with invalid data after swapping.
This will likely lead to checksum errors on received packets.
E.g. when trying to mount an NFS rootfs:
UDP: bad checksum. From 192.168.1.225:111 to 192.168.100.73:44662 ulen 36
Do the byte swapping and copying to the new skb in one go if
necessary.
Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de>
---
drivers/net/ethernet/freescale/fec_main.c | 25 +++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 404fb9d..b92324c 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -339,6 +339,18 @@ static void *swap_buffer(void *bufaddr, int len)
return bufaddr;
}
+static void *swap_buffer2(void *dst_buf, void *src_buf, int len)
+{
+ int i;
+ unsigned int *src = src_buf;
+ unsigned int *dst = dst_buf;
+
+ for (i = 0; i < len; i += 4, src++, dst++)
+ swab32s(src);
+
+ return dst_buf;
+}
+
static void fec_dump(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
@@ -1334,7 +1346,7 @@ fec_enet_new_rxbdp(struct net_device *ndev, struct bufdesc *bdp, struct sk_buff
}
static bool fec_enet_copybreak(struct net_device *ndev, struct sk_buff **skb,
- struct bufdesc *bdp, u32 length)
+ struct bufdesc *bdp, u32 length, bool swap)
{
struct fec_enet_private *fep = netdev_priv(ndev);
struct sk_buff *new_skb;
@@ -1349,7 +1361,10 @@ static bool fec_enet_copybreak(struct net_device *ndev, struct sk_buff **skb,
dma_sync_single_for_cpu(&fep->pdev->dev, bdp->cbd_bufaddr,
FEC_ENET_RX_FRSIZE - fep->rx_align,
DMA_FROM_DEVICE);
- memcpy(new_skb->data, (*skb)->data, length);
+ if (!swap)
+ memcpy(new_skb->data, (*skb)->data, length);
+ else
+ swap_buffer2(new_skb->data, (*skb)->data, length);
*skb = new_skb;
return true;
@@ -1377,6 +1392,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
u16 vlan_tag;
int index = 0;
bool is_copybreak;
+ bool need_swap = fep->quirks & FEC_QUIRK_SWAP_FRAME;
#ifdef CONFIG_M532x
flush_cache_all();
@@ -1440,7 +1456,8 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
* include that when passing upstream as it messes up
* bridging applications.
*/
- is_copybreak = fec_enet_copybreak(ndev, &skb, bdp, pkt_len - 4);
+ is_copybreak = fec_enet_copybreak(ndev, &skb, bdp, pkt_len - 4,
+ need_swap);
if (!is_copybreak) {
skb_new = netdev_alloc_skb(ndev, FEC_ENET_RX_FRSIZE);
if (unlikely(!skb_new)) {
@@ -1455,7 +1472,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
prefetch(skb->data - NET_IP_ALIGN);
skb_put(skb, pkt_len - 4);
data = skb->data;
- if (fep->quirks & FEC_QUIRK_SWAP_FRAME)
+ if (!is_copybreak && need_swap)
swap_buffer(data, pkt_len);
/* Extract the enhanced buffer descriptor */
--
1.7.10.4
^ permalink raw reply related
* RE: [PATCHv2 6/6] net: fec: fix regression on i.MX28 introduced by rx_copybreak support
From: David Laight @ 2014-10-28 11:12 UTC (permalink / raw)
To: 'Lothar Waßmann', netdev@vger.kernel.org
Cc: David S. Miller, Russell King, Frank Li, Fabio Estevam,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <1414494104-27943-7-git-send-email-LW@KARO-electronics.de>
From: Lothar Waßmann
> commit 1b7bde6d659d ("net: fec: implement rx_copybreak to improve rx performance")
> introduced a regression for i.MX28. The swap_buffer() function doing
> the endian conversion of the received data on i.MX28 may access memory
> beyond the actual packet size in the DMA buffer. fec_enet_copybreak()
> does not copy those bytes, so that the last bytes of a packet may be
> filled with invalid data after swapping.
> This will likely lead to checksum errors on received packets.
> E.g. when trying to mount an NFS rootfs:
> UDP: bad checksum. From 192.168.1.225:111 to 192.168.100.73:44662 ulen 36
>
> Do the byte swapping and copying to the new skb in one go if
> necessary.
>
> Signed-off-by: Lothar Wamann <LW@KARO-electronics.de>
> ---
> drivers/net/ethernet/freescale/fec_main.c | 25 +++++++++++++++++++++----
> 1 file changed, 21 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
> index 404fb9d..b92324c 100644
> --- a/drivers/net/ethernet/freescale/fec_main.c
> +++ b/drivers/net/ethernet/freescale/fec_main.c
> @@ -339,6 +339,18 @@ static void *swap_buffer(void *bufaddr, int len)
> return bufaddr;
> }
>
> +static void *swap_buffer2(void *dst_buf, void *src_buf, int len)
> +{
> + int i;
> + unsigned int *src = src_buf;
> + unsigned int *dst = dst_buf;
> +
> + for (i = 0; i < len; i += 4, src++, dst++)
> + swab32s(src);
This will probably benefit from being unrolled slightly.
Neither 'dst' nor the return value is used.
> +
> + return dst_buf;
> +}
> +
> static void fec_dump(struct net_device *ndev)
> {
> struct fec_enet_private *fep = netdev_priv(ndev);
> @@ -1334,7 +1346,7 @@ fec_enet_new_rxbdp(struct net_device *ndev, struct bufdesc *bdp, struct sk_buff
> }
>
> static bool fec_enet_copybreak(struct net_device *ndev, struct sk_buff **skb,
> - struct bufdesc *bdp, u32 length)
> + struct bufdesc *bdp, u32 length, bool swap)
> {
> struct fec_enet_private *fep = netdev_priv(ndev);
> struct sk_buff *new_skb;
> @@ -1349,7 +1361,10 @@ static bool fec_enet_copybreak(struct net_device *ndev, struct sk_buff **skb,
> dma_sync_single_for_cpu(&fep->pdev->dev, bdp->cbd_bufaddr,
> FEC_ENET_RX_FRSIZE - fep->rx_align,
> DMA_FROM_DEVICE);
> - memcpy(new_skb->data, (*skb)->data, length);
> + if (!swap)
> + memcpy(new_skb->data, (*skb)->data, length);
> + else
> + swap_buffer2(new_skb->data, (*skb)->data, length);
> *skb = new_skb;
>
> return true;
> @@ -1377,6 +1392,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
> u16 vlan_tag;
> int index = 0;
> bool is_copybreak;
> + bool need_swap = fep->quirks & FEC_QUIRK_SWAP_FRAME;
>
> #ifdef CONFIG_M532x
> flush_cache_all();
> @@ -1440,7 +1456,8 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
> * include that when passing upstream as it messes up
> * bridging applications.
> */
> - is_copybreak = fec_enet_copybreak(ndev, &skb, bdp, pkt_len - 4);
> + is_copybreak = fec_enet_copybreak(ndev, &skb, bdp, pkt_len - 4,
> + need_swap);
> if (!is_copybreak) {
> skb_new = netdev_alloc_skb(ndev, FEC_ENET_RX_FRSIZE);
> if (unlikely(!skb_new)) {
> @@ -1455,7 +1472,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
> prefetch(skb->data - NET_IP_ALIGN);
> skb_put(skb, pkt_len - 4);
> data = skb->data;
> - if (fep->quirks & FEC_QUIRK_SWAP_FRAME)
> + if (!is_copybreak && need_swap)
> swap_buffer(data, pkt_len);
It has to be better to set the 'copybreak' limit to be larger than the
maximum frame size and so always go through the 'copybreak' paths.
>
> /* Extract the enhanced buffer descriptor */
> --
> 1.7.10.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* RE: [PATCHv2 6/6] net: fec: fix regression on i.MX28 introduced by rx_copybreak support
From: David Laight @ 2014-10-28 11:14 UTC (permalink / raw)
To: 'Lothar Waßmann', netdev@vger.kernel.org
Cc: David S. Miller, Russell King, Frank Li, Fabio Estevam,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <1414494104-27943-7-git-send-email-LW@KARO-electronics.de>
From: Lothar Waßmann
> commit 1b7bde6d659d ("net: fec: implement rx_copybreak to improve rx performance")
> introduced a regression for i.MX28. The swap_buffer() function doing
> the endian conversion of the received data on i.MX28 may access memory
> beyond the actual packet size in the DMA buffer. fec_enet_copybreak()
> does not copy those bytes, so that the last bytes of a packet may be
> filled with invalid data after swapping.
> This will likely lead to checksum errors on received packets.
> E.g. when trying to mount an NFS rootfs:
> UDP: bad checksum. From 192.168.1.225:111 to 192.168.100.73:44662 ulen 36
>
> Do the byte swapping and copying to the new skb in one go if
> necessary.
>
> Signed-off-by: Lothar Wamann <LW@KARO-electronics.de>
> ---
> drivers/net/ethernet/freescale/fec_main.c | 25 +++++++++++++++++++++----
> 1 file changed, 21 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
> index 404fb9d..b92324c 100644
> --- a/drivers/net/ethernet/freescale/fec_main.c
> +++ b/drivers/net/ethernet/freescale/fec_main.c
> @@ -339,6 +339,18 @@ static void *swap_buffer(void *bufaddr, int len)
> return bufaddr;
> }
>
> +static void *swap_buffer2(void *dst_buf, void *src_buf, int len)
> +{
> + int i;
> + unsigned int *src = src_buf;
> + unsigned int *dst = dst_buf;
> +
> + for (i = 0; i < len; i += 4, src++, dst++)
> + swab32s(src);
> +
> + return dst_buf;
> +}
> +
Actually that is completely f*cked....
David
^ permalink raw reply
* Re: [PATCHv2 6/6] net: fec: fix regression on i.MX28 introduced by rx_copybreak support
From: Lothar Waßmann @ 2014-10-28 12:10 UTC (permalink / raw)
To: David Laight
Cc: netdev@vger.kernel.org, David S. Miller, Russell King, Frank Li,
Fabio Estevam, linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <063D6719AE5E284EB5DD2968C1650D6D1C9E04DB@AcuExch.aculab.com>
Hi,
David Laight wrote:
> From: Lothar Waßmann
> > commit 1b7bde6d659d ("net: fec: implement rx_copybreak to improve rx performance")
> > introduced a regression for i.MX28. The swap_buffer() function doing
> > the endian conversion of the received data on i.MX28 may access memory
> > beyond the actual packet size in the DMA buffer. fec_enet_copybreak()
> > does not copy those bytes, so that the last bytes of a packet may be
> > filled with invalid data after swapping.
> > This will likely lead to checksum errors on received packets.
> > E.g. when trying to mount an NFS rootfs:
> > UDP: bad checksum. From 192.168.1.225:111 to 192.168.100.73:44662 ulen 36
> >
> > Do the byte swapping and copying to the new skb in one go if
> > necessary.
> >
> > Signed-off-by: Lothar Wamann <LW@KARO-electronics.de>
> > ---
> > drivers/net/ethernet/freescale/fec_main.c | 25 +++++++++++++++++++++----
> > 1 file changed, 21 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
> > index 404fb9d..b92324c 100644
> > --- a/drivers/net/ethernet/freescale/fec_main.c
> > +++ b/drivers/net/ethernet/freescale/fec_main.c
> > @@ -339,6 +339,18 @@ static void *swap_buffer(void *bufaddr, int len)
> > return bufaddr;
> > }
> >
> > +static void *swap_buffer2(void *dst_buf, void *src_buf, int len)
> > +{
> > + int i;
> > + unsigned int *src = src_buf;
> > + unsigned int *dst = dst_buf;
> > +
> > + for (i = 0; i < len; i += 4, src++, dst++)
> > + swab32s(src);
> > +
> > + return dst_buf;
> > +}
> > +
>
> Actually that is completely f*cked....
>
Yeah, noticed that shortly after sending out. :(
One change too many...
Lothar Waßmann
^ permalink raw reply
* Re: [PATCH net-next] net: skb_segment() should preserve backpressure
From: Toshiaki Makita @ 2014-10-28 12:15 UTC (permalink / raw)
To: Eric Dumazet, David Miller; +Cc: netdev, Herbert Xu
In-Reply-To: <1414431051.16231.23.camel@edumazet-glaptop2.roam.corp.google.com>
On 2014/10/28 2:30, Eric Dumazet wrote:
> From: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
>
> This patch generalizes commit d6a4a1041176 ("tcp: GSO should be TSQ
> friendly") to protocols using skb_set_owner_w()
>
> TCP uses its own destructor (tcp_wfree) and needs a more complex scheme
> as explained in commit 6ff50cd55545 ("tcp: gso: do not generate out of
> order packets")
>
> This allows UDP sockets using UFO to get proper backpressure,
> thus avoiding qdisc drops and excessive cpu usage.
>
...
> [edumazet] Rewrote patch and changelog.
This looks better in performance.
I tested this patch and couldn't find any problem.
Thank you for your reviewing and suggesting,
Toshiaki Makita
^ permalink raw reply
* Re: [PATCHv2 6/6] net: fec: fix regression on i.MX28 introduced by rx_copybreak support
From: Lothar Waßmann @ 2014-10-28 12:36 UTC (permalink / raw)
To: David Laight
Cc: netdev@vger.kernel.org, David S. Miller, Russell King, Frank Li,
Fabio Estevam, linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <063D6719AE5E284EB5DD2968C1650D6D1C9E04C0@AcuExch.aculab.com>
Hi,
David Laight wrote:
> From: Lothar Waßmann
> > commit 1b7bde6d659d ("net: fec: implement rx_copybreak to improve rx performance")
> > introduced a regression for i.MX28. The swap_buffer() function doing
> > the endian conversion of the received data on i.MX28 may access memory
> > beyond the actual packet size in the DMA buffer. fec_enet_copybreak()
> > does not copy those bytes, so that the last bytes of a packet may be
> > filled with invalid data after swapping.
> > This will likely lead to checksum errors on received packets.
> > E.g. when trying to mount an NFS rootfs:
> > UDP: bad checksum. From 192.168.1.225:111 to 192.168.100.73:44662 ulen 36
> >
> > Do the byte swapping and copying to the new skb in one go if
> > necessary.
> >
> > Signed-off-by: Lothar Wamann <LW@KARO-electronics.de>
> > ---
> > drivers/net/ethernet/freescale/fec_main.c | 25 +++++++++++++++++++++----
> > 1 file changed, 21 insertions(+), 4 deletions(-)
> >
> > @@ -1455,7 +1472,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
> > prefetch(skb->data - NET_IP_ALIGN);
> > skb_put(skb, pkt_len - 4);
> > data = skb->data;
> > - if (fep->quirks & FEC_QUIRK_SWAP_FRAME)
> > + if (!is_copybreak && need_swap)
> > swap_buffer(data, pkt_len);
>
> It has to be better to set the 'copybreak' limit to be larger than the
> maximum frame size and so always go through the 'copybreak' paths.
>
Since the copybreak support is all about performance optimistation, we
should IMO buy the additional advantage for i.MX28 by not having to
access the buffer twice (once for copying and once again for swapping).
Lothar Waßmann
--
___________________________________________________________
Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Geschäftsführer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996
www.karo-electronics.de | info@karo-electronics.de
___________________________________________________________
^ permalink raw reply
* Re: localed stuck in recent 3.18 git in copy_net_ns?
From: Paul E. McKenney @ 2014-10-28 12:50 UTC (permalink / raw)
To: Yanko Kaneti
Cc: Jay Vosburgh, Josh Boyer, Eric W. Biederman, Cong Wang,
Kevin Fenzi, netdev, Linux-Kernel@Vger. Kernel. Org, mroos, tj
In-Reply-To: <20141028081243.GA32082@declera.com>
On Tue, Oct 28, 2014 at 10:12:43AM +0200, Yanko Kaneti wrote:
> On Mon-10/27/14-2014 10:45, Paul E. McKenney wrote:
> > On Sat, Oct 25, 2014 at 11:18:27AM -0700, Paul E. McKenney wrote:
> > > On Sat, Oct 25, 2014 at 09:38:16AM -0700, Jay Vosburgh wrote:
> > > > Paul E. McKenney <paulmck@linux.vnet.ibm.com> wrote:
> > > >
> > > > >On Fri, Oct 24, 2014 at 09:33:33PM -0700, Jay Vosburgh wrote:
> > > > >> Looking at the dmesg, the early boot messages seem to be
> > > > >> confused as to how many CPUs there are, e.g.,
> > > > >>
> > > > >> [ 0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1
> > > > >> [ 0.000000] Hierarchical RCU implementation.
> > > > >> [ 0.000000] RCU debugfs-based tracing is enabled.
> > > > >> [ 0.000000] RCU dyntick-idle grace-period acceleration is enabled.
> > > > >> [ 0.000000] RCU restricting CPUs from NR_CPUS=256 to nr_cpu_ids=4.
> > > > >> [ 0.000000] RCU: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=4
> > > > >> [ 0.000000] NR_IRQS:16640 nr_irqs:456 0
> > > > >> [ 0.000000] Offload RCU callbacks from all CPUs
> > > > >> [ 0.000000] Offload RCU callbacks from CPUs: 0-3.
> > > > >>
> > > > >> but later shows 2:
> > > > >>
> > > > >> [ 0.233703] x86: Booting SMP configuration:
> > > > >> [ 0.236003] .... node #0, CPUs: #1
> > > > >> [ 0.255528] x86: Booted up 1 node, 2 CPUs
> > > > >>
> > > > >> In any event, the E8400 is a 2 core CPU with no hyperthreading.
> > > > >
> > > > >Well, this might explain some of the difficulties. If RCU decides to wait
> > > > >on CPUs that don't exist, we will of course get a hang. And rcu_barrier()
> > > > >was definitely expecting four CPUs.
> > > > >
> > > > >So what happens if you boot with maxcpus=2? (Or build with
> > > > >CONFIG_NR_CPUS=2.) I suspect that this might avoid the hang. If so,
> > > > >I might have some ideas for a real fix.
> > > >
> > > > Booting with maxcpus=2 makes no difference (the dmesg output is
> > > > the same).
> > > >
> > > > Rebuilding with CONFIG_NR_CPUS=2 makes the problem go away, and
> > > > dmesg has different CPU information at boot:
> > > >
> > > > [ 0.000000] smpboot: 4 Processors exceeds NR_CPUS limit of 2
> > > > [ 0.000000] smpboot: Allowing 2 CPUs, 0 hotplug CPUs
> > > > [...]
> > > > [ 0.000000] setup_percpu: NR_CPUS:2 nr_cpumask_bits:2 nr_cpu_ids:2 nr_node_ids:1
> > > > [...]
> > > > [ 0.000000] Hierarchical RCU implementation.
> > > > [ 0.000000] RCU debugfs-based tracing is enabled.
> > > > [ 0.000000] RCU dyntick-idle grace-period acceleration is enabled.
> > > > [ 0.000000] NR_IRQS:4352 nr_irqs:440 0
> > > > [ 0.000000] Offload RCU callbacks from all CPUs
> > > > [ 0.000000] Offload RCU callbacks from CPUs: 0-1.
> > >
> > > Thank you -- this confirms my suspicions on the fix, though I must admit
> > > to being surprised that maxcpus made no difference.
> >
> > And here is an alleged fix, lightly tested at this end. Does this patch
> > help?
>
> Tested this on top of rc2 (as found in Fedora, and failing without the patch)
> with all my modprobe scenarios and it seems to have fixed it.
Very good! May I apply your Tested-by?
Thanx, Paul
> Thanks
> -Yanko
>
>
> > Thanx, Paul
> >
> > ------------------------------------------------------------------------
> >
> > rcu: Make rcu_barrier() understand about missing rcuo kthreads
> >
> > Commit 35ce7f29a44a (rcu: Create rcuo kthreads only for onlined CPUs)
> > avoids creating rcuo kthreads for CPUs that never come online. This
> > fixes a bug in many instances of firmware: Instead of lying about their
> > age, these systems instead lie about the number of CPUs that they have.
> > Before commit 35ce7f29a44a, this could result in huge numbers of useless
> > rcuo kthreads being created.
> >
> > It appears that experience indicates that I should have told the
> > people suffering from this problem to fix their broken firmware, but
> > I instead produced what turned out to be a partial fix. The missing
> > piece supplied by this commit makes sure that rcu_barrier() knows not to
> > post callbacks for no-CBs CPUs that have not yet come online, because
> > otherwise rcu_barrier() will hang on systems having firmware that lies
> > about the number of CPUs.
> >
> > It is tempting to simply have rcu_barrier() refuse to post a callback on
> > any no-CBs CPU that does not have an rcuo kthread. This unfortunately
> > does not work because rcu_barrier() is required to wait for all pending
> > callbacks. It is therefore required to wait even for those callbacks
> > that cannot possibly be invoked. Even if doing so hangs the system.
> >
> > Given that posting a callback to a no-CBs CPU that does not yet have an
> > rcuo kthread can hang rcu_barrier(), It is tempting to report an error
> > in this case. Unfortunately, this will result in false positives at
> > boot time, when it is perfectly legal to post callbacks to the boot CPU
> > before the scheduler has started, in other words, before it is legal
> > to invoke rcu_barrier().
> >
> > So this commit instead has rcu_barrier() avoid posting callbacks to
> > CPUs having neither rcuo kthread nor pending callbacks, and has it
> > complain bitterly if it finds CPUs having no rcuo kthread but some
> > pending callbacks. And when rcu_barrier() does find CPUs having no rcuo
> > kthread but pending callbacks, as noted earlier, it has no choice but
> > to hang indefinitely.
> >
> > Reported-by: Yanko Kaneti <yaneti@declera.com>
> > Reported-by: Jay Vosburgh <jay.vosburgh@canonical.com>
> > Reported-by: Meelis Roos <mroos@linux.ee>
> > Reported-by: Eric B Munson <emunson@akamai.com>
> > Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> >
> > diff --git a/include/trace/events/rcu.h b/include/trace/events/rcu.h
> > index aa8e5eea3ab4..c78e88ce5ea3 100644
> > --- a/include/trace/events/rcu.h
> > +++ b/include/trace/events/rcu.h
> > @@ -660,18 +660,18 @@ TRACE_EVENT(rcu_torture_read,
> > /*
> > * Tracepoint for _rcu_barrier() execution. The string "s" describes
> > * the _rcu_barrier phase:
> > - * "Begin": rcu_barrier_callback() started.
> > - * "Check": rcu_barrier_callback() checking for piggybacking.
> > - * "EarlyExit": rcu_barrier_callback() piggybacked, thus early exit.
> > - * "Inc1": rcu_barrier_callback() piggyback check counter incremented.
> > - * "Offline": rcu_barrier_callback() found offline CPU
> > - * "OnlineNoCB": rcu_barrier_callback() found online no-CBs CPU.
> > - * "OnlineQ": rcu_barrier_callback() found online CPU with callbacks.
> > - * "OnlineNQ": rcu_barrier_callback() found online CPU, no callbacks.
> > + * "Begin": _rcu_barrier() started.
> > + * "Check": _rcu_barrier() checking for piggybacking.
> > + * "EarlyExit": _rcu_barrier() piggybacked, thus early exit.
> > + * "Inc1": _rcu_barrier() piggyback check counter incremented.
> > + * "OfflineNoCB": _rcu_barrier() found callback on never-online CPU
> > + * "OnlineNoCB": _rcu_barrier() found online no-CBs CPU.
> > + * "OnlineQ": _rcu_barrier() found online CPU with callbacks.
> > + * "OnlineNQ": _rcu_barrier() found online CPU, no callbacks.
> > * "IRQ": An rcu_barrier_callback() callback posted on remote CPU.
> > * "CB": An rcu_barrier_callback() invoked a callback, not the last.
> > * "LastCB": An rcu_barrier_callback() invoked the last callback.
> > - * "Inc2": rcu_barrier_callback() piggyback check counter incremented.
> > + * "Inc2": _rcu_barrier() piggyback check counter incremented.
> > * The "cpu" argument is the CPU or -1 if meaningless, the "cnt" argument
> > * is the count of remaining callbacks, and "done" is the piggybacking count.
> > */
> > diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
> > index f6880052b917..7680fc275036 100644
> > --- a/kernel/rcu/tree.c
> > +++ b/kernel/rcu/tree.c
> > @@ -3312,11 +3312,16 @@ static void _rcu_barrier(struct rcu_state *rsp)
> > continue;
> > rdp = per_cpu_ptr(rsp->rda, cpu);
> > if (rcu_is_nocb_cpu(cpu)) {
> > - _rcu_barrier_trace(rsp, "OnlineNoCB", cpu,
> > - rsp->n_barrier_done);
> > - atomic_inc(&rsp->barrier_cpu_count);
> > - __call_rcu(&rdp->barrier_head, rcu_barrier_callback,
> > - rsp, cpu, 0);
> > + if (!rcu_nocb_cpu_needs_barrier(rsp, cpu)) {
> > + _rcu_barrier_trace(rsp, "OfflineNoCB", cpu,
> > + rsp->n_barrier_done);
> > + } else {
> > + _rcu_barrier_trace(rsp, "OnlineNoCB", cpu,
> > + rsp->n_barrier_done);
> > + atomic_inc(&rsp->barrier_cpu_count);
> > + __call_rcu(&rdp->barrier_head,
> > + rcu_barrier_callback, rsp, cpu, 0);
> > + }
> > } else if (ACCESS_ONCE(rdp->qlen)) {
> > _rcu_barrier_trace(rsp, "OnlineQ", cpu,
> > rsp->n_barrier_done);
> > diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h
> > index 4beab3d2328c..8e7b1843896e 100644
> > --- a/kernel/rcu/tree.h
> > +++ b/kernel/rcu/tree.h
> > @@ -587,6 +587,7 @@ static void print_cpu_stall_info(struct rcu_state *rsp, int cpu);
> > static void print_cpu_stall_info_end(void);
> > static void zero_cpu_stall_ticks(struct rcu_data *rdp);
> > static void increment_cpu_stall_ticks(void);
> > +static bool rcu_nocb_cpu_needs_barrier(struct rcu_state *rsp, int cpu);
> > static void rcu_nocb_gp_set(struct rcu_node *rnp, int nrq);
> > static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp);
> > static void rcu_init_one_nocb(struct rcu_node *rnp);
> > diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
> > index 927c17b081c7..68c5b23b7173 100644
> > --- a/kernel/rcu/tree_plugin.h
> > +++ b/kernel/rcu/tree_plugin.h
> > @@ -2050,6 +2050,33 @@ static void wake_nocb_leader(struct rcu_data *rdp, bool force)
> > }
> >
> > /*
> > + * Does the specified CPU need an RCU callback for the specified flavor
> > + * of rcu_barrier()?
> > + */
> > +static bool rcu_nocb_cpu_needs_barrier(struct rcu_state *rsp, int cpu)
> > +{
> > + struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu);
> > + struct rcu_head *rhp;
> > +
> > + /* No-CBs CPUs might have callbacks on any of three lists. */
> > + rhp = ACCESS_ONCE(rdp->nocb_head);
> > + if (!rhp)
> > + rhp = ACCESS_ONCE(rdp->nocb_gp_head);
> > + if (!rhp)
> > + rhp = ACCESS_ONCE(rdp->nocb_follower_head);
> > +
> > + /* Having no rcuo kthread but CBs after scheduler starts is bad! */
> > + if (!ACCESS_ONCE(rdp->nocb_kthread) && rhp) {
> > + /* RCU callback enqueued before CPU first came online??? */
> > + pr_err("RCU: Never-onlined no-CBs CPU %d has CB %p\n",
> > + cpu, rhp->func);
> > + WARN_ON_ONCE(1);
> > + }
> > +
> > + return !!rhp;
> > +}
> > +
> > +/*
> > * Enqueue the specified string of rcu_head structures onto the specified
> > * CPU's no-CBs lists. The CPU is specified by rdp, the head of the
> > * string by rhp, and the tail of the string by rhtp. The non-lazy/lazy
> > @@ -2646,6 +2673,10 @@ static bool init_nocb_callback_list(struct rcu_data *rdp)
> >
> > #else /* #ifdef CONFIG_RCU_NOCB_CPU */
> >
> > +static bool rcu_nocb_cpu_needs_barrier(struct rcu_state *rsp, int cpu)
> > +{
> > +}
> > +
> > static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp)
> > {
> > }
> >
>
^ permalink raw reply
* Re: localed stuck in recent 3.18 git in copy_net_ns?
From: Yanko Kaneti @ 2014-10-28 13:00 UTC (permalink / raw)
To: Paul E. McKenney
Cc: Jay Vosburgh, Josh Boyer, Eric W. Biederman, Cong Wang,
Kevin Fenzi, netdev, Linux-Kernel@Vger. Kernel. Org, mroos, tj
In-Reply-To: <20141028125059.GO5718@linux.vnet.ibm.com>
On Tue-10/28/14-2014 05:50, Paul E. McKenney wrote:
> On Tue, Oct 28, 2014 at 10:12:43AM +0200, Yanko Kaneti wrote:
> > On Mon-10/27/14-2014 10:45, Paul E. McKenney wrote:
> > > On Sat, Oct 25, 2014 at 11:18:27AM -0700, Paul E. McKenney wrote:
> > > > On Sat, Oct 25, 2014 at 09:38:16AM -0700, Jay Vosburgh wrote:
> > > > > Paul E. McKenney <paulmck@linux.vnet.ibm.com> wrote:
> > > > >
> > > > > >On Fri, Oct 24, 2014 at 09:33:33PM -0700, Jay Vosburgh wrote:
> > > > > >> Looking at the dmesg, the early boot messages seem to be
> > > > > >> confused as to how many CPUs there are, e.g.,
> > > > > >>
> > > > > >> [ 0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1
> > > > > >> [ 0.000000] Hierarchical RCU implementation.
> > > > > >> [ 0.000000] RCU debugfs-based tracing is enabled.
> > > > > >> [ 0.000000] RCU dyntick-idle grace-period acceleration is enabled.
> > > > > >> [ 0.000000] RCU restricting CPUs from NR_CPUS=256 to nr_cpu_ids=4.
> > > > > >> [ 0.000000] RCU: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=4
> > > > > >> [ 0.000000] NR_IRQS:16640 nr_irqs:456 0
> > > > > >> [ 0.000000] Offload RCU callbacks from all CPUs
> > > > > >> [ 0.000000] Offload RCU callbacks from CPUs: 0-3.
> > > > > >>
> > > > > >> but later shows 2:
> > > > > >>
> > > > > >> [ 0.233703] x86: Booting SMP configuration:
> > > > > >> [ 0.236003] .... node #0, CPUs: #1
> > > > > >> [ 0.255528] x86: Booted up 1 node, 2 CPUs
> > > > > >>
> > > > > >> In any event, the E8400 is a 2 core CPU with no hyperthreading.
> > > > > >
> > > > > >Well, this might explain some of the difficulties. If RCU decides to wait
> > > > > >on CPUs that don't exist, we will of course get a hang. And rcu_barrier()
> > > > > >was definitely expecting four CPUs.
> > > > > >
> > > > > >So what happens if you boot with maxcpus=2? (Or build with
> > > > > >CONFIG_NR_CPUS=2.) I suspect that this might avoid the hang. If so,
> > > > > >I might have some ideas for a real fix.
> > > > >
> > > > > Booting with maxcpus=2 makes no difference (the dmesg output is
> > > > > the same).
> > > > >
> > > > > Rebuilding with CONFIG_NR_CPUS=2 makes the problem go away, and
> > > > > dmesg has different CPU information at boot:
> > > > >
> > > > > [ 0.000000] smpboot: 4 Processors exceeds NR_CPUS limit of 2
> > > > > [ 0.000000] smpboot: Allowing 2 CPUs, 0 hotplug CPUs
> > > > > [...]
> > > > > [ 0.000000] setup_percpu: NR_CPUS:2 nr_cpumask_bits:2 nr_cpu_ids:2 nr_node_ids:1
> > > > > [...]
> > > > > [ 0.000000] Hierarchical RCU implementation.
> > > > > [ 0.000000] RCU debugfs-based tracing is enabled.
> > > > > [ 0.000000] RCU dyntick-idle grace-period acceleration is enabled.
> > > > > [ 0.000000] NR_IRQS:4352 nr_irqs:440 0
> > > > > [ 0.000000] Offload RCU callbacks from all CPUs
> > > > > [ 0.000000] Offload RCU callbacks from CPUs: 0-1.
> > > >
> > > > Thank you -- this confirms my suspicions on the fix, though I must admit
> > > > to being surprised that maxcpus made no difference.
> > >
> > > And here is an alleged fix, lightly tested at this end. Does this patch
> > > help?
> >
> > Tested this on top of rc2 (as found in Fedora, and failing without the patch)
> > with all my modprobe scenarios and it seems to have fixed it.
>
> Very good! May I apply your Tested-by?
Sure. Sorry didn't include this earlier
Tested-by: Yanko Kaneti <yaneti@declera.com>
> Thanx, Paul
>
> > Thanks
> > -Yanko
> >
> >
> > > Thanx, Paul
> > >
> > > ------------------------------------------------------------------------
> > >
> > > rcu: Make rcu_barrier() understand about missing rcuo kthreads
> > >
> > > Commit 35ce7f29a44a (rcu: Create rcuo kthreads only for onlined CPUs)
> > > avoids creating rcuo kthreads for CPUs that never come online. This
> > > fixes a bug in many instances of firmware: Instead of lying about their
> > > age, these systems instead lie about the number of CPUs that they have.
> > > Before commit 35ce7f29a44a, this could result in huge numbers of useless
> > > rcuo kthreads being created.
> > >
> > > It appears that experience indicates that I should have told the
> > > people suffering from this problem to fix their broken firmware, but
> > > I instead produced what turned out to be a partial fix. The missing
> > > piece supplied by this commit makes sure that rcu_barrier() knows not to
> > > post callbacks for no-CBs CPUs that have not yet come online, because
> > > otherwise rcu_barrier() will hang on systems having firmware that lies
> > > about the number of CPUs.
> > >
> > > It is tempting to simply have rcu_barrier() refuse to post a callback on
> > > any no-CBs CPU that does not have an rcuo kthread. This unfortunately
> > > does not work because rcu_barrier() is required to wait for all pending
> > > callbacks. It is therefore required to wait even for those callbacks
> > > that cannot possibly be invoked. Even if doing so hangs the system.
> > >
> > > Given that posting a callback to a no-CBs CPU that does not yet have an
> > > rcuo kthread can hang rcu_barrier(), It is tempting to report an error
> > > in this case. Unfortunately, this will result in false positives at
> > > boot time, when it is perfectly legal to post callbacks to the boot CPU
> > > before the scheduler has started, in other words, before it is legal
> > > to invoke rcu_barrier().
> > >
> > > So this commit instead has rcu_barrier() avoid posting callbacks to
> > > CPUs having neither rcuo kthread nor pending callbacks, and has it
> > > complain bitterly if it finds CPUs having no rcuo kthread but some
> > > pending callbacks. And when rcu_barrier() does find CPUs having no rcuo
> > > kthread but pending callbacks, as noted earlier, it has no choice but
> > > to hang indefinitely.
> > >
> > > Reported-by: Yanko Kaneti <yaneti@declera.com>
> > > Reported-by: Jay Vosburgh <jay.vosburgh@canonical.com>
> > > Reported-by: Meelis Roos <mroos@linux.ee>
> > > Reported-by: Eric B Munson <emunson@akamai.com>
> > > Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> > >
> > > diff --git a/include/trace/events/rcu.h b/include/trace/events/rcu.h
> > > index aa8e5eea3ab4..c78e88ce5ea3 100644
> > > --- a/include/trace/events/rcu.h
> > > +++ b/include/trace/events/rcu.h
> > > @@ -660,18 +660,18 @@ TRACE_EVENT(rcu_torture_read,
> > > /*
> > > * Tracepoint for _rcu_barrier() execution. The string "s" describes
> > > * the _rcu_barrier phase:
> > > - * "Begin": rcu_barrier_callback() started.
> > > - * "Check": rcu_barrier_callback() checking for piggybacking.
> > > - * "EarlyExit": rcu_barrier_callback() piggybacked, thus early exit.
> > > - * "Inc1": rcu_barrier_callback() piggyback check counter incremented.
> > > - * "Offline": rcu_barrier_callback() found offline CPU
> > > - * "OnlineNoCB": rcu_barrier_callback() found online no-CBs CPU.
> > > - * "OnlineQ": rcu_barrier_callback() found online CPU with callbacks.
> > > - * "OnlineNQ": rcu_barrier_callback() found online CPU, no callbacks.
> > > + * "Begin": _rcu_barrier() started.
> > > + * "Check": _rcu_barrier() checking for piggybacking.
> > > + * "EarlyExit": _rcu_barrier() piggybacked, thus early exit.
> > > + * "Inc1": _rcu_barrier() piggyback check counter incremented.
> > > + * "OfflineNoCB": _rcu_barrier() found callback on never-online CPU
> > > + * "OnlineNoCB": _rcu_barrier() found online no-CBs CPU.
> > > + * "OnlineQ": _rcu_barrier() found online CPU with callbacks.
> > > + * "OnlineNQ": _rcu_barrier() found online CPU, no callbacks.
> > > * "IRQ": An rcu_barrier_callback() callback posted on remote CPU.
> > > * "CB": An rcu_barrier_callback() invoked a callback, not the last.
> > > * "LastCB": An rcu_barrier_callback() invoked the last callback.
> > > - * "Inc2": rcu_barrier_callback() piggyback check counter incremented.
> > > + * "Inc2": _rcu_barrier() piggyback check counter incremented.
> > > * The "cpu" argument is the CPU or -1 if meaningless, the "cnt" argument
> > > * is the count of remaining callbacks, and "done" is the piggybacking count.
> > > */
> > > diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
> > > index f6880052b917..7680fc275036 100644
> > > --- a/kernel/rcu/tree.c
> > > +++ b/kernel/rcu/tree.c
> > > @@ -3312,11 +3312,16 @@ static void _rcu_barrier(struct rcu_state *rsp)
> > > continue;
> > > rdp = per_cpu_ptr(rsp->rda, cpu);
> > > if (rcu_is_nocb_cpu(cpu)) {
> > > - _rcu_barrier_trace(rsp, "OnlineNoCB", cpu,
> > > - rsp->n_barrier_done);
> > > - atomic_inc(&rsp->barrier_cpu_count);
> > > - __call_rcu(&rdp->barrier_head, rcu_barrier_callback,
> > > - rsp, cpu, 0);
> > > + if (!rcu_nocb_cpu_needs_barrier(rsp, cpu)) {
> > > + _rcu_barrier_trace(rsp, "OfflineNoCB", cpu,
> > > + rsp->n_barrier_done);
> > > + } else {
> > > + _rcu_barrier_trace(rsp, "OnlineNoCB", cpu,
> > > + rsp->n_barrier_done);
> > > + atomic_inc(&rsp->barrier_cpu_count);
> > > + __call_rcu(&rdp->barrier_head,
> > > + rcu_barrier_callback, rsp, cpu, 0);
> > > + }
> > > } else if (ACCESS_ONCE(rdp->qlen)) {
> > > _rcu_barrier_trace(rsp, "OnlineQ", cpu,
> > > rsp->n_barrier_done);
> > > diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h
> > > index 4beab3d2328c..8e7b1843896e 100644
> > > --- a/kernel/rcu/tree.h
> > > +++ b/kernel/rcu/tree.h
> > > @@ -587,6 +587,7 @@ static void print_cpu_stall_info(struct rcu_state *rsp, int cpu);
> > > static void print_cpu_stall_info_end(void);
> > > static void zero_cpu_stall_ticks(struct rcu_data *rdp);
> > > static void increment_cpu_stall_ticks(void);
> > > +static bool rcu_nocb_cpu_needs_barrier(struct rcu_state *rsp, int cpu);
> > > static void rcu_nocb_gp_set(struct rcu_node *rnp, int nrq);
> > > static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp);
> > > static void rcu_init_one_nocb(struct rcu_node *rnp);
> > > diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
> > > index 927c17b081c7..68c5b23b7173 100644
> > > --- a/kernel/rcu/tree_plugin.h
> > > +++ b/kernel/rcu/tree_plugin.h
> > > @@ -2050,6 +2050,33 @@ static void wake_nocb_leader(struct rcu_data *rdp, bool force)
> > > }
> > >
> > > /*
> > > + * Does the specified CPU need an RCU callback for the specified flavor
> > > + * of rcu_barrier()?
> > > + */
> > > +static bool rcu_nocb_cpu_needs_barrier(struct rcu_state *rsp, int cpu)
> > > +{
> > > + struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu);
> > > + struct rcu_head *rhp;
> > > +
> > > + /* No-CBs CPUs might have callbacks on any of three lists. */
> > > + rhp = ACCESS_ONCE(rdp->nocb_head);
> > > + if (!rhp)
> > > + rhp = ACCESS_ONCE(rdp->nocb_gp_head);
> > > + if (!rhp)
> > > + rhp = ACCESS_ONCE(rdp->nocb_follower_head);
> > > +
> > > + /* Having no rcuo kthread but CBs after scheduler starts is bad! */
> > > + if (!ACCESS_ONCE(rdp->nocb_kthread) && rhp) {
> > > + /* RCU callback enqueued before CPU first came online??? */
> > > + pr_err("RCU: Never-onlined no-CBs CPU %d has CB %p\n",
> > > + cpu, rhp->func);
> > > + WARN_ON_ONCE(1);
> > > + }
> > > +
> > > + return !!rhp;
> > > +}
> > > +
> > > +/*
> > > * Enqueue the specified string of rcu_head structures onto the specified
> > > * CPU's no-CBs lists. The CPU is specified by rdp, the head of the
> > > * string by rhp, and the tail of the string by rhtp. The non-lazy/lazy
> > > @@ -2646,6 +2673,10 @@ static bool init_nocb_callback_list(struct rcu_data *rdp)
> > >
> > > #else /* #ifdef CONFIG_RCU_NOCB_CPU */
> > >
> > > +static bool rcu_nocb_cpu_needs_barrier(struct rcu_state *rsp, int cpu)
> > > +{
> > > +}
> > > +
> > > static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp)
> > > {
> > > }
> > >
> >
>
^ permalink raw reply
* RE: [PATCHv2 6/6] net: fec: fix regression on i.MX28 introduced by rx_copybreak support
From: David Laight @ 2014-10-28 13:01 UTC (permalink / raw)
To: 'Lothar Waßmann'
Cc: netdev@vger.kernel.org, David S. Miller, Russell King, Frank Li,
Fabio Estevam, linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <20141028133609.2bf6c745@ipc1.ka-ro>
From: Lothar Waßmann
> David Laight wrote:
> > From: Lothar Waßmann
> > > commit 1b7bde6d659d ("net: fec: implement rx_copybreak to improve rx performance")
> > > introduced a regression for i.MX28. The swap_buffer() function doing
> > > the endian conversion of the received data on i.MX28 may access memory
> > > beyond the actual packet size in the DMA buffer. fec_enet_copybreak()
> > > does not copy those bytes, so that the last bytes of a packet may be
> > > filled with invalid data after swapping.
> > > This will likely lead to checksum errors on received packets.
> > > E.g. when trying to mount an NFS rootfs:
> > > UDP: bad checksum. From 192.168.1.225:111 to 192.168.100.73:44662 ulen 36
> > >
> > > Do the byte swapping and copying to the new skb in one go if
> > > necessary.
> > >
> > > Signed-off-by: Lothar Wamann <LW@KARO-electronics.de>
> > > ---
> > > drivers/net/ethernet/freescale/fec_main.c | 25 +++++++++++++++++++++----
> > > 1 file changed, 21 insertions(+), 4 deletions(-)
> > >
> > > @@ -1455,7 +1472,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
> > > prefetch(skb->data - NET_IP_ALIGN);
> > > skb_put(skb, pkt_len - 4);
> > > data = skb->data;
> > > - if (fep->quirks & FEC_QUIRK_SWAP_FRAME)
> > > + if (!is_copybreak && need_swap)
> > > swap_buffer(data, pkt_len);
> >
> > It has to be better to set the 'copybreak' limit to be larger than the
> > maximum frame size and so always go through the 'copybreak' paths.
> >
> Since the copybreak support is all about performance optimistation, we
> should IMO buy the additional advantage for i.MX28 by not having to
> access the buffer twice (once for copying and once again for swapping).
You definitely want to do the byteswap at the same time as the copy.
The point I'm trying to make that if you need to do the byteswap you
probably might as well copy the data to an skb of the correct size at
the same time.
Certainly I'd expect the 'break even' length will be much higher.
David
^ permalink raw reply
* net: fec: fix regression on i.MX28 introduced by rx_copybreak support
From: Lothar Waßmann @ 2014-10-28 13:22 UTC (permalink / raw)
To: netdev
Cc: Fabio Estevam, Frank Li, linux-kernel, Russell King,
David S. Miller, linux-arm-kernel, Lothar Waßmann
In-Reply-To: <1414494104-27943-1-git-send-email-LW@KARO-electronics.de>
Changes wrt. v1:
- added some cleanup patches
- simplify handling of 'quirks' flags as suggested by Russell King.
- remove DIV_ROUND_UP() from byte swapping loop as suggested by
Eric Dumazet
Changes wrt. v2:
- rebased against next-20141028
- added some more cleanups in fec.h
- removed unused return value from swap_buffer()
- fixed messed swab32s() call in swap_buffer2()
- fixed messed up setup of fep->quirks
^ permalink raw reply
* [PATCHv3 1/9] net: fec: indentation cleanup
From: Lothar Waßmann @ 2014-10-28 13:22 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Russell King, Frank Li, Fabio Estevam,
linux-kernel, Lothar Waßmann, linux-arm-kernel
In-Reply-To: <1414502584-10583-1-git-send-email-LW@KARO-electronics.de>
consistently use TABs for indentation
Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de>
---
drivers/net/ethernet/freescale/fec.h | 108 +++++++++++++++++-----------------
1 file changed, 54 insertions(+), 54 deletions(-)
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 9af296a..3047db4 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -213,60 +213,60 @@ struct bufdesc_ex {
* The following definitions courtesy of commproc.h, which where
* Copyright (c) 1997 Dan Malek (dmalek@jlc.net).
*/
-#define BD_SC_EMPTY ((ushort)0x8000) /* Receive is empty */
-#define BD_SC_READY ((ushort)0x8000) /* Transmit is ready */
-#define BD_SC_WRAP ((ushort)0x2000) /* Last buffer descriptor */
-#define BD_SC_INTRPT ((ushort)0x1000) /* Interrupt on change */
-#define BD_SC_CM ((ushort)0x0200) /* Continuous mode */
-#define BD_SC_ID ((ushort)0x0100) /* Rec'd too many idles */
-#define BD_SC_P ((ushort)0x0100) /* xmt preamble */
-#define BD_SC_BR ((ushort)0x0020) /* Break received */
-#define BD_SC_FR ((ushort)0x0010) /* Framing error */
-#define BD_SC_PR ((ushort)0x0008) /* Parity error */
-#define BD_SC_OV ((ushort)0x0002) /* Overrun */
-#define BD_SC_CD ((ushort)0x0001) /* ?? */
+#define BD_SC_EMPTY ((ushort)0x8000) /* Receive is empty */
+#define BD_SC_READY ((ushort)0x8000) /* Transmit is ready */
+#define BD_SC_WRAP ((ushort)0x2000) /* Last buffer descriptor */
+#define BD_SC_INTRPT ((ushort)0x1000) /* Interrupt on change */
+#define BD_SC_CM ((ushort)0x0200) /* Continuous mode */
+#define BD_SC_ID ((ushort)0x0100) /* Rec'd too many idles */
+#define BD_SC_P ((ushort)0x0100) /* xmt preamble */
+#define BD_SC_BR ((ushort)0x0020) /* Break received */
+#define BD_SC_FR ((ushort)0x0010) /* Framing error */
+#define BD_SC_PR ((ushort)0x0008) /* Parity error */
+#define BD_SC_OV ((ushort)0x0002) /* Overrun */
+#define BD_SC_CD ((ushort)0x0001) /* ?? */
/* Buffer descriptor control/status used by Ethernet receive.
-*/
-#define BD_ENET_RX_EMPTY ((ushort)0x8000)
-#define BD_ENET_RX_WRAP ((ushort)0x2000)
-#define BD_ENET_RX_INTR ((ushort)0x1000)
-#define BD_ENET_RX_LAST ((ushort)0x0800)
-#define BD_ENET_RX_FIRST ((ushort)0x0400)
-#define BD_ENET_RX_MISS ((ushort)0x0100)
-#define BD_ENET_RX_LG ((ushort)0x0020)
-#define BD_ENET_RX_NO ((ushort)0x0010)
-#define BD_ENET_RX_SH ((ushort)0x0008)
-#define BD_ENET_RX_CR ((ushort)0x0004)
-#define BD_ENET_RX_OV ((ushort)0x0002)
-#define BD_ENET_RX_CL ((ushort)0x0001)
-#define BD_ENET_RX_STATS ((ushort)0x013f) /* All status bits */
+ */
+#define BD_ENET_RX_EMPTY ((ushort)0x8000)
+#define BD_ENET_RX_WRAP ((ushort)0x2000)
+#define BD_ENET_RX_INTR ((ushort)0x1000)
+#define BD_ENET_RX_LAST ((ushort)0x0800)
+#define BD_ENET_RX_FIRST ((ushort)0x0400)
+#define BD_ENET_RX_MISS ((ushort)0x0100)
+#define BD_ENET_RX_LG ((ushort)0x0020)
+#define BD_ENET_RX_NO ((ushort)0x0010)
+#define BD_ENET_RX_SH ((ushort)0x0008)
+#define BD_ENET_RX_CR ((ushort)0x0004)
+#define BD_ENET_RX_OV ((ushort)0x0002)
+#define BD_ENET_RX_CL ((ushort)0x0001)
+#define BD_ENET_RX_STATS ((ushort)0x013f) /* All status bits */
/* Enhanced buffer descriptor control/status used by Ethernet receive */
-#define BD_ENET_RX_VLAN 0x00000004
+#define BD_ENET_RX_VLAN 0x00000004
/* Buffer descriptor control/status used by Ethernet transmit.
-*/
-#define BD_ENET_TX_READY ((ushort)0x8000)
-#define BD_ENET_TX_PAD ((ushort)0x4000)
-#define BD_ENET_TX_WRAP ((ushort)0x2000)
-#define BD_ENET_TX_INTR ((ushort)0x1000)
-#define BD_ENET_TX_LAST ((ushort)0x0800)
-#define BD_ENET_TX_TC ((ushort)0x0400)
-#define BD_ENET_TX_DEF ((ushort)0x0200)
-#define BD_ENET_TX_HB ((ushort)0x0100)
-#define BD_ENET_TX_LC ((ushort)0x0080)
-#define BD_ENET_TX_RL ((ushort)0x0040)
-#define BD_ENET_TX_RCMASK ((ushort)0x003c)
-#define BD_ENET_TX_UN ((ushort)0x0002)
-#define BD_ENET_TX_CSL ((ushort)0x0001)
-#define BD_ENET_TX_STATS ((ushort)0x0fff) /* All status bits */
-
-/*enhanced buffer descriptor control/status used by Ethernet transmit*/
-#define BD_ENET_TX_INT 0x40000000
-#define BD_ENET_TX_TS 0x20000000
-#define BD_ENET_TX_PINS 0x10000000
-#define BD_ENET_TX_IINS 0x08000000
+ */
+#define BD_ENET_TX_READY ((ushort)0x8000)
+#define BD_ENET_TX_PAD ((ushort)0x4000)
+#define BD_ENET_TX_WRAP ((ushort)0x2000)
+#define BD_ENET_TX_INTR ((ushort)0x1000)
+#define BD_ENET_TX_LAST ((ushort)0x0800)
+#define BD_ENET_TX_TC ((ushort)0x0400)
+#define BD_ENET_TX_DEF ((ushort)0x0200)
+#define BD_ENET_TX_HB ((ushort)0x0100)
+#define BD_ENET_TX_LC ((ushort)0x0080)
+#define BD_ENET_TX_RL ((ushort)0x0040)
+#define BD_ENET_TX_RCMASK ((ushort)0x003c)
+#define BD_ENET_TX_UN ((ushort)0x0002)
+#define BD_ENET_TX_CSL ((ushort)0x0001)
+#define BD_ENET_TX_STATS ((ushort)0x0fff) /* All status bits */
+
+/* enhanced buffer descriptor control/status used by Ethernet transmit */
+#define BD_ENET_TX_INT 0x40000000
+#define BD_ENET_TX_TS 0x20000000
+#define BD_ENET_TX_PINS 0x10000000
+#define BD_ENET_TX_IINS 0x08000000
/* This device has up to three irqs on some platforms */
@@ -301,7 +301,7 @@ struct bufdesc_ex {
#define IDLE_SLOPE_2 0x200 /* BW fraction: 0.5 */
#define IDLE_SLOPE(X) ((X == 1) ? (IDLE_SLOPE_1 & IDLE_SLOPE_MASK) : \
(IDLE_SLOPE_2 & IDLE_SLOPE_MASK))
-#define RCMR_MATCHEN (0x1 << 16)
+#define RCMR_MATCHEN (0x1 << 16)
#define RCMR_CMP_CFG(v, n) ((v & 0x7) << (n << 2))
#define RCMR_CMP_1 (RCMR_CMP_CFG(0, 0) | RCMR_CMP_CFG(1, 1) | \
RCMR_CMP_CFG(2, 2) | RCMR_CMP_CFG(3, 3))
@@ -326,8 +326,8 @@ struct bufdesc_ex {
#define TX_RING_SIZE 512 /* Must be power of two */
#define TX_RING_MOD_MASK 511 /* for this to work */
-#define BD_ENET_RX_INT 0x00800000
-#define BD_ENET_RX_PTP ((ushort)0x0400)
+#define BD_ENET_RX_INT 0x00800000
+#define BD_ENET_RX_PTP ((ushort)0x0400)
#define BD_ENET_RX_ICE 0x00000020
#define BD_ENET_RX_PCR 0x00000010
#define FLAG_RX_CSUM_ENABLED (BD_ENET_RX_ICE | BD_ENET_RX_PCR)
@@ -364,8 +364,8 @@ struct bufdesc_ex {
#define FEC_ITR_ICFT_DEFAULT 200 /* Set 200 frame count threshold */
#define FEC_ITR_ICTT_DEFAULT 1000 /* Set 1000us timer threshold */
-#define FEC_VLAN_TAG_LEN 0x04
-#define FEC_ETHTYPE_LEN 0x02
+#define FEC_VLAN_TAG_LEN 0x04
+#define FEC_ETHTYPE_LEN 0x02
/* Controller is ENET-MAC */
#define FEC_QUIRK_ENET_MAC (1 << 0)
@@ -390,7 +390,7 @@ struct bufdesc_ex {
* frames not being transmitted until there is a 0-to-1 transition on
* ENET_TDAR[TDAR].
*/
-#define FEC_QUIRK_ERR006358 (1 << 7)
+#define FEC_QUIRK_ERR006358 (1 << 7)
/* ENET IP hw AVB
*
* i.MX6SX ENET IP add Audio Video Bridging (AVB) feature support.
--
1.7.10.4
^ permalink raw reply related
* [PATCHv3 2/9] net: fec: consistently use lower case chars as hex digits
From: Lothar Waßmann @ 2014-10-28 13:22 UTC (permalink / raw)
To: netdev
Cc: Fabio Estevam, Frank Li, linux-kernel, Russell King,
David S. Miller, linux-arm-kernel, Lothar Waßmann
In-Reply-To: <1414502584-10583-1-git-send-email-LW@KARO-electronics.de>
Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de>
---
drivers/net/ethernet/freescale/fec.h | 88 +++++++++++++++++-----------------
1 file changed, 44 insertions(+), 44 deletions(-)
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 3047db4..e778b9e 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -38,9 +38,9 @@
#define FEC_ADDR_LOW 0x0e4 /* Low 32bits MAC address */
#define FEC_ADDR_HIGH 0x0e8 /* High 16bits MAC address */
#define FEC_OPD 0x0ec /* Opcode + Pause duration */
-#define FEC_TXIC0 0xF0 /* Tx Interrupt Coalescing for ring 0 */
-#define FEC_TXIC1 0xF4 /* Tx Interrupt Coalescing for ring 1 */
-#define FEC_TXIC2 0xF8 /* Tx Interrupt Coalescing for ring 2 */
+#define FEC_TXIC0 0x0f0 /* Tx Interrupt Coalescing for ring 0 */
+#define FEC_TXIC1 0x0f4 /* Tx Interrupt Coalescing for ring 1 */
+#define FEC_TXIC2 0x0f8 /* Tx Interrupt Coalescing for ring 2 */
#define FEC_RXIC0 0x100 /* Rx Interrupt Coalescing for ring 0 */
#define FEC_RXIC1 0x104 /* Rx Interrupt Coalescing for ring 1 */
#define FEC_RXIC2 0x108 /* Rx Interrupt Coalescing for ring 2 */
@@ -62,7 +62,7 @@
#define FEC_R_FIFO_RSEM 0x194 /* Receive FIFO section empty threshold */
#define FEC_R_FIFO_RAEM 0x198 /* Receive FIFO almost empty threshold */
#define FEC_R_FIFO_RAFL 0x19c /* Receive FIFO almost full threshold */
-#define FEC_RACC 0x1C4 /* Receive Accelerator function */
+#define FEC_RACC 0x1c4 /* Receive Accelerator function */
#define FEC_RCMR_1 0x1c8 /* Receive classification match ring 1 */
#define FEC_RCMR_2 0x1cc /* Receive classification match ring 2 */
#define FEC_DMA_CFG_1 0x1d8 /* DMA class configuration for ring 1 */
@@ -82,57 +82,57 @@
#define RMON_T_DROP 0x200 /* Count of frames not cntd correctly */
#define RMON_T_PACKETS 0x204 /* RMON TX packet count */
#define RMON_T_BC_PKT 0x208 /* RMON TX broadcast pkts */
-#define RMON_T_MC_PKT 0x20C /* RMON TX multicast pkts */
+#define RMON_T_MC_PKT 0x20c /* RMON TX multicast pkts */
#define RMON_T_CRC_ALIGN 0x210 /* RMON TX pkts with CRC align err */
#define RMON_T_UNDERSIZE 0x214 /* RMON TX pkts < 64 bytes, good CRC */
#define RMON_T_OVERSIZE 0x218 /* RMON TX pkts > MAX_FL bytes good CRC */
-#define RMON_T_FRAG 0x21C /* RMON TX pkts < 64 bytes, bad CRC */
+#define RMON_T_FRAG 0x21c /* RMON TX pkts < 64 bytes, bad CRC */
#define RMON_T_JAB 0x220 /* RMON TX pkts > MAX_FL bytes, bad CRC */
#define RMON_T_COL 0x224 /* RMON TX collision count */
#define RMON_T_P64 0x228 /* RMON TX 64 byte pkts */
-#define RMON_T_P65TO127 0x22C /* RMON TX 65 to 127 byte pkts */
+#define RMON_T_P65TO127 0x22c /* RMON TX 65 to 127 byte pkts */
#define RMON_T_P128TO255 0x230 /* RMON TX 128 to 255 byte pkts */
#define RMON_T_P256TO511 0x234 /* RMON TX 256 to 511 byte pkts */
#define RMON_T_P512TO1023 0x238 /* RMON TX 512 to 1023 byte pkts */
-#define RMON_T_P1024TO2047 0x23C /* RMON TX 1024 to 2047 byte pkts */
+#define RMON_T_P1024TO2047 0x23c /* RMON TX 1024 to 2047 byte pkts */
#define RMON_T_P_GTE2048 0x240 /* RMON TX pkts > 2048 bytes */
#define RMON_T_OCTETS 0x244 /* RMON TX octets */
#define IEEE_T_DROP 0x248 /* Count of frames not counted crtly */
-#define IEEE_T_FRAME_OK 0x24C /* Frames tx'd OK */
+#define IEEE_T_FRAME_OK 0x24c /* Frames tx'd OK */
#define IEEE_T_1COL 0x250 /* Frames tx'd with single collision */
#define IEEE_T_MCOL 0x254 /* Frames tx'd with multiple collision */
#define IEEE_T_DEF 0x258 /* Frames tx'd after deferral delay */
-#define IEEE_T_LCOL 0x25C /* Frames tx'd with late collision */
+#define IEEE_T_LCOL 0x25c /* Frames tx'd with late collision */
#define IEEE_T_EXCOL 0x260 /* Frames tx'd with excesv collisions */
#define IEEE_T_MACERR 0x264 /* Frames tx'd with TX FIFO underrun */
#define IEEE_T_CSERR 0x268 /* Frames tx'd with carrier sense err */
-#define IEEE_T_SQE 0x26C /* Frames tx'd with SQE err */
+#define IEEE_T_SQE 0x26c /* Frames tx'd with SQE err */
#define IEEE_T_FDXFC 0x270 /* Flow control pause frames tx'd */
#define IEEE_T_OCTETS_OK 0x274 /* Octet count for frames tx'd w/o err */
#define RMON_R_PACKETS 0x284 /* RMON RX packet count */
#define RMON_R_BC_PKT 0x288 /* RMON RX broadcast pkts */
-#define RMON_R_MC_PKT 0x28C /* RMON RX multicast pkts */
+#define RMON_R_MC_PKT 0x28c /* RMON RX multicast pkts */
#define RMON_R_CRC_ALIGN 0x290 /* RMON RX pkts with CRC alignment err */
#define RMON_R_UNDERSIZE 0x294 /* RMON RX pkts < 64 bytes, good CRC */
#define RMON_R_OVERSIZE 0x298 /* RMON RX pkts > MAX_FL bytes good CRC */
-#define RMON_R_FRAG 0x29C /* RMON RX pkts < 64 bytes, bad CRC */
-#define RMON_R_JAB 0x2A0 /* RMON RX pkts > MAX_FL bytes, bad CRC */
-#define RMON_R_RESVD_O 0x2A4 /* Reserved */
-#define RMON_R_P64 0x2A8 /* RMON RX 64 byte pkts */
-#define RMON_R_P65TO127 0x2AC /* RMON RX 65 to 127 byte pkts */
-#define RMON_R_P128TO255 0x2B0 /* RMON RX 128 to 255 byte pkts */
-#define RMON_R_P256TO511 0x2B4 /* RMON RX 256 to 511 byte pkts */
-#define RMON_R_P512TO1023 0x2B8 /* RMON RX 512 to 1023 byte pkts */
-#define RMON_R_P1024TO2047 0x2BC /* RMON RX 1024 to 2047 byte pkts */
-#define RMON_R_P_GTE2048 0x2C0 /* RMON RX pkts > 2048 bytes */
-#define RMON_R_OCTETS 0x2C4 /* RMON RX octets */
-#define IEEE_R_DROP 0x2C8 /* Count frames not counted correctly */
-#define IEEE_R_FRAME_OK 0x2CC /* Frames rx'd OK */
-#define IEEE_R_CRC 0x2D0 /* Frames rx'd with CRC err */
-#define IEEE_R_ALIGN 0x2D4 /* Frames rx'd with alignment err */
-#define IEEE_R_MACERR 0x2D8 /* Receive FIFO overflow count */
-#define IEEE_R_FDXFC 0x2DC /* Flow control pause frames rx'd */
-#define IEEE_R_OCTETS_OK 0x2E0 /* Octet cnt for frames rx'd w/o err */
+#define RMON_R_FRAG 0x29c /* RMON RX pkts < 64 bytes, bad CRC */
+#define RMON_R_JAB 0x2a0 /* RMON RX pkts > MAX_FL bytes, bad CRC */
+#define RMON_R_RESVD_O 0x2a4 /* Reserved */
+#define RMON_R_P64 0x2a8 /* RMON RX 64 byte pkts */
+#define RMON_R_P65TO127 0x2ac /* RMON RX 65 to 127 byte pkts */
+#define RMON_R_P128TO255 0x2b0 /* RMON RX 128 to 255 byte pkts */
+#define RMON_R_P256TO511 0x2b4 /* RMON RX 256 to 511 byte pkts */
+#define RMON_R_P512TO1023 0x2b8 /* RMON RX 512 to 1023 byte pkts */
+#define RMON_R_P1024TO2047 0x2bc /* RMON RX 1024 to 2047 byte pkts */
+#define RMON_R_P_GTE2048 0x2c0 /* RMON RX pkts > 2048 bytes */
+#define RMON_R_OCTETS 0x2c4 /* RMON RX octets */
+#define IEEE_R_DROP 0x2c8 /* Count frames not counted correctly */
+#define IEEE_R_FRAME_OK 0x2cc /* Frames rx'd OK */
+#define IEEE_R_CRC 0x2d0 /* Frames rx'd with CRC err */
+#define IEEE_R_ALIGN 0x2d4 /* Frames rx'd with alignment err */
+#define IEEE_R_MACERR 0x2d8 /* Receive FIFO overflow count */
+#define IEEE_R_FDXFC 0x2dc /* Flow control pause frames rx'd */
+#define IEEE_R_OCTETS_OK 0x2e0 /* Octet cnt for frames rx'd w/o err */
#else
@@ -170,16 +170,16 @@
/* Not existed in real chip
* Just for pass build.
*/
-#define FEC_RCMR_1 0xFFF
-#define FEC_RCMR_2 0xFFF
-#define FEC_DMA_CFG_1 0xFFF
-#define FEC_DMA_CFG_2 0xFFF
-#define FEC_TXIC0 0xFFF
-#define FEC_TXIC1 0xFFF
-#define FEC_TXIC2 0xFFF
-#define FEC_RXIC0 0xFFF
-#define FEC_RXIC1 0xFFF
-#define FEC_RXIC2 0xFFF
+#define FEC_RCMR_1 0xfff
+#define FEC_RCMR_2 0xfff
+#define FEC_DMA_CFG_1 0xfff
+#define FEC_DMA_CFG_2 0xfff
+#define FEC_TXIC0 0xfff
+#define FEC_TXIC1 0xfff
+#define FEC_TXIC2 0xfff
+#define FEC_RXIC0 0xfff
+#define FEC_RXIC1 0xfff
+#define FEC_RXIC2 0xfff
#endif /* CONFIG_M5272 */
@@ -296,7 +296,7 @@ struct bufdesc_ex {
#define DMA_CLASS_EN (1 << 16)
#define FEC_RCMR(X) ((X == 2) ? FEC_RCMR_2 : FEC_RCMR_1)
-#define IDLE_SLOPE_MASK 0xFFFF
+#define IDLE_SLOPE_MASK 0xffff
#define IDLE_SLOPE_1 0x200 /* BW fraction: 0.5 */
#define IDLE_SLOPE_2 0x200 /* BW fraction: 0.5 */
#define IDLE_SLOPE(X) ((X == 1) ? (IDLE_SLOPE_1 & IDLE_SLOPE_MASK) : \
@@ -308,7 +308,7 @@ struct bufdesc_ex {
#define RCMR_CMP_2 (RCMR_CMP_CFG(4, 0) | RCMR_CMP_CFG(5, 1) | \
RCMR_CMP_CFG(6, 2) | RCMR_CMP_CFG(7, 3))
#define RCMR_CMP(X) ((X == 1) ? RCMR_CMP_1 : RCMR_CMP_2)
-#define FEC_TX_BD_FTYPE(X) ((X & 0xF) << 20)
+#define FEC_TX_BD_FTYPE(X) ((X & 0xf) << 20)
/* The number of Tx and Rx buffers. These are allocated from the page
* pool. The code may assume these are power of two, so it it best
@@ -359,8 +359,8 @@ struct bufdesc_ex {
/* ENET interrupt coalescing macro define */
#define FEC_ITR_CLK_SEL (0x1 << 30)
#define FEC_ITR_EN (0x1 << 31)
-#define FEC_ITR_ICFT(X) ((X & 0xFF) << 20)
-#define FEC_ITR_ICTT(X) ((X) & 0xFFFF)
+#define FEC_ITR_ICFT(X) ((X & 0xff) << 20)
+#define FEC_ITR_ICTT(X) ((X) & 0xffff)
#define FEC_ITR_ICFT_DEFAULT 200 /* Set 200 frame count threshold */
#define FEC_ITR_ICTT_DEFAULT 1000 /* Set 1000us timer threshold */
--
1.7.10.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCHv3 3/9] net: fec: properly parenthesize macro args
From: Lothar Waßmann @ 2014-10-28 13:22 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Russell King, Frank Li, Fabio Estevam,
linux-kernel, Lothar Waßmann, linux-arm-kernel
In-Reply-To: <1414502584-10583-1-git-send-email-LW@KARO-electronics.de>
Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de>
---
drivers/net/ethernet/freescale/fec.h | 31 ++++++++++++++++---------------
1 file changed, 16 insertions(+), 15 deletions(-)
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index e778b9e..27e75cf 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -279,36 +279,37 @@ struct bufdesc_ex {
#define FEC_ENET_MAX_TX_QS 3
#define FEC_ENET_MAX_RX_QS 3
-#define FEC_R_DES_START(X) ((X == 1) ? FEC_R_DES_START_1 : \
- ((X == 2) ? \
+#define FEC_R_DES_START(X) (((X) == 1) ? FEC_R_DES_START_1 : \
+ (((X) == 2) ? \
FEC_R_DES_START_2 : FEC_R_DES_START_0))
-#define FEC_X_DES_START(X) ((X == 1) ? FEC_X_DES_START_1 : \
- ((X == 2) ? \
+#define FEC_X_DES_START(X) (((X) == 1) ? FEC_X_DES_START_1 : \
+ (((X) == 2) ? \
FEC_X_DES_START_2 : FEC_X_DES_START_0))
-#define FEC_R_DES_ACTIVE(X) ((X == 1) ? FEC_R_DES_ACTIVE_1 : \
- ((X == 2) ? \
+#define FEC_R_DES_ACTIVE(X) (((X) == 1) ? FEC_R_DES_ACTIVE_1 : \
+ (((X) == 2) ? \
FEC_R_DES_ACTIVE_2 : FEC_R_DES_ACTIVE_0))
-#define FEC_X_DES_ACTIVE(X) ((X == 1) ? FEC_X_DES_ACTIVE_1 : \
- ((X == 2) ? \
+#define FEC_X_DES_ACTIVE(X) (((X) == 1) ? FEC_X_DES_ACTIVE_1 : \
+ (((X) == 2) ? \
FEC_X_DES_ACTIVE_2 : FEC_X_DES_ACTIVE_0))
-#define FEC_DMA_CFG(X) ((X == 2) ? FEC_DMA_CFG_2 : FEC_DMA_CFG_1)
+#define FEC_DMA_CFG(X) (((X) == 2) ? FEC_DMA_CFG_2 : FEC_DMA_CFG_1)
#define DMA_CLASS_EN (1 << 16)
-#define FEC_RCMR(X) ((X == 2) ? FEC_RCMR_2 : FEC_RCMR_1)
+#define FEC_RCMR(X) (((X) == 2) ? FEC_RCMR_2 : FEC_RCMR_1)
#define IDLE_SLOPE_MASK 0xffff
#define IDLE_SLOPE_1 0x200 /* BW fraction: 0.5 */
#define IDLE_SLOPE_2 0x200 /* BW fraction: 0.5 */
-#define IDLE_SLOPE(X) ((X == 1) ? (IDLE_SLOPE_1 & IDLE_SLOPE_MASK) : \
+#define IDLE_SLOPE(X) (((X) == 1) ? \
+ (IDLE_SLOPE_1 & IDLE_SLOPE_MASK) : \
(IDLE_SLOPE_2 & IDLE_SLOPE_MASK))
#define RCMR_MATCHEN (0x1 << 16)
-#define RCMR_CMP_CFG(v, n) ((v & 0x7) << (n << 2))
+#define RCMR_CMP_CFG(v, n) (((v) & 0x7) << (n << 2))
#define RCMR_CMP_1 (RCMR_CMP_CFG(0, 0) | RCMR_CMP_CFG(1, 1) | \
RCMR_CMP_CFG(2, 2) | RCMR_CMP_CFG(3, 3))
#define RCMR_CMP_2 (RCMR_CMP_CFG(4, 0) | RCMR_CMP_CFG(5, 1) | \
RCMR_CMP_CFG(6, 2) | RCMR_CMP_CFG(7, 3))
-#define RCMR_CMP(X) ((X == 1) ? RCMR_CMP_1 : RCMR_CMP_2)
-#define FEC_TX_BD_FTYPE(X) ((X & 0xf) << 20)
+#define RCMR_CMP(X) (((X) == 1) ? RCMR_CMP_1 : RCMR_CMP_2)
+#define FEC_TX_BD_FTYPE(X) (((X) & 0xf) << 20)
/* The number of Tx and Rx buffers. These are allocated from the page
* pool. The code may assume these are power of two, so it it best
@@ -359,7 +360,7 @@ struct bufdesc_ex {
/* ENET interrupt coalescing macro define */
#define FEC_ITR_CLK_SEL (0x1 << 30)
#define FEC_ITR_EN (0x1 << 31)
-#define FEC_ITR_ICFT(X) ((X & 0xff) << 20)
+#define FEC_ITR_ICFT(X) (((X) & 0xff) << 20)
#define FEC_ITR_ICTT(X) ((X) & 0xffff)
#define FEC_ITR_ICFT_DEFAULT 200 /* Set 200 frame count threshold */
#define FEC_ITR_ICTT_DEFAULT 1000 /* Set 1000us timer threshold */
--
1.7.10.4
^ permalink raw reply related
* [PATCHv3 4/9] net: fec: declare bufdesc_ex flag as bool
From: Lothar Waßmann @ 2014-10-28 13:22 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Russell King, Frank Li, Fabio Estevam,
linux-kernel, Lothar Waßmann, linux-arm-kernel
In-Reply-To: <1414502584-10583-1-git-send-email-LW@KARO-electronics.de>
fep->bufdesc_ex is used as boolean flag; thus declare it as such.
Also remove an unnecessary initialization to 0.
Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de>
---
drivers/net/ethernet/freescale/fec.h | 2 +-
drivers/net/ethernet/freescale/fec_main.c | 4 +---
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 27e75cf..1418813 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -502,7 +502,7 @@ struct fec_enet_private {
int speed;
struct completion mdio_done;
int irq[FEC_IRQ_NUM];
- int bufdesc_ex;
+ bool bufdesc_ex;
int pause_flag;
struct napi_struct napi;
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 50a851d..bb006e1 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -3169,8 +3169,6 @@ fec_probe(struct platform_device *pdev)
fep->pdev = pdev;
fep->dev_id = dev_id++;
- fep->bufdesc_ex = 0;
-
platform_set_drvdata(pdev, ndev);
phy_node = of_parse_phandle(np, "phy-handle", 0);
@@ -3228,7 +3226,7 @@ fec_probe(struct platform_device *pdev)
pdev->id_entry->driver_data & FEC_QUIRK_HAS_BUFDESC_EX;
if (IS_ERR(fep->clk_ptp)) {
fep->clk_ptp = NULL;
- fep->bufdesc_ex = 0;
+ fep->bufdesc_ex = false;
}
ret = fec_enet_clk_enable(ndev, true);
--
1.7.10.4
^ permalink raw reply related
* [PATCHv3 5/9] net: fec: improve access to quirk flags by copying them into fec_enet_private struct
From: Lothar Waßmann @ 2014-10-28 13:23 UTC (permalink / raw)
To: netdev
Cc: Fabio Estevam, Frank Li, linux-kernel, Russell King,
David S. Miller, linux-arm-kernel, Lothar Waßmann
In-Reply-To: <1414502584-10583-1-git-send-email-LW@KARO-electronics.de>
Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de>
---
drivers/net/ethernet/freescale/fec.h | 1 +
drivers/net/ethernet/freescale/fec_main.c | 106 +++++++++++------------------
2 files changed, 39 insertions(+), 68 deletions(-)
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 1418813..7aa9388 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -504,6 +504,7 @@ struct fec_enet_private {
int irq[FEC_IRQ_NUM];
bool bufdesc_ex;
int pause_flag;
+ u32 quirks;
struct napi_struct napi;
int csum_flags;
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index bb006e1..5c1d517 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -351,8 +351,6 @@ fec_enet_txq_submit_frag_skb(struct fec_enet_priv_tx_q *txq,
struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
struct bufdesc *bdp = txq->cur_tx;
struct bufdesc_ex *ebdp;
int nr_frags = skb_shinfo(skb)->nr_frags;
@@ -388,7 +386,7 @@ fec_enet_txq_submit_frag_skb(struct fec_enet_priv_tx_q *txq,
}
if (fep->bufdesc_ex) {
- if (id_entry->driver_data & FEC_QUIRK_HAS_AVB)
+ if (fep->quirks & FEC_QUIRK_HAS_AVB)
estatus |= FEC_TX_BD_FTYPE(queue);
if (skb->ip_summed == CHECKSUM_PARTIAL)
estatus |= BD_ENET_TX_PINS | BD_ENET_TX_IINS;
@@ -400,11 +398,11 @@ fec_enet_txq_submit_frag_skb(struct fec_enet_priv_tx_q *txq,
index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
if (((unsigned long) bufaddr) & fep->tx_align ||
- id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
+ fep->quirks & FEC_QUIRK_SWAP_FRAME) {
memcpy(txq->tx_bounce[index], bufaddr, frag_len);
bufaddr = txq->tx_bounce[index];
- if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
+ if (fep->quirks & FEC_QUIRK_SWAP_FRAME)
swap_buffer(bufaddr, frag_len);
}
@@ -440,8 +438,6 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq,
struct sk_buff *skb, struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
int nr_frags = skb_shinfo(skb)->nr_frags;
struct bufdesc *bdp, *last_bdp;
void *bufaddr;
@@ -480,11 +476,11 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq,
queue = skb_get_queue_mapping(skb);
index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
if (((unsigned long) bufaddr) & fep->tx_align ||
- id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
+ fep->quirks & FEC_QUIRK_SWAP_FRAME) {
memcpy(txq->tx_bounce[index], skb->data, buflen);
bufaddr = txq->tx_bounce[index];
- if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
+ if (fep->quirks & FEC_QUIRK_SWAP_FRAME)
swap_buffer(bufaddr, buflen);
}
@@ -519,7 +515,7 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq,
fep->hwts_tx_en))
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
- if (id_entry->driver_data & FEC_QUIRK_HAS_AVB)
+ if (fep->quirks & FEC_QUIRK_HAS_AVB)
estatus |= FEC_TX_BD_FTYPE(queue);
if (skb->ip_summed == CHECKSUM_PARTIAL)
@@ -563,8 +559,6 @@ fec_enet_txq_put_data_tso(struct fec_enet_priv_tx_q *txq, struct sk_buff *skb,
int size, bool last_tcp, bool is_last)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
struct bufdesc_ex *ebdp = container_of(bdp, struct bufdesc_ex, desc);
unsigned short queue = skb_get_queue_mapping(skb);
unsigned short status;
@@ -577,11 +571,11 @@ fec_enet_txq_put_data_tso(struct fec_enet_priv_tx_q *txq, struct sk_buff *skb,
status |= (BD_ENET_TX_TC | BD_ENET_TX_READY);
if (((unsigned long) data) & fep->tx_align ||
- id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
+ fep->quirks & FEC_QUIRK_SWAP_FRAME) {
memcpy(txq->tx_bounce[index], data, size);
data = txq->tx_bounce[index];
- if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
+ if (fep->quirks & FEC_QUIRK_SWAP_FRAME)
swap_buffer(data, size);
}
@@ -597,7 +591,7 @@ fec_enet_txq_put_data_tso(struct fec_enet_priv_tx_q *txq, struct sk_buff *skb,
bdp->cbd_bufaddr = addr;
if (fep->bufdesc_ex) {
- if (id_entry->driver_data & FEC_QUIRK_HAS_AVB)
+ if (fep->quirks & FEC_QUIRK_HAS_AVB)
estatus |= FEC_TX_BD_FTYPE(queue);
if (skb->ip_summed == CHECKSUM_PARTIAL)
estatus |= BD_ENET_TX_PINS | BD_ENET_TX_IINS;
@@ -625,8 +619,6 @@ fec_enet_txq_put_hdr_tso(struct fec_enet_priv_tx_q *txq,
struct bufdesc *bdp, int index)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
struct bufdesc_ex *ebdp = container_of(bdp, struct bufdesc_ex, desc);
unsigned short queue = skb_get_queue_mapping(skb);
@@ -642,11 +634,11 @@ fec_enet_txq_put_hdr_tso(struct fec_enet_priv_tx_q *txq,
bufaddr = txq->tso_hdrs + index * TSO_HEADER_SIZE;
dmabuf = txq->tso_hdrs_dma + index * TSO_HEADER_SIZE;
if (((unsigned long)bufaddr) & fep->tx_align ||
- id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
+ fep->quirks & FEC_QUIRK_SWAP_FRAME) {
memcpy(txq->tx_bounce[index], skb->data, hdr_len);
bufaddr = txq->tx_bounce[index];
- if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
+ if (fep->quirks & FEC_QUIRK_SWAP_FRAME)
swap_buffer(bufaddr, hdr_len);
dmabuf = dma_map_single(&fep->pdev->dev, bufaddr,
@@ -663,7 +655,7 @@ fec_enet_txq_put_hdr_tso(struct fec_enet_priv_tx_q *txq,
bdp->cbd_datlen = hdr_len;
if (fep->bufdesc_ex) {
- if (id_entry->driver_data & FEC_QUIRK_HAS_AVB)
+ if (fep->quirks & FEC_QUIRK_HAS_AVB)
estatus |= FEC_TX_BD_FTYPE(queue);
if (skb->ip_summed == CHECKSUM_PARTIAL)
estatus |= BD_ENET_TX_PINS | BD_ENET_TX_IINS;
@@ -688,8 +680,6 @@ static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq,
struct tso_t tso;
unsigned int index = 0;
int ret;
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
if (tso_count_descs(skb) >= fec_enet_get_free_txdesc_num(fep, txq)) {
dev_kfree_skb_any(skb);
@@ -751,7 +741,7 @@ static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq,
txq->cur_tx = bdp;
/* Trigger transmission start */
- if (!(id_entry->driver_data & FEC_QUIRK_ERR007885) ||
+ if (!(fep->quirks & FEC_QUIRK_ERR007885) ||
!readl(fep->hwp + FEC_X_DES_ACTIVE(queue)) ||
!readl(fep->hwp + FEC_X_DES_ACTIVE(queue)) ||
!readl(fep->hwp + FEC_X_DES_ACTIVE(queue)) ||
@@ -914,8 +904,6 @@ static void
fec_restart(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
u32 val;
u32 temp_mac[2];
u32 rcntl = OPT_FRAME_SIZE | 0x04;
@@ -925,7 +913,7 @@ fec_restart(struct net_device *ndev)
* For i.MX6SX SOC, enet use AXI bus, we use disable MAC
* instead of reset MAC itself.
*/
- if (id_entry && id_entry->driver_data & FEC_QUIRK_HAS_AVB) {
+ if (fep->quirks & FEC_QUIRK_HAS_AVB) {
writel(0, fep->hwp + FEC_ECNTRL);
} else {
writel(1, fep->hwp + FEC_ECNTRL);
@@ -936,7 +924,7 @@ fec_restart(struct net_device *ndev)
* enet-mac reset will reset mac address registers too,
* so need to reconfigure it.
*/
- if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
+ if (fep->quirks & FEC_QUIRK_ENET_MAC) {
memcpy(&temp_mac, ndev->dev_addr, ETH_ALEN);
writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW);
writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH);
@@ -982,7 +970,7 @@ fec_restart(struct net_device *ndev)
* The phy interface and speed need to get configured
* differently on enet-mac.
*/
- if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
+ if (fep->quirks & FEC_QUIRK_ENET_MAC) {
/* Enable flow control and length check */
rcntl |= 0x40000000 | 0x00000020;
@@ -1005,7 +993,7 @@ fec_restart(struct net_device *ndev)
}
} else {
#ifdef FEC_MIIGSK_ENR
- if (id_entry->driver_data & FEC_QUIRK_USE_GASKET) {
+ if (fep->quirks & FEC_QUIRK_USE_GASKET) {
u32 cfgr;
/* disable the gasket and wait */
writel(0, fep->hwp + FEC_MIIGSK_ENR);
@@ -1058,7 +1046,7 @@ fec_restart(struct net_device *ndev)
writel(0, fep->hwp + FEC_HASH_TABLE_LOW);
#endif
- if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
+ if (fep->quirks & FEC_QUIRK_ENET_MAC) {
/* enable ENET endian swap */
ecntl |= (1 << 8);
/* enable ENET store and forward mode */
@@ -1092,8 +1080,6 @@ static void
fec_stop(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8);
/* We cannot expect a graceful transmit stop without link !!! */
@@ -1108,7 +1094,7 @@ fec_stop(struct net_device *ndev)
* For i.MX6SX SOC, enet use AXI bus, we use disable MAC
* instead of reset MAC itself.
*/
- if (id_entry && id_entry->driver_data & FEC_QUIRK_HAS_AVB) {
+ if (fep->quirks & FEC_QUIRK_HAS_AVB) {
writel(0, fep->hwp + FEC_ECNTRL);
} else {
writel(1, fep->hwp + FEC_ECNTRL);
@@ -1118,7 +1104,7 @@ fec_stop(struct net_device *ndev)
writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
/* We have to keep ENET enabled to have MII interrupt stay working */
- if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
+ if (fep->quirks & FEC_QUIRK_ENET_MAC) {
writel(2, fep->hwp + FEC_ECNTRL);
writel(rmii_mode, fep->hwp + FEC_R_CNTRL);
}
@@ -1337,8 +1323,6 @@ static int
fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
struct fec_enet_priv_rx_q *rxq;
struct bufdesc *bdp;
unsigned short status;
@@ -1430,7 +1414,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
prefetch(skb->data - NET_IP_ALIGN);
skb_put(skb, pkt_len - 4);
data = skb->data;
- if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
+ if (fep->quirks & FEC_QUIRK_SWAP_FRAME)
swap_buffer(data, pkt_len);
/* Extract the enhanced buffer descriptor */
@@ -1865,8 +1849,6 @@ failed_clk_ipg:
static int fec_enet_mii_probe(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
struct phy_device *phy_dev = NULL;
char mdio_bus_id[MII_BUS_ID_SIZE];
char phy_name[MII_BUS_ID_SIZE + 3];
@@ -1912,7 +1894,7 @@ static int fec_enet_mii_probe(struct net_device *ndev)
}
/* mask with MAC supported features */
- if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT) {
+ if (fep->quirks & FEC_QUIRK_HAS_GBIT) {
phy_dev->supported &= PHY_GBIT_FEATURES;
phy_dev->supported &= ~SUPPORTED_1000baseT_Half;
#if !defined(CONFIG_M5272)
@@ -1940,8 +1922,6 @@ static int fec_enet_mii_init(struct platform_device *pdev)
static struct mii_bus *fec0_mii_bus;
struct net_device *ndev = platform_get_drvdata(pdev);
struct fec_enet_private *fep = netdev_priv(ndev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
struct device_node *node;
int err = -ENXIO, i;
@@ -1961,7 +1941,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)
* mdio interface in board design, and need to be configured by
* fec0 mii_bus.
*/
- if ((id_entry->driver_data & FEC_QUIRK_ENET_MAC) && fep->dev_id > 0) {
+ if ((fep->quirks & FEC_QUIRK_ENET_MAC) && fep->dev_id > 0) {
/* fec1 uses fec0 mii_bus */
if (mii_cnt && fec0_mii_bus) {
fep->mii_bus = fec0_mii_bus;
@@ -1982,7 +1962,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)
* document.
*/
fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 5000000);
- if (id_entry->driver_data & FEC_QUIRK_ENET_MAC)
+ if (fep->quirks & FEC_QUIRK_ENET_MAC)
fep->phy_speed--;
fep->phy_speed <<= 1;
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
@@ -2024,7 +2004,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)
mii_cnt++;
/* save fec0 mii_bus */
- if (id_entry->driver_data & FEC_QUIRK_ENET_MAC)
+ if (fep->quirks & FEC_QUIRK_ENET_MAC)
fec0_mii_bus = fep->mii_bus;
return 0;
@@ -2293,11 +2273,9 @@ static int fec_enet_us_to_itr_clock(struct net_device *ndev, int us)
static void fec_enet_itr_coal_set(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
int rx_itr, tx_itr;
- if (!(id_entry->driver_data & FEC_QUIRK_HAS_AVB))
+ if (!(fep->quirks & FEC_QUIRK_HAS_AVB))
return;
/* Must be greater than zero to avoid unpredictable behavior */
@@ -2332,10 +2310,8 @@ static int
fec_enet_get_coalesce(struct net_device *ndev, struct ethtool_coalesce *ec)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
- if (!(id_entry->driver_data & FEC_QUIRK_HAS_AVB))
+ if (!(fep->quirks & FEC_QUIRK_HAS_AVB))
return -EOPNOTSUPP;
ec->rx_coalesce_usecs = fep->rx_time_itr;
@@ -2351,12 +2327,9 @@ static int
fec_enet_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *ec)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
-
unsigned int cycle;
- if (!(id_entry->driver_data & FEC_QUIRK_HAS_AVB))
+ if (!(fep->quirks & FEC_QUIRK_HAS_AVB))
return -EOPNOTSUPP;
if (ec->rx_max_coalesced_frames > 255) {
@@ -2936,8 +2909,6 @@ static const struct net_device_ops fec_netdev_ops = {
static int fec_enet_init(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
struct fec_enet_priv_tx_q *txq;
struct fec_enet_priv_rx_q *rxq;
struct bufdesc *cbd_base;
@@ -3016,11 +2987,11 @@ static int fec_enet_init(struct net_device *ndev)
writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK);
netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, NAPI_POLL_WEIGHT);
- if (id_entry->driver_data & FEC_QUIRK_HAS_VLAN)
+ if (fep->quirks & FEC_QUIRK_HAS_VLAN)
/* enable hw VLAN support */
ndev->features |= NETIF_F_HW_VLAN_CTAG_RX;
- if (id_entry->driver_data & FEC_QUIRK_HAS_CSUM) {
+ if (fep->quirks & FEC_QUIRK_HAS_CSUM) {
ndev->gso_max_segs = FEC_MAX_TSO_SEGS;
/* enable hw accelerator */
@@ -3029,7 +3000,7 @@ static int fec_enet_init(struct net_device *ndev)
fep->csum_flags |= FLAG_RX_CSUM_ENABLED;
}
- if (id_entry->driver_data & FEC_QUIRK_HAS_AVB) {
+ if (fep->quirks & FEC_QUIRK_HAS_AVB) {
fep->tx_align = 0;
fep->rx_align = 0x3f;
}
@@ -3129,10 +3100,6 @@ fec_probe(struct platform_device *pdev)
int num_tx_qs;
int num_rx_qs;
- of_id = of_match_device(fec_dt_ids, &pdev->dev);
- if (of_id)
- pdev->id_entry = of_id->data;
-
fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs);
/* Init network device */
@@ -3146,13 +3113,17 @@ fec_probe(struct platform_device *pdev)
/* setup board info structure */
fep = netdev_priv(ndev);
+ of_id = of_match_device(fec_dt_ids, &pdev->dev);
+ if (of_id)
+ pdev->id_entry = of_id->data;
+ fep->quirks = pdev->id_entry->driver_data;
+
fep->num_rx_queues = num_rx_qs;
fep->num_tx_queues = num_tx_qs;
#if !defined(CONFIG_M5272)
/* default enable pause frame auto negotiation */
- if (pdev->id_entry &&
- (pdev->id_entry->driver_data & FEC_QUIRK_HAS_GBIT))
+ if (fep->quirks & FEC_QUIRK_HAS_GBIT)
fep->pause_flag |= FEC_PAUSE_FLAG_AUTONEG;
#endif
@@ -3221,9 +3192,8 @@ fec_probe(struct platform_device *pdev)
if (IS_ERR(fep->clk_ref))
fep->clk_ref = NULL;
+ fep->bufdesc_ex = fep->quirks & FEC_QUIRK_HAS_BUFDESC_EX;
fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp");
- fep->bufdesc_ex =
- pdev->id_entry->driver_data & FEC_QUIRK_HAS_BUFDESC_EX;
if (IS_ERR(fep->clk_ptp)) {
fep->clk_ptp = NULL;
fep->bufdesc_ex = false;
--
1.7.10.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox