* [PATCH net-next v1 4/4] amd-xgbe-phy: Checkpatch driver fixes
From: Tom Lendacky @ 2014-09-03 17:14 UTC (permalink / raw)
To: netdev; +Cc: davem
In-Reply-To: <20140903171410.9710.37086.stgit@tlendack-t1.amdoffice.net>
This patch contains fixes identified by checkpatch when run with the
strict option.
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
---
drivers/net/phy/amd-xgbe-phy.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/drivers/net/phy/amd-xgbe-phy.c b/drivers/net/phy/amd-xgbe-phy.c
index da351d3..4e1f7f7 100644
--- a/drivers/net/phy/amd-xgbe-phy.c
+++ b/drivers/net/phy/amd-xgbe-phy.c
@@ -75,7 +75,6 @@
#include <linux/of_device.h>
#include <linux/uaccess.h>
-
MODULE_AUTHOR("Tom Lendacky <thomas.lendacky@amd.com>");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION("1.0.0-a");
@@ -172,7 +171,6 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
#define SPEED_1000_TXAMP 0xf
#define SPEED_1000_WORD 0x1
-
/* SerDes RxTx register offsets */
#define RXTX_REG20 0x0050
#define RXTX_REG114 0x01c8
@@ -266,7 +264,6 @@ do { \
XSIR1_IOWRITE((_priv), _reg, reg_val); \
} while (0)
-
/* Macros for reading or writing SerDes RxTx registers
* The ioread macros will get bit fields or full values using the
* register definitions formed using the input names
@@ -294,7 +291,6 @@ do { \
XRXTX_IOWRITE((_priv), _reg, reg_val); \
} while (0)
-
enum amd_xgbe_phy_an {
AMD_XGBE_AN_READY = 0,
AMD_XGBE_AN_START,
^ permalink raw reply related
* Re: [PATCH net-next] mlx4_en: Convert the normal skb free path to dev_consume_skb_any()
From: Eric Dumazet @ 2014-09-03 17:53 UTC (permalink / raw)
To: Rick Jones; +Cc: netdev, amirv, davem
In-Reply-To: <20140903161800.301F629002CD@tardy>
On Wed, 2014-09-03 at 09:18 -0700, Rick Jones wrote:
> From: Rick Jones <rick.jones2@hp.com>
>
> It would appear the mlx4_en driver was still making a call to
> dev_kfree_skb_any() where dev_consume_skb_any() would be more
> appropriate. This should make dropped packet profiling/tracking
> easier/better over a NIC driven by mlx4_en.
>
> Signed-off-by: Rick Jones <rick.jones2@hp.com>
>
> ---
>
> Compile tested only
>
>
> diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
> index dae3da6..bc8f51c 100644
> --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c
> +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
> @@ -319,7 +319,7 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
> }
> }
> }
> - dev_kfree_skb_any(skb);
> + dev_consume_skb_any(skb);
> return tx_info->nr_txbb;
> }
>
I use a similar patch here, I confirm this works.
Acked-by: Eric Dumazet <edumazet@google.com>
^ permalink raw reply
* Re: [PATCH v5 1/4] ethernet: arc: Add support for Rockchip SoC layer device tree bindings
From: Arnd Bergmann @ 2014-09-03 18:17 UTC (permalink / raw)
To: linux-arm-kernel; +Cc: Romain Perier, heiko, linux-rockchip, devicetree, netdev
In-Reply-To: <1409763165-16461-1-git-send-email-romain.perier@gmail.com>
On Wednesday 03 September 2014 16:52:42 Romain Perier wrote:
> This patch defines a platform glue layer for Rockchip SoCs which
> support arc-emac driver. It ensures that regulator for the rmii is on
> before trying to connect to the ethernet controller. It applies right
> speed and mode changes to the grf when ethernet settings change.
>
> Signed-off-by: Romain Perier <romain.perier@gmail.com>
>
Whole series
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
^ permalink raw reply
* Re: [PATCH net] core: Don't attempt to load the "" driver.
From: Stephen Hemminger @ 2014-09-03 18:18 UTC (permalink / raw)
To: Cong Wang; +Cc: David Laight, Linux Netdev List, David Miller
In-Reply-To: <CAHA+R7OoBp=ZAJeg_hXRjNhT6_n2siVQidJK6hx8EtHW7iRwqA@mail.gmail.com>
On Wed, 3 Sep 2014 10:02:26 -0700
Cong Wang <cwang@twopensource.com> wrote:
> On Wed, Sep 3, 2014 at 2:02 AM, David Laight <David.Laight@aculab.com> wrote:
> >> On Tue, Sep 2, 2014 at 6:48 AM, David Laight <David.Laight@aculab.com> wrote:
> >> > While the applications shouldn't be calling an SIOCxxx ioctl with ifr_name[0] == 0
> >> > the kernel shouldn't be tracing the error either.
> >> >
> >>
> >> Why don't we reject this empty string? It doesn't look like a valid one.
> >> I assume this is for compatibility?
> >
> > The ioctl code will error it later on - the module load is 'speculative'.
> > Analysing whether all the ioctls need dev_load() to succeed is another issue.
> >
> > Indeed I'm not sure anything stops the module being unloaded before the
> > ioctl action tries to take a real reference on the interface.
> >
> > Whether request_module("") should be an error is a different question,
> > probably much harder to analyse.
> >
>
> If an empty string is an invalid name, we definitely should reject it from
> the very beginning, so that you would not need to worry about the above
> issues.
>
> Something like the attached patch.
This will break for many things where the code randomly tries
to load something based on name, but the module is already there.
^ permalink raw reply
* (no subject)
From: US-ARMEE @ 2014-09-03 12:18 UTC (permalink / raw)
--
Hallo Freund
Ich bin Sgt Edward Hatton, ein amerikanischer Soldat, der derzeit in
Kabul Afghanistan dienen. Sie vertraut werden können?; Kann ich $ 5,5
Millionen Us-Dollar in Ihre Obhut anzuvertrauen? Ich wird dich dieser
Transaktion mehr aufzuklären, sobald ich von Ihnen zu hören. Ich brauche
nur eine vertrauenswürdige Person mir erhalten und diese Mittel zu
sichern, bis ich durch meine Pflicht hier Kabul Afghanistan bin zu
helfen.
^ permalink raw reply
* Re: [patch net-next 01/13] openvswitch: split flow structures into ovs specific and generic ones
From: Pravin Shelar @ 2014-09-03 18:41 UTC (permalink / raw)
To: Jiri Pirko
Cc: netdev, David Miller, nhorman, andy, Thomas Graf, Daniel Borkmann,
Or Gerlitz, Jesse Gross, Andy Zhou, Ben Hutchings,
Stephen Hemminger, jeffrey.t.kirsher, vyasevic, Cong Wang,
john.r.fastabend, Eric Dumazet, jhs, sfeldma, f.fainelli, roopa,
John Linville, dev@openvswitch.org, jasowang, ebiederm,
Nicolas Dichtel, ryazanov.s.a, buytenh, aviadr, nbd, alexei.s
In-Reply-To: <1409736300-12303-2-git-send-email-jiri@resnulli.us>
On Wed, Sep 3, 2014 at 2:24 AM, Jiri Pirko <jiri@resnulli.us> wrote:
> After this, flow related structures can be used in other code.
>
> Signed-off-by: Jiri Pirko <jiri@resnulli.us>
> ---
> include/net/sw_flow.h | 99 ++++++++++++++++++++++++++++++++++
> net/openvswitch/actions.c | 3 +-
> net/openvswitch/datapath.c | 74 +++++++++++++-------------
> net/openvswitch/datapath.h | 4 +-
> net/openvswitch/flow.c | 6 +--
> net/openvswitch/flow.h | 102 +++++++----------------------------
> net/openvswitch/flow_netlink.c | 53 +++++++++---------
> net/openvswitch/flow_netlink.h | 10 ++--
> net/openvswitch/flow_table.c | 118 ++++++++++++++++++++++-------------------
> net/openvswitch/flow_table.h | 30 +++++------
> net/openvswitch/vport-gre.c | 4 +-
> net/openvswitch/vport-vxlan.c | 2 +-
> net/openvswitch/vport.c | 2 +-
> net/openvswitch/vport.h | 2 +-
> 14 files changed, 276 insertions(+), 233 deletions(-)
> create mode 100644 include/net/sw_flow.h
>
> diff --git a/include/net/sw_flow.h b/include/net/sw_flow.h
> new file mode 100644
> index 0000000..21724f1
> --- /dev/null
> +++ b/include/net/sw_flow.h
> @@ -0,0 +1,99 @@
> +/*
> + * include/net/sw_flow.h - Generic switch flow structures
> + * Copyright (c) 2007-2012 Nicira, Inc.
> + * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#ifndef _NET_SW_FLOW_H_
> +#define _NET_SW_FLOW_H_
> +
> +struct sw_flow_key_ipv4_tunnel {
> + __be64 tun_id;
> + __be32 ipv4_src;
> + __be32 ipv4_dst;
> + __be16 tun_flags;
> + u8 ipv4_tos;
> + u8 ipv4_ttl;
> +};
> +
> +struct sw_flow_key {
> + struct sw_flow_key_ipv4_tunnel tun_key; /* Encapsulating tunnel key. */
> + struct {
> + u32 priority; /* Packet QoS priority. */
> + u32 skb_mark; /* SKB mark. */
> + u16 in_port; /* Input switch port (or DP_MAX_PORTS). */
> + } __packed phy; /* Safe when right after 'tun_key'. */
> + struct {
> + u8 src[ETH_ALEN]; /* Ethernet source address. */
> + u8 dst[ETH_ALEN]; /* Ethernet destination address. */
> + __be16 tci; /* 0 if no VLAN, VLAN_TAG_PRESENT set otherwise. */
> + __be16 type; /* Ethernet frame type. */
> + } eth;
> + struct {
> + u8 proto; /* IP protocol or lower 8 bits of ARP opcode. */
> + u8 tos; /* IP ToS. */
> + u8 ttl; /* IP TTL/hop limit. */
> + u8 frag; /* One of OVS_FRAG_TYPE_*. */
> + } ip;
> + struct {
> + __be16 src; /* TCP/UDP/SCTP source port. */
> + __be16 dst; /* TCP/UDP/SCTP destination port. */
> + __be16 flags; /* TCP flags. */
> + } tp;
> + union {
> + struct {
> + struct {
> + __be32 src; /* IP source address. */
> + __be32 dst; /* IP destination address. */
> + } addr;
> + struct {
> + u8 sha[ETH_ALEN]; /* ARP source hardware address. */
> + u8 tha[ETH_ALEN]; /* ARP target hardware address. */
> + } arp;
> + } ipv4;
> + struct {
> + struct {
> + struct in6_addr src; /* IPv6 source address. */
> + struct in6_addr dst; /* IPv6 destination address. */
> + } addr;
> + __be32 label; /* IPv6 flow label. */
> + struct {
> + struct in6_addr target; /* ND target address. */
> + u8 sll[ETH_ALEN]; /* ND source link layer address. */
> + u8 tll[ETH_ALEN]; /* ND target link layer address. */
> + } nd;
> + } ipv6;
> + };
> +} __aligned(BITS_PER_LONG/8); /* Ensure that we can do comparisons as longs. */
> +
HW offload API should be separate from OVS module. This has following
advantages.
1. It can be managed by OVS userspace vswitchd process which has much
better context to setup hardware flow table. Once we add capabilities
for swdev, it is much more easier for vswitchd process to choose
correct (hw or sw) flow table for given flow.
2. Other application that wants to use HW offload does not have
dependency on OVS kernel module.
3. Hardware and software datapath remains separate, these two
components has no dependency on each other, both can be developed
independent of each other.
Thanks.
^ permalink raw reply
* Re: [PATCH v2 2/4] dt-bindings: Document EMAC Rockchip
From: PERIER Romain @ 2014-09-03 18:41 UTC (permalink / raw)
To: netdev
In-Reply-To: <1409763165-16461-2-git-send-email-romain.perier@gmail.com>
see "[PATCH v5 1/4] ethernet: arc: Add support for Rockchip SoC layer
device tree bindings" for acceptance
2014-09-03 18:52 GMT+02:00 Romain Perier <romain.perier@gmail.com>:
> This adds the necessary binding documentation for the EMAC Rockchip platform
> driver found in RK3066 and RK3188 SoCs.
>
> Signed-off-by: Romain Perier <romain.perier@gmail.com>
> ---
> .../devicetree/bindings/net/emac_rockchip.txt | 50 ++++++++++++++++++++++
> 1 file changed, 50 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/net/emac_rockchip.txt
>
> diff --git a/Documentation/devicetree/bindings/net/emac_rockchip.txt b/Documentation/devicetree/bindings/net/emac_rockchip.txt
> new file mode 100644
> index 0000000..8dc1c79
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/emac_rockchip.txt
> @@ -0,0 +1,50 @@
> +* ARC EMAC 10/100 Ethernet platform driver for Rockchip Rk3066/RK3188 SoCs
> +
> +Required properties:
> +- compatible: Should be "rockchip,rk3066-emac" or "rockchip,rk3188-emac"
> + according to the target SoC.
> +- reg: Address and length of the register set for the device
> +- interrupts: Should contain the EMAC interrupts
> +- rockchip,grf: phandle to the syscon grf used to control speed and mode
> + for emac.
> +- phy: see ethernet.txt file in the same directory.
> +- phy-mode: see ethernet.txt file in the same directory.
> +
> +Optional properties:
> +- phy-supply: phandle to a regulator if the PHY needs one
> +
> +Clock handling:
> +- clocks: Must contain an entry for each entry in clock-names.
> +- clock-names: Shall be "hclk" for the host clock needed to calculate and set
> + polling period of EMAC and "macref" for the reference clock needed to transfer
> + data to and from the phy.
> +
> +Child nodes of the driver are the individual PHY devices connected to the
> +MDIO bus. They must have a "reg" property given the PHY address on the MDIO bus.
> +
> +Examples:
> +
> +ethernet@10204000 {
> + compatible = "rockchip,rk3188-emac";
> + reg = <0xc0fc2000 0x3c>;
> + interrupts = <6>;
> + mac-address = [ 00 11 22 33 44 55 ];
> +
> + clocks = <&cru HCLK_EMAC>, <&cru SCLK_MAC>;
> + clock-names = "hclk", "macref";
> +
> + pinctrl-names = "default";
> + pinctrl-0 = <&emac_xfer>, <&emac_mdio>, <&phy_int>;
> +
> + rockchip,grf = <&grf>;
> +
> + phy = <&phy0>;
> + phy-mode = "rmii";
> + phy-supply = <&vcc_rmii>;
> +
> + #address-cells = <1>;
> + #size-cells = <0>;
> + phy0: ethernet-phy@0 {
> + reg = <1>;
> + };
> +};
> --
> 1.9.1
>
^ permalink raw reply
* Re: [patch net-next 01/13] openvswitch: split flow structures into ovs specific and generic ones
From: Pravin Shelar @ 2014-09-03 18:42 UTC (permalink / raw)
To: John Fastabend
Cc: ryazanov.s.a-Re5JQEeQqe8AvxtiuMwx3w,
jasowang-H+wXaHxf7aLQT0dZR+AlfA,
john.r.fastabend-ral2JQCrhuEAvxtiuMwx3w,
Neil.Jerram-QnUH15yq9NYqDJ6do+/SaQ, Eric Dumazet,
andy-QlMahl40kYEqcZcGjlUOXw,
dev-yBygre7rU0TnMu66kgdUjQ@public.gmane.org,
nbd-p3rKhJxN3npAfugRpC6u6w, f.fainelli-Re5JQEeQqe8AvxtiuMwx3w,
Rony Efraim, jeffrey.t.kirsher-ral2JQCrhuEAvxtiuMwx3w, Or Gerlitz,
Ben Hutchings, buytenh-OLH4Qvv75CYX/NnBR394Jw, Jiri Pirko,
roopa-qUQiAmfTcIp+XZJcv9eMoEEOCMrvLtNR,
jhs-jkUAjuhPggJWk0Htik3J/w, aviadr-VPRAkNaXOzVWk0Htik3J/w,
Nicolas Dichtel, vyasevic-H+wXaHxf7aLQT0dZR+AlfA,
nhorman-2XuSBdqkA4R54TAoqtyWWQ, netdev, Stephen Hemminger,
Daniel Borkmann, ebiederm-aS9lmoZGLiVWk0Htik3J/w, David Miller
In-Reply-To: <540731B9.4010603-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On Wed, Sep 3, 2014 at 8:20 AM, John Fastabend <john.fastabend-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On 09/03/2014 02:24 AM, Jiri Pirko wrote:
>>
>> After this, flow related structures can be used in other code.
>>
>> Signed-off-by: Jiri Pirko <jiri-rHqAuBHg3fBzbRFIqnYvSA@public.gmane.org>
>> ---
>
>
> Hi Jiri,
>
> As I indicated before I'm looking into integrating this with some
> hardware here. Progress is a bit slow but starting to look at it.The
> i40e/ixgbe driver being one open source example with very limited
> support for tables, flow matches, etc. And then a closed source driver
> with much more flexibility. What I don't have is a middle of the road
> switch to work with something better then a host nic but not as
> flexible as a TOR.
>
> Couple questions my assumption here is I can extend the flow_key
> as needed to support additional match criteria my hardware has.
> I scanned the ./net/openvswitch source and I didn't catch any
> place that would break but might need to take a closer look.
> Similarly the actions set will need to be extended. For example
> if I want to use this with i40e a OVS_ACTION_ATTR_QUEUE could
> be used to steer packets to the queue. With this in mind we
> will want a follow up patch to rename OVS_ACTION_ATTR_* to
> FLOW_ACTION_ATTR_*
>
struct sw_flow_key is internal structure of OVS, it is designed to
have better flow-table performance. By adding hw specific fields in
sw_flow_key, it increase flow-key size and that has negative impact on
OVS software switching performance. Therefore it is better not to
share this internal structure with driver interface.
Thanks.
> Also I have some filters that can match on offset/length/mask
> tuples. As far as I can tell this is going to have to be yet
> another interface? Or would it be worth the effort to define
> the flow key more generically. My initial guess is I'll just
> write a separate interface. I think this is what Jamal referred
> to as another "classifier".
>
> Thanks,
> John
>
> [...]
>
>
>> +
>> +struct sw_flow_key_ipv4_tunnel {
>> + __be64 tun_id;
>> + __be32 ipv4_src;
>> + __be32 ipv4_dst;
>> + __be16 tun_flags;
>> + u8 ipv4_tos;
>> + u8 ipv4_ttl;
>> +};
>> +
>> +struct sw_flow_key {
>> + struct sw_flow_key_ipv4_tunnel tun_key; /* Encapsulating tunnel
>> key. */
>> + struct {
>> + u32 priority; /* Packet QoS priority. */
>> + u32 skb_mark; /* SKB mark. */
>> + u16 in_port; /* Input switch port (or
>> DP_MAX_PORTS). */
>> + } __packed phy; /* Safe when right after 'tun_key'. */
>> + struct {
>> + u8 src[ETH_ALEN]; /* Ethernet source address. */
>> + u8 dst[ETH_ALEN]; /* Ethernet destination address.
>> */
>> + __be16 tci; /* 0 if no VLAN, VLAN_TAG_PRESENT
>> set otherwise. */
>> + __be16 type; /* Ethernet frame type. */
>> + } eth;
>> + struct {
>> + u8 proto; /* IP protocol or lower 8 bits of
>> ARP opcode. */
>> + u8 tos; /* IP ToS. */
>> + u8 ttl; /* IP TTL/hop limit. */
>> + u8 frag; /* One of OVS_FRAG_TYPE_*. */
>> + } ip;
>> + struct {
>> + __be16 src; /* TCP/UDP/SCTP source port. */
>> + __be16 dst; /* TCP/UDP/SCTP destination port.
>> */
>> + __be16 flags; /* TCP flags. */
>> + } tp;
>> + union {
>> + struct {
>> + struct {
>> + __be32 src; /* IP source address. */
>> + __be32 dst; /* IP destination address.
>> */
>> + } addr;
>> + struct {
>> + u8 sha[ETH_ALEN]; /* ARP source
>> hardware address. */
>> + u8 tha[ETH_ALEN]; /* ARP target
>> hardware address. */
>> + } arp;
>> + } ipv4;
>> + struct {
>> + struct {
>> + struct in6_addr src; /* IPv6 source
>> address. */
>> + struct in6_addr dst; /* IPv6
>> destination address. */
>> + } addr;
>> + __be32 label; /* IPv6 flow
>> label. */
>> + struct {
>> + struct in6_addr target; /* ND target
>> address. */
>> + u8 sll[ETH_ALEN]; /* ND source link
>> layer address. */
>> + u8 tll[ETH_ALEN]; /* ND target link
>> layer address. */
>> + } nd;
>> + } ipv6;
>> + };
>> +} __aligned(BITS_PER_LONG/8); /* Ensure that we can do comparisons as
>> longs. */
>> +
>> +struct sw_flow_key_range {
>> + unsigned short int start;
>> + unsigned short int end;
>> +};
>> +
>> +struct sw_flow_mask {
>> + struct sw_flow_key_range range;
>> + struct sw_flow_key key;
>> +};
>> +
>> +struct sw_flow_action {
>> +};
>> +
>> +struct sw_flow_actions {
>> + unsigned count;
>> + struct sw_flow_action actions[0];
>> +};
>> +
>> +struct sw_flow {
>> + struct sw_flow_key key;
>> + struct sw_flow_key unmasked_key;
>> + struct sw_flow_mask *mask;
>> + struct sw_flow_actions *actions;
>> +};
>> +
>
>
>
> --
> John Fastabend Intel Corporation
^ permalink raw reply
* Re: [PATCH 1/2] net-timestamp: Merge shared code between phy and regular timestamping
From: Willem de Bruijn @ 2014-09-03 18:50 UTC (permalink / raw)
To: Alexander Duyck; +Cc: Network Development, Richard Cochran, David Miller
In-Reply-To: <20140903155351.1896.54047.stgit@ahduyck-bv4.jf.intel.com>
> +}
> +EXPORT_SYMBOL_GPL(skb_complete_tx_timestamp);
> +
> +void __skb_tstamp_tx(struct sk_buff *orig_skb,
> + struct skb_shared_hwtstamps *hwtstamps,
> + struct sock *sk, int tstype)
> +{
> + struct sk_buff *skb;
> +
> + if (!sk)
> + return;
> +
> + /*
> + * no hardware time stamps available,
> + * so keep the shared tx_flags and only
> + * store software time stamp
> + */
This comment only makes sense within the else {} clause. As a matter
of fact, I'd just drop it. The patch also inverts the branch. I would
keep the original order, as that is also the order in
skb_complete_tx_timestamp.
> + if (!hwtstamps)
> + orig_skb->tstamp = ktime_get_real();
> + else
> + *skb_hwtstamps(orig_skb) = *hwtstamps;
> +
Otherwise looks great to me. The code deduplicates shared code between
__skb_tstamp_tx and skb_complete_timestamp without introduces logical
changes to either codepath.
^ permalink raw reply
* Re: [PATCH 2/2] net-timestamp: Make the clone operation stand-alone from phy timestamping
From: Willem de Bruijn @ 2014-09-03 18:54 UTC (permalink / raw)
To: Alexander Duyck; +Cc: Network Development, Richard Cochran, David Miller
In-Reply-To: <20140903155357.1896.92538.stgit@ahduyck-bv4.jf.intel.com>
On Wed, Sep 3, 2014 at 11:53 AM, Alexander Duyck
<alexander.h.duyck@intel.com> wrote:
> The phy timestamping takes a different path than the regular timestamping
> does in that it will create a clone first so that the packets needing to be
> timestamped can be placed in a queue, or the context block could be used.
>
> In order to support these use cases I am pulling the core of the code out
> so it can be used in other drivers beyond just phy devices.
Do you already have additional such use cases?
> +struct sk_buff *__skb_clone_tx_timestamp(struct sk_buff *skb)
> +{
> + struct sock *sk = skb->sk;
> + struct sk_buff *clone;
> +
> + if (!sk || !atomic_inc_not_zero(&sk->sk_refcnt))
> + return NULL;
> +
> + clone = skb_clone(skb, GFP_ATOMIC);
> + if (!clone) {
> + sock_put(sk);
> + return NULL;
> + }
> +
> + clone->sk = sk;
> +
> + return clone;
> +}
> +EXPORT_SYMBOL(__skb_clone_tx_timestamp);
> +
Code looks great. Again, this can be verified to be a functional noop.
One minor comment is that this really is not a timestamping function,
but an skb_clone variant. skb_clone_sk?
^ permalink raw reply
* Re: [PATCH 3/6] drivers: net: ethernet: cpsw: add multicast address to ALE table
From: Graeme Smecher @ 2014-09-03 19:01 UTC (permalink / raw)
To: Mugunthan V N; +Cc: netdev
In-Reply-To: <5406D128.3080304@ti.com>
Hi Mungathan,
FYI, I think the multicast bug I'm working on also affects dual EMAC
mode in upstream cpsw.c. I will add a 2.6.37-specific patch on my e2e
forum post (link below), but this is a heads-up for code you maintain.
Symptoms: each port in dual EMAC mode trashes the other port's multicast
reception.
Cause: cpsw_ndo_set_rx_mode does the following:
cpsw_ale_flush_multicast(priv->ale, ALE_ALL_PORTS << priv->host_port);
if (!netdev_mc_empty(ndev)) {
struct netdev_hw_addr *ha;
/* program multicast address list into ALE register */
netdev_for_each_mc_addr(ha, ndev) {
cpsw_add_mcast(priv, (u8 *)ha->addr);
}
}
This code can be invoked by eth0 or eth1, which have potentially
differing multicast lists. However, cpsw_ale_flush_multicast() trashes
ALL multicast entries in the ALE, affecting both ports. Only the entries
for the net_device that invoked cpsw_ndo_set_rx_mode() are restored.
To fix this, you will have to pass a correct port_mask to
cpsw_ale_flush_multicast(), and correct the free-entry check at the
bottom of cpsw_ale_flush_mcast().
best,
Graeme
On Wed, 2014-09-03 at 13:58 +0530, Mugunthan V N wrote:
> Hi Graeme
>
> There is already a support for add multicast in v2.6.37 cpsw driver, if
> there is a bug and you found a fix, can go a head and fix that. The
> patch you have mentioned is an upstream patch with was done on top of
> am335x platform, so there might be bugs fixed and added into the patch
> which are not in v2.6.37 cpsw driver.
>
> Regards
> Mugunthan V N
>
> On Tuesday 02 September 2014 11:52 PM, Graeme Smecher wrote:
> > Hi Mugunthan,
> >
> >> On Wed, Oct 17, 2012 at 04:15:15AM +0530, Mugunthan V N wrote:
> >>> Adding multicast address to ALE table via netdev ops to subscribe, transmit
> >>> or receive multicast frames to and from the network
> >>
> >> Is this somehow related to the time stamping function? If so, how?
> >>
> >> Thanks,
> >> Richard
> >
> > Can you give me a brief description of this (relatively ancient) patch? Your
> > original e-mail is visible here:
> >
> > http://marc.info/?l=linux-netdev&m=135042754927177&w=2
> >
> > I'm wondering if this patch needs to be backported to older CPSW driver
> > snapshots (specifically, TI's 2.6.37 branch for dm81xx.) It appears to
> > fix a multicast bug I'm tracking down, but it's difficult to know for
> > sure without a good description of what problem the patch addresses. (I
> > don't want to commit code that fixes my hardware by accident.)
> >
> > For a little more information, you can refer to my e2e.ti.com post:
> >
> > http://e2e.ti.com/support/dsp/davinci_digital_media_processors/f/716/t/365586.aspx
> >
> > I'm slowly learning about ALE filtering, but a quick reply from a
> > domain expert would be very helpful.
> >
> > best,
> > Graeme
> >
>
^ permalink raw reply
* FROM: Husam Al Sayed.
From: Husam Al Sayed @ 2014-09-03 18:57 UTC (permalink / raw)
Cc: bp, linux-edac, m.chehab, boris.ostrovsky, david.vrabel,
stefano.stabellini, ian.campbell, wei.liu2, netdev, konrad.wilk,
xen-devel, david, bpm, xfs, anirudh, John.Linn, jacmet,
linux-serial, jpr, Henk.Vergonet, usbb2k-api-dev, jreuter,
linux-hams, dsd, kune, linux-wireless, zd1211-devs, mjpeg-users,
linux-media, macro
FROM: Husam Al Sayed.
EMAIL:alsayedhusa@hotmail.com
Hello,
I decided to write you this proposal in good faith, believing that you will
not betray me. I am Mr. Husam Al Sayed, a Bank officer here in U.A.E.
One Mr. Peter Adams, a citizen of your country and Crude Oil dealer made a fixed deposit with my bank in 2005 for 108 calendar months, valued at US$30,000,000.00 (Thirty Million United State Dollars) the due date for this deposit contract was last 22nd of January 2014. Sadly Peter was among the death victims in the May 27 2006 Earthquake disaster in Java, Indonesia that killed over 5,000 people. He was in Indonesia on a business trip and that was how he met his untimely end. My bank management is yet to know about his death, I knew about it because he was my friend and I am his Account Officer. Peter did not mention any Next of Kin/ Heir when the account was opened, he was not married and no children. Last week my Bank Management requested that Peter should give instructions on what to do
about his funds, if to renew the contract.
I know this will happen and that is why I have been looking for a means to handle the situation, because if my Bank Directors happens to know that Peter is dead and do not have any Heir, they will take the funds for their personal use, so I don't want such to happen. That is why I am seeking your co-operation to present you as the Next of Kin/ Heir to the account, since you are a foreigner and my bank head quarters will release the account to you. There is no risk involved; the transaction will be executed under a legitimate arrangement that will protect us from any breach of law. It is better that we claim the money, than allowing the Bank Directors to take it, they are rich already. I am not a greedy person, so I am suggesting we share the funds in this ratio, 50/50%, equal sharing. Let
me know your mind on this and please do treat this information highly confidential. We shall go over the details once I receive your urgent response. Please Urgently get back to me through this email address as soon as possible:
Have a nice day and God bless. Anticipating your communication.
Regards,
FROM: Husam Al Sayed.
EMAIL: alsayedhusa@hotmail.com
_____________________________________________________________________
Vsetko podstatne z vedy, pocitacov, mobilov aj hier - http://www.TECHsme.sk
^ permalink raw reply
* Re: [PATCH net-next] sock: consistent errqueue errors and signals
From: Willem de Bruijn @ 2014-09-03 19:40 UTC (permalink / raw)
To: Hannes Frederic Sowa; +Cc: Network Development, David Miller
In-Reply-To: <1409746453.14224.14.camel@localhost>
> I just noticed another problem with this approach why I think we cannot
> use it.
>
> In case we generate an error back to the socket locally because
> something (e.g. the packet was too big) in output path, we must not
> update sk->sk_err because we return it immediately to the sender but
> nonetheless must update the error queue.
>
> It seems to me that this patch would report the same error two times to
> the program then.
For instance in __ip_append_data reaching
ip_local_error(sk, EMSGSIZE, ..);
return -EMSGSIZE;
With this patch, where sk->sk_err is set, the error will continuously
be returned on send/recv until the caller reads from the error queue.
A recvmsg MSG_ERRQUEUE will cause the error to be reset immediately.
If socket option IP_RECVERR is set, the process should immediately
read the error queue when a send call fails with EMSGSIZE or any other
relevant error. In that case, the error is not reported more than
once.
The alternative patch does not overwrite sk->sk_err, but results in
this same modified user-visible behavior.
Without the patch, after a send call fails in the above code, the
process can continue calling send/recv normally while ignoring the
error, since all "if (sk->sk_err)" checks fall through. If we have to
treat this as legacy behavior, then neither patch should be applied.
Then, the semantics are that queued errors are non-blocking. In that
case, the only patch needed for consistent semantics is to remove the
sk->sk_err assigment in skb_dequeue_err_skb.
On a related note, when returning an error, returning the errno from
the item on the queue is a confusing signal. Some error codes are the
result of protocol processing and have nothing queued (e.g., EINVAL),
others are due to an queued error (ENOMSG) and some are simply
ambiguous (EMSGSIZE). It is not reasonable to expect processes to
figure out the three sets. One solution would be to dedicate a special
error code to denote "there is a message queued onto sk_error_queue,
read the actual errno from there". This choice only relevant if we
decide to return an error, at all, of course.
^ permalink raw reply
* netfilter: NETFILTER_XT_NAT?
From: Paul Bolle @ 2014-09-03 20:17 UTC (permalink / raw)
To: Pablo Neira Ayuso
Cc: Matteo Croce, Patrick McHardy, Jozsef Kadlecsik, David S. Miller,
netfilter-devel, coreteam, netdev
Hi Pablo,
Your commit 8993cf8edf42 ("netfilter: move NAT Kconfig switches out of
the iptables scope") just landed in linux-next (ie, in next-20140903).
It claims to add NETFILTER_XT_NAT.
That commit does add two select statements for NETFILTER_XT_NAT, and a
Makefile line checking for NETFILTER_XT_NAT. But it does not add the
actual Kconfig symbol NETFILTER_XT_NAT. This is a bit confusing. Do you
know what may have happened here?
Paul Bolle
^ permalink raw reply
* [net-next] l2tp: fix missing line continuation
From: Andy Zhou @ 2014-09-03 20:16 UTC (permalink / raw)
To: davem; +Cc: netdev, Andy Zhou
This syntax error was covered by L2TP_REFCNT_DEBUG not being set by
default.
Signed-off-by: Andy Zhou <azhou@nicira.com>
---
net/l2tp/l2tp_core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index 797c0af..2aa2b6c 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -148,7 +148,7 @@ do { \
atomic_read(&_t->ref_count)); \
l2tp_tunnel_inc_refcount_1(_t); \
} while (0)
-#define l2tp_tunnel_dec_refcount(_t)
+#define l2tp_tunnel_dec_refcount(_t) \
do { \
pr_debug("l2tp_tunnel_dec_refcount: %s:%d %s: cnt=%d\n", \
__func__, __LINE__, (_t)->name, \
--
1.7.9.5
^ permalink raw reply related
* [Patch net-next 00/11] net: fec: imx6sx multiqueue support
From: y @ 2014-09-03 20:34 UTC (permalink / raw)
To: b38611-KZfg59tc24xl57MIdRCFDg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
netdev-u79uwXL29TY76Z2rM5mHXA, lznuaa-Re5JQEeQqe8AvxtiuMwx3w
Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, Frank Li
From: Frank Li <Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
These patches enable i.MX6SX multi queue support.
i.MX6SX support 3 queue and AVB feature.
Frank Li (3):
net:fec: add enet-avb IP support
ARM: Documentation: Update fec dts binding doc
ARM: dts: imx6sx: add multi-queue support enet
Fugang Duan (8):
net:fec: add enet refrence clock for i.MX 6SX chip
net:fec: add enet AVB feature macro define for imx6sx
net:fec: use multiqueue interface to allocate Ethernet device
net:fec: add multiqueue support
net:fec: Disable enet-avb MAC instead of reset MAC
net:fec: Add fsl,imx6sx-fec compatible strings
net:fec: change FEC alignment to 64 bytes for ARM platform
net:fec: remove unnessary memory copy for address alignment in .xmit()
Documentation/devicetree/bindings/net/fsl-fec.txt | 6 +
arch/arm/boot/dts/imx6sx.dtsi | 2 +
drivers/net/ethernet/freescale/fec.h | 151 +++-
drivers/net/ethernet/freescale/fec_main.c | 877 +++++++++++++++-------
4 files changed, 750 insertions(+), 286 deletions(-)
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [Patch net-next 01/11] net:fec: add enet refrence clock for i.MX 6SX chip
From: y @ 2014-09-03 20:34 UTC (permalink / raw)
To: b38611-KZfg59tc24xl57MIdRCFDg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
netdev-u79uwXL29TY76Z2rM5mHXA, lznuaa-Re5JQEeQqe8AvxtiuMwx3w
Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, Fugang Duan, Frank Li
In-Reply-To: <1409776486-1403-1-git-send-email-y>
From: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
i.MX6sx enet has below clocks for user config:
clk_ipg: ipg_clk_s, ipg_clk_mac0_s, 66Mhz
clk_ahb: enet system clock, it is enet AXI clock for imx6sx.
For imx6sx, it alos is the clock source of interrupt coalescing.
The clock range: 200Mhz ~ 266Mhz.
clk_ref: refrence clock for tx and rx. For imx6sx enet RGMII mode,
the refrence clock is 125Mhz coming from internal PLL or external.
In i.MX6sx-arm2 board, the clock is from internal PLL.
clk_ref is optional, depends on board.
clk_enet_out: The clock can be output from internal PLL. It can supply 50Mhz
clock for phy. clk_enet_out is optional, depends on chip and board.
clk_ptp: 1588 ts clock. It is optional, depends on chip.
The patch add clk_ref to distiguish the different clocks.
Signed-off-by: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Signed-off-by: Frank Li <Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---
drivers/net/ethernet/freescale/fec.h | 1 +
drivers/net/ethernet/freescale/fec_main.c | 17 +++++++++++++++++
2 files changed, 18 insertions(+)
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index ee41d98..635772b 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -272,6 +272,7 @@ struct fec_enet_private {
struct clk *clk_ipg;
struct clk *clk_ahb;
+ struct clk *clk_ref;
struct clk *clk_enet_out;
struct clk *clk_ptp;
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 89355a7..c21ecff1 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1621,6 +1621,11 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
}
mutex_unlock(&fep->ptp_clk_mutex);
}
+ if (fep->clk_ref) {
+ ret = clk_prepare_enable(fep->clk_ref);
+ if (ret)
+ goto failed_clk_ref;
+ }
} else {
clk_disable_unprepare(fep->clk_ahb);
clk_disable_unprepare(fep->clk_ipg);
@@ -1632,9 +1637,15 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
fep->ptp_clk_on = false;
mutex_unlock(&fep->ptp_clk_mutex);
}
+ if (fep->clk_ref)
+ clk_disable_unprepare(fep->clk_ref);
}
return 0;
+
+failed_clk_ref:
+ if (fep->clk_ref)
+ clk_disable_unprepare(fep->clk_ref);
failed_clk_ptp:
if (fep->clk_enet_out)
clk_disable_unprepare(fep->clk_enet_out);
@@ -2637,6 +2648,12 @@ fec_probe(struct platform_device *pdev)
fep->ptp_clk_on = false;
mutex_init(&fep->ptp_clk_mutex);
+
+ /* clk_ref is optional, depends on board */
+ fep->clk_ref = devm_clk_get(&pdev->dev, "enet_clk_ref");
+ if (IS_ERR(fep->clk_ref))
+ fep->clk_ref = NULL;
+
fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp");
fep->bufdesc_ex =
pdev->id_entry->driver_data & FEC_QUIRK_HAS_BUFDESC_EX;
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [Patch net-next 02/11] net:fec: add enet AVB feature macro define for imx6sx
From: y @ 2014-09-03 20:34 UTC (permalink / raw)
To: b38611-KZfg59tc24xl57MIdRCFDg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
netdev-u79uwXL29TY76Z2rM5mHXA, lznuaa-Re5JQEeQqe8AvxtiuMwx3w
Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, Fugang Duan, Frank Li
In-Reply-To: <1409776486-1403-1-git-send-email-y>
From: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Add enet AVB feature macro define for imx6sx.
Signed-off-by: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Signed-off-by: Frank Li <Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---
drivers/net/ethernet/freescale/fec_main.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index c21ecff1..ee9f04f 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -104,6 +104,16 @@ static void set_multicast_list(struct net_device *ndev);
* ENET_TDAR[TDAR].
*/
#define FEC_QUIRK_ERR006358 (1 << 7)
+/* ENET IP hw AVB
+ *
+ * i.MX6SX ENET IP add Audio Video Bridging (AVB) feature support.
+ * - Two class indicators on receive with configurable priority
+ * - Two class indicators and line speed timer on transmit allowing
+ * implementation class credit based shapers externally
+ * - Additional DMA registers provisioned to allow managing up to 3
+ * independent rings
+ */
+#define FEC_QUIRK_HAS_AVB (1 << 8)
static struct platform_device_id fec_devtype[] = {
{
@@ -128,6 +138,12 @@ static struct platform_device_id fec_devtype[] = {
.name = "mvf600-fec",
.driver_data = FEC_QUIRK_ENET_MAC,
}, {
+ .name = "imx6sx-fec",
+ .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
+ FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
+ FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358 |
+ FEC_QUIRK_HAS_AVB,
+ }, {
/* sentinel */
}
};
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [Patch net-next 03/11] net:fec: use multiqueue interface to allocate Ethernet device
From: y @ 2014-09-03 20:34 UTC (permalink / raw)
To: b38611-KZfg59tc24xl57MIdRCFDg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
netdev-u79uwXL29TY76Z2rM5mHXA, lznuaa-Re5JQEeQqe8AvxtiuMwx3w
Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, Fugang Duan, Frank Li
In-Reply-To: <1409776486-1403-1-git-send-email-y>
From: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Since i.MX6SX enet-AVB IP support multi queues, so use multi queues
interface to allocate and set up an Ethernet device.
Signed-off-by: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Signed-off-by: Frank Li <Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---
drivers/net/ethernet/freescale/fec.h | 9 ++++++
drivers/net/ethernet/freescale/fec_main.c | 49 ++++++++++++++++++++++++++++++-
2 files changed, 57 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 635772b..f77ed6f 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -233,6 +233,13 @@ struct bufdesc_ex {
/* This device has up to three irqs on some platforms */
#define FEC_IRQ_NUM 3
+/* Maximum number of queues supported
+ * ENET with AVB IP can support up to 3 independent tx queues and rx queues.
+ * User can point the queue number that is less than or equal to 3.
+ */
+#define FEC_ENET_MAX_TX_QS 3
+#define FEC_ENET_MAX_RX_QS 3
+
/* 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
* to keep them that size.
@@ -278,6 +285,8 @@ struct fec_enet_private {
bool ptp_clk_on;
struct mutex ptp_clk_mutex;
+ int num_tx_queues;
+ int num_rx_queues;
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
unsigned char *tx_bounce[TX_RING_SIZE];
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index ee9f04f..00fcadd 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -2573,6 +2573,39 @@ static void fec_reset_phy(struct platform_device *pdev)
#endif /* CONFIG_OF */
static int
+fec_enet_get_queue_num(struct platform_device *pdev, int *num_tx, int *num_rx)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int err;
+
+ if (!np || !of_device_is_available(np))
+ return -ENODEV;
+
+ /* parse the num of tx and rx queues */
+ err = of_property_read_u32(np, "fsl,num_tx_queues", num_tx);
+ err |= of_property_read_u32(np, "fsl,num_rx_queues", num_rx);
+ if (err) {
+ *num_tx = 1;
+ *num_rx = 1;
+ return 0;
+ }
+
+ if (*num_tx < 1 || *num_tx > FEC_ENET_MAX_TX_QS) {
+ dev_err(&pdev->dev, "num_tx(=%d) greater than MAX_TX_QS(=%d)\n",
+ *num_tx, FEC_ENET_MAX_TX_QS);
+ return -EINVAL;
+ }
+
+ if (*num_rx < 1 || *num_rx > FEC_ENET_MAX_RX_QS) {
+ dev_err(&pdev->dev, "num_rx(=%d) greater than MAX_RX_QS(=%d)\n",
+ *num_rx, FEC_ENET_MAX_RX_QS);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
fec_probe(struct platform_device *pdev)
{
struct fec_enet_private *fep;
@@ -2583,13 +2616,23 @@ fec_probe(struct platform_device *pdev)
const struct of_device_id *of_id;
static int dev_id;
struct device_node *np = pdev->dev.of_node, *phy_node;
+ int num_tx_qs = 1;
+ int num_rx_qs = 1;
of_id = of_match_device(fec_dt_ids, &pdev->dev);
if (of_id)
pdev->id_entry = of_id->data;
+ if (pdev->id_entry &&
+ (pdev->id_entry->driver_data & FEC_QUIRK_HAS_AVB)) {
+ ret = fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs);
+ if (ret)
+ return ret;
+ }
+
/* Init network device */
- ndev = alloc_etherdev(sizeof(struct fec_enet_private));
+ ndev = alloc_etherdev_mqs(sizeof(struct fec_enet_private),
+ num_tx_qs, num_rx_qs);
if (!ndev)
return -ENOMEM;
@@ -2598,6 +2641,10 @@ fec_probe(struct platform_device *pdev)
/* setup board info structure */
fep = netdev_priv(ndev);
+ fep->num_rx_queues = num_rx_qs;
+ fep->num_tx_queues = num_tx_qs;
+ netif_set_real_num_rx_queues(ndev, num_rx_qs);
+
#if !defined(CONFIG_M5272)
/* default enable pause frame auto negotiation */
if (pdev->id_entry &&
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [Patch net-next 04/11] net:fec: add multiqueue support
From: y @ 2014-09-03 20:34 UTC (permalink / raw)
To: b38611-KZfg59tc24xl57MIdRCFDg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
netdev-u79uwXL29TY76Z2rM5mHXA, lznuaa-Re5JQEeQqe8AvxtiuMwx3w
Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, Fugang Duan, Frank Li
In-Reply-To: <1409776486-1403-1-git-send-email-y>
From: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Add multiqueue support, which is compatible with previous single queue
driver for FEC/ENET IPs.
By default, the tx/rx queue number is 1, user can config the queue number
at DTS file like this:
fsl,num_tx_queues=<3>;
fsl,num_rx_queues=<3>;
Ethernet multiqueue mechanism can improve performance in SMP system.
For single hw queue, multiqueue can balance cpu loading.
For multi hw queues, multiple cores can process network packets in parallel,
and refer the article for the detail advantage for multiqueue:
http://vger.kernel.org/~davem/davem_nyc09.pdf
Signed-off-by: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Signed-off-by: Frank Li <frank.li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---
drivers/net/ethernet/freescale/fec.h | 108 ++++-
drivers/net/ethernet/freescale/fec_main.c | 730 ++++++++++++++++++++----------
2 files changed, 577 insertions(+), 261 deletions(-)
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index f77ed6f..984eaf2 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -27,8 +27,8 @@
*/
#define FEC_IEVENT 0x004 /* Interrupt event reg */
#define FEC_IMASK 0x008 /* Interrupt mask reg */
-#define FEC_R_DES_ACTIVE 0x010 /* Receive descriptor reg */
-#define FEC_X_DES_ACTIVE 0x014 /* Transmit descriptor reg */
+#define FEC_R_DES_ACTIVE_0 0x010 /* Receive descriptor reg */
+#define FEC_X_DES_ACTIVE_0 0x014 /* Transmit descriptor reg */
#define FEC_ECNTRL 0x024 /* Ethernet control reg */
#define FEC_MII_DATA 0x040 /* MII manage frame reg */
#define FEC_MII_SPEED 0x044 /* MII speed control reg */
@@ -45,14 +45,26 @@
#define FEC_X_WMRK 0x144 /* FIFO transmit water mark */
#define FEC_R_BOUND 0x14c /* FIFO receive bound reg */
#define FEC_R_FSTART 0x150 /* FIFO receive start reg */
-#define FEC_R_DES_START 0x180 /* Receive descriptor ring */
-#define FEC_X_DES_START 0x184 /* Transmit descriptor ring */
+#define FEC_R_DES_START_1 0x160 /* Receive descriptor ring 1 */
+#define FEC_X_DES_START_1 0x164 /* Transmit descriptor ring 1 */
+#define FEC_R_DES_START_2 0x16c /* Receive descriptor ring 2 */
+#define FEC_X_DES_START_2 0x170 /* Transmit descriptor ring 2 */
+#define FEC_R_DES_START_0 0x180 /* Receive descriptor ring */
+#define FEC_X_DES_START_0 0x184 /* Transmit descriptor ring */
#define FEC_R_BUFF_SIZE 0x188 /* Maximum receive buff size */
#define FEC_R_FIFO_RSFL 0x190 /* Receive FIFO section full threshold */
#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_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 */
+#define FEC_DMA_CFG_2 0x1dc /* DMA class Configuration for ring 2 */
+#define FEC_R_DES_ACTIVE_1 0x1e0 /* Rx descriptor active for ring 1 */
+#define FEC_X_DES_ACTIVE_1 0x1e4 /* Tx descriptor active for ring 1 */
+#define FEC_R_DES_ACTIVE_2 0x1e8 /* Rx descriptor active for ring 2 */
+#define FEC_X_DES_ACTIVE_2 0x1ec /* Tx descriptor active for ring 2 */
#define FEC_MIIGSK_CFGR 0x300 /* MIIGSK Configuration reg */
#define FEC_MIIGSK_ENR 0x308 /* MIIGSK Enable reg */
@@ -240,6 +252,36 @@ 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) ? \
+ 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) ? \
+ 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) ? \
+ 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) ? \
+ 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 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_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) : \
+ (IDLE_SLOPE_2 & IDLE_SLOPE_MASK))
+#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))
+#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)
+
/* 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
* to keep them that size.
@@ -263,6 +305,35 @@ struct bufdesc_ex {
#define FLAG_RX_CSUM_ENABLED (BD_ENET_RX_ICE | BD_ENET_RX_PCR)
#define FLAG_RX_CSUM_ERROR (BD_ENET_RX_ICE | BD_ENET_RX_PCR)
+struct fec_enet_priv_tx_q {
+ int index;
+ unsigned char *tx_bounce[TX_RING_SIZE];
+ struct sk_buff *tx_skbuff[TX_RING_SIZE];
+
+ dma_addr_t bd_dma;
+ struct bufdesc *tx_bd_base;
+ uint tx_ring_size;
+
+ unsigned short tx_stop_threshold;
+ unsigned short tx_wake_threshold;
+
+ struct bufdesc *cur_tx;
+ struct bufdesc *dirty_tx;
+ char *tso_hdrs;
+ dma_addr_t tso_hdrs_dma;
+};
+
+struct fec_enet_priv_rx_q {
+ int index;
+ struct sk_buff *rx_skbuff[RX_RING_SIZE];
+
+ dma_addr_t bd_dma;
+ struct bufdesc *rx_bd_base;
+ uint rx_ring_size;
+
+ struct bufdesc *cur_rx;
+};
+
/* The FEC buffer descriptors track the ring buffers. The rx_bd_base and
* tx_bd_base always point to the base of the buffer descriptors. The
* cur_rx and cur_tx point to the currently available buffer.
@@ -289,29 +360,18 @@ struct fec_enet_private {
int num_rx_queues;
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
- unsigned char *tx_bounce[TX_RING_SIZE];
- struct sk_buff *tx_skbuff[TX_RING_SIZE];
- struct sk_buff *rx_skbuff[RX_RING_SIZE];
+ struct fec_enet_priv_tx_q *tx_queue[FEC_ENET_MAX_TX_QS];
+ struct fec_enet_priv_rx_q *rx_queue[FEC_ENET_MAX_RX_QS];
- /* CPM dual port RAM relative addresses */
- dma_addr_t bd_dma;
- /* Address of Rx and Tx buffers */
- struct bufdesc *rx_bd_base;
- struct bufdesc *tx_bd_base;
- /* The next free ring entry */
- struct bufdesc *cur_rx, *cur_tx;
- /* The ring entries to be free()ed */
- struct bufdesc *dirty_tx;
+ unsigned int total_tx_ring_size;
+ unsigned int total_rx_ring_size;
- unsigned short bufdesc_size;
- unsigned short tx_ring_size;
- unsigned short rx_ring_size;
- unsigned short tx_stop_threshold;
- unsigned short tx_wake_threshold;
+ unsigned long work_tx;
+ unsigned long work_rx;
+ unsigned long work_ts;
+ unsigned long work_mdio;
- /* Software TSO */
- char *tso_hdrs;
- dma_addr_t tso_hdrs_dma;
+ unsigned short bufdesc_size;
struct platform_device *pdev;
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 00fcadd..f973a92 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -72,6 +72,8 @@ static void set_multicast_list(struct net_device *ndev);
#define DRIVER_NAME "fec"
+#define FEC_ENET_GET_QUQUE(_x) ((_x == 0) ? 1 : ((_x == 1) ? 2 : 0))
+
/* Pause frame feild and FIFO threshold */
#define FEC_ENET_FCE (1 << 5)
#define FEC_ENET_RSEM_V 0x84
@@ -258,22 +260,26 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
static int mii_cnt;
static inline
-struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp, struct fec_enet_private *fep)
+struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp,
+ struct fec_enet_private *fep,
+ int queue_id)
{
struct bufdesc *new_bd = bdp + 1;
struct bufdesc_ex *ex_new_bd = (struct bufdesc_ex *)bdp + 1;
+ struct fec_enet_priv_tx_q *tx_queue = fep->tx_queue[queue_id];
+ struct fec_enet_priv_rx_q *rx_queue = fep->rx_queue[queue_id];
struct bufdesc_ex *ex_base;
struct bufdesc *base;
int ring_size;
- if (bdp >= fep->tx_bd_base) {
- base = fep->tx_bd_base;
- ring_size = fep->tx_ring_size;
- ex_base = (struct bufdesc_ex *)fep->tx_bd_base;
+ if (bdp >= tx_queue->tx_bd_base) {
+ base = tx_queue->tx_bd_base;
+ ring_size = tx_queue->tx_ring_size;
+ ex_base = (struct bufdesc_ex *)tx_queue->tx_bd_base;
} else {
- base = fep->rx_bd_base;
- ring_size = fep->rx_ring_size;
- ex_base = (struct bufdesc_ex *)fep->rx_bd_base;
+ base = rx_queue->rx_bd_base;
+ ring_size = rx_queue->rx_ring_size;
+ ex_base = (struct bufdesc_ex *)rx_queue->rx_bd_base;
}
if (fep->bufdesc_ex)
@@ -285,22 +291,26 @@ struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp, struct fec_enet_priva
}
static inline
-struct bufdesc *fec_enet_get_prevdesc(struct bufdesc *bdp, struct fec_enet_private *fep)
+struct bufdesc *fec_enet_get_prevdesc(struct bufdesc *bdp,
+ struct fec_enet_private *fep,
+ int queue_id)
{
struct bufdesc *new_bd = bdp - 1;
struct bufdesc_ex *ex_new_bd = (struct bufdesc_ex *)bdp - 1;
+ struct fec_enet_priv_tx_q *tx_queue = fep->tx_queue[queue_id];
+ struct fec_enet_priv_rx_q *rx_queue = fep->rx_queue[queue_id];
struct bufdesc_ex *ex_base;
struct bufdesc *base;
int ring_size;
- if (bdp >= fep->tx_bd_base) {
- base = fep->tx_bd_base;
- ring_size = fep->tx_ring_size;
- ex_base = (struct bufdesc_ex *)fep->tx_bd_base;
+ if (bdp >= tx_queue->tx_bd_base) {
+ base = tx_queue->tx_bd_base;
+ ring_size = tx_queue->tx_ring_size;
+ ex_base = (struct bufdesc_ex *)tx_queue->tx_bd_base;
} else {
- base = fep->rx_bd_base;
- ring_size = fep->rx_ring_size;
- ex_base = (struct bufdesc_ex *)fep->rx_bd_base;
+ base = rx_queue->rx_bd_base;
+ ring_size = rx_queue->rx_ring_size;
+ ex_base = (struct bufdesc_ex *)rx_queue->rx_bd_base;
}
if (fep->bufdesc_ex)
@@ -316,14 +326,15 @@ static int fec_enet_get_bd_index(struct bufdesc *base, struct bufdesc *bdp,
return ((const char *)bdp - (const char *)base) / fep->bufdesc_size;
}
-static int fec_enet_get_free_txdesc_num(struct fec_enet_private *fep)
+static int fec_enet_get_free_txdesc_num(struct fec_enet_private *fep,
+ struct fec_enet_priv_tx_q *txq)
{
int entries;
- entries = ((const char *)fep->dirty_tx -
- (const char *)fep->cur_tx) / fep->bufdesc_size - 1;
+ entries = ((const char *)txq->dirty_tx -
+ (const char *)txq->cur_tx) / fep->bufdesc_size - 1;
- return entries > 0 ? entries : entries + fep->tx_ring_size;
+ return entries > 0 ? entries : entries + txq->tx_ring_size;
}
static void *swap_buffer(void *bufaddr, int len)
@@ -340,22 +351,30 @@ static void *swap_buffer(void *bufaddr, int len)
static void fec_dump(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- struct bufdesc *bdp = fep->tx_bd_base;
- unsigned int index = 0;
+ struct bufdesc *bdp;
+ struct fec_enet_priv_tx_q *txq;
+ int index = 0;
+ int i;
netdev_info(ndev, "TX ring dump\n");
pr_info("Nr SC addr len SKB\n");
- do {
- pr_info("%3u %c%c 0x%04x 0x%08lx %4u %p\n",
- index,
- bdp == fep->cur_tx ? 'S' : ' ',
- bdp == fep->dirty_tx ? 'H' : ' ',
- bdp->cbd_sc, bdp->cbd_bufaddr, bdp->cbd_datlen,
- fep->tx_skbuff[index]);
- bdp = fec_enet_get_nextdesc(bdp, fep);
- index++;
- } while (bdp != fep->tx_bd_base);
+ for (i = 0; i < fep->num_tx_queues; i++) {
+ txq = fep->tx_queue[i];
+ bdp = txq->tx_bd_base;
+ pr_info("Tx Queue %d\n", i);
+
+ do {
+ pr_info("%3u %c%c 0x%04x 0x%08lx %4u %p\n",
+ index,
+ bdp == txq->cur_tx ? 'S' : ' ',
+ bdp == txq->dirty_tx ? 'H' : ' ',
+ bdp->cbd_sc, bdp->cbd_bufaddr, bdp->cbd_datlen,
+ txq->tx_skbuff[index]);
+ bdp = fec_enet_get_nextdesc(bdp, fep, i);
+ index++;
+ } while (bdp != txq->tx_bd_base);
+ }
}
static inline bool is_ipv4_pkt(struct sk_buff *skb)
@@ -381,14 +400,17 @@ fec_enet_clear_csum(struct sk_buff *skb, struct net_device *ndev)
}
static int
-fec_enet_txq_submit_frag_skb(struct sk_buff *skb, struct net_device *ndev)
+fec_enet_txq_submit_frag_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);
- struct bufdesc *bdp = fep->cur_tx;
+ struct bufdesc *bdp = txq->cur_tx;
struct bufdesc_ex *ebdp;
int nr_frags = skb_shinfo(skb)->nr_frags;
+ unsigned short queue = skb_get_queue_mapping(skb);
int frag, frag_len;
unsigned short status;
unsigned int estatus = 0;
@@ -400,7 +422,7 @@ fec_enet_txq_submit_frag_skb(struct sk_buff *skb, struct net_device *ndev)
for (frag = 0; frag < nr_frags; frag++) {
this_frag = &skb_shinfo(skb)->frags[frag];
- bdp = fec_enet_get_nextdesc(bdp, fep);
+ bdp = fec_enet_get_nextdesc(bdp, fep, queue);
ebdp = (struct bufdesc_ex *)bdp;
status = bdp->cbd_sc;
@@ -428,11 +450,11 @@ fec_enet_txq_submit_frag_skb(struct sk_buff *skb, struct net_device *ndev)
bufaddr = page_address(this_frag->page.p) + this_frag->page_offset;
- index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep);
+ index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
if (((unsigned long) bufaddr) & FEC_ALIGNMENT ||
id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
- memcpy(fep->tx_bounce[index], bufaddr, frag_len);
- bufaddr = fep->tx_bounce[index];
+ memcpy(txq->tx_bounce[index], bufaddr, frag_len);
+ bufaddr = txq->tx_bounce[index];
if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
swap_buffer(bufaddr, frag_len);
@@ -452,21 +474,22 @@ fec_enet_txq_submit_frag_skb(struct sk_buff *skb, struct net_device *ndev)
bdp->cbd_sc = status;
}
- fep->cur_tx = bdp;
+ txq->cur_tx = bdp;
return 0;
dma_mapping_error:
- bdp = fep->cur_tx;
+ bdp = txq->cur_tx;
for (i = 0; i < frag; i++) {
- bdp = fec_enet_get_nextdesc(bdp, fep);
+ bdp = fec_enet_get_nextdesc(bdp, fep, queue);
dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
bdp->cbd_datlen, DMA_TO_DEVICE);
}
return NETDEV_TX_OK;
}
-static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
+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 =
@@ -477,12 +500,13 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
dma_addr_t addr;
unsigned short status;
unsigned short buflen;
+ unsigned short queue;
unsigned int estatus = 0;
unsigned int index;
int entries_free;
int ret;
- entries_free = fec_enet_get_free_txdesc_num(fep);
+ entries_free = fec_enet_get_free_txdesc_num(fep, txq);
if (entries_free < MAX_SKB_FRAGS + 1) {
dev_kfree_skb_any(skb);
if (net_ratelimit())
@@ -497,7 +521,7 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
}
/* Fill in a Tx ring entry */
- bdp = fep->cur_tx;
+ bdp = txq->cur_tx;
status = bdp->cbd_sc;
status &= ~BD_ENET_TX_STATS;
@@ -505,11 +529,12 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
bufaddr = skb->data;
buflen = skb_headlen(skb);
- index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep);
+ queue = skb_get_queue_mapping(skb);
+ index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
if (((unsigned long) bufaddr) & FEC_ALIGNMENT ||
id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
- memcpy(fep->tx_bounce[index], skb->data, buflen);
- bufaddr = fep->tx_bounce[index];
+ memcpy(txq->tx_bounce[index], skb->data, buflen);
+ bufaddr = txq->tx_bounce[index];
if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
swap_buffer(bufaddr, buflen);
@@ -525,7 +550,7 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
}
if (nr_frags) {
- ret = fec_enet_txq_submit_frag_skb(skb, ndev);
+ ret = fec_enet_txq_submit_frag_skb(txq, skb, ndev);
if (ret)
return ret;
} else {
@@ -553,10 +578,10 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
ebdp->cbd_esc = estatus;
}
- last_bdp = fep->cur_tx;
- index = fec_enet_get_bd_index(fep->tx_bd_base, last_bdp, fep);
+ last_bdp = txq->cur_tx;
+ index = fec_enet_get_bd_index(txq->tx_bd_base, last_bdp, fep);
/* Save skb pointer */
- fep->tx_skbuff[index] = skb;
+ txq->tx_skbuff[index] = skb;
bdp->cbd_datlen = buflen;
bdp->cbd_bufaddr = addr;
@@ -568,22 +593,23 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
bdp->cbd_sc = status;
/* If this was the last BD in the ring, start at the beginning again. */
- bdp = fec_enet_get_nextdesc(last_bdp, fep);
+ bdp = fec_enet_get_nextdesc(last_bdp, fep, queue);
skb_tx_timestamp(skb);
- fep->cur_tx = bdp;
+ txq->cur_tx = bdp;
/* Trigger transmission start */
- writel(0, fep->hwp + FEC_X_DES_ACTIVE);
+ writel(0, fep->hwp + FEC_X_DES_ACTIVE(queue));
return 0;
}
static int
-fec_enet_txq_put_data_tso(struct sk_buff *skb, struct net_device *ndev,
- struct bufdesc *bdp, int index, char *data,
- int size, bool last_tcp, bool is_last)
+fec_enet_txq_put_data_tso(struct fec_enet_priv_tx_q *txq, struct sk_buff *skb,
+ struct net_device *ndev,
+ struct bufdesc *bdp, int index, char *data,
+ int size, bool last_tcp, bool is_last)
{
struct fec_enet_private *fep = netdev_priv(ndev);
const struct platform_device_id *id_entry =
@@ -600,8 +626,8 @@ fec_enet_txq_put_data_tso(struct sk_buff *skb, struct net_device *ndev,
if (((unsigned long) data) & FEC_ALIGNMENT ||
id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
- memcpy(fep->tx_bounce[index], data, size);
- data = fep->tx_bounce[index];
+ memcpy(txq->tx_bounce[index], data, size);
+ data = txq->tx_bounce[index];
if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
swap_buffer(data, size);
@@ -640,8 +666,9 @@ fec_enet_txq_put_data_tso(struct sk_buff *skb, struct net_device *ndev,
}
static int
-fec_enet_txq_put_hdr_tso(struct sk_buff *skb, struct net_device *ndev,
- struct bufdesc *bdp, int index)
+fec_enet_txq_put_hdr_tso(struct fec_enet_priv_tx_q *txq,
+ struct sk_buff *skb, struct net_device *ndev,
+ struct bufdesc *bdp, int index)
{
struct fec_enet_private *fep = netdev_priv(ndev);
const struct platform_device_id *id_entry =
@@ -657,12 +684,12 @@ fec_enet_txq_put_hdr_tso(struct sk_buff *skb, struct net_device *ndev,
status &= ~BD_ENET_TX_STATS;
status |= (BD_ENET_TX_TC | BD_ENET_TX_READY);
- bufaddr = fep->tso_hdrs + index * TSO_HEADER_SIZE;
- dmabuf = fep->tso_hdrs_dma + index * TSO_HEADER_SIZE;
+ bufaddr = txq->tso_hdrs + index * TSO_HEADER_SIZE;
+ dmabuf = txq->tso_hdrs_dma + index * TSO_HEADER_SIZE;
if (((unsigned long) bufaddr) & FEC_ALIGNMENT ||
id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
- memcpy(fep->tx_bounce[index], skb->data, hdr_len);
- bufaddr = fep->tx_bounce[index];
+ memcpy(txq->tx_bounce[index], skb->data, hdr_len);
+ bufaddr = txq->tx_bounce[index];
if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME)
swap_buffer(bufaddr, hdr_len);
@@ -692,17 +719,20 @@ fec_enet_txq_put_hdr_tso(struct sk_buff *skb, struct net_device *ndev,
return 0;
}
-static int fec_enet_txq_submit_tso(struct sk_buff *skb, struct net_device *ndev)
+static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq,
+ struct sk_buff *skb,
+ struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
int total_len, data_left;
- struct bufdesc *bdp = fep->cur_tx;
+ struct bufdesc *bdp = txq->cur_tx;
+ unsigned short queue = skb_get_queue_mapping(skb);
struct tso_t tso;
unsigned int index = 0;
int ret;
- if (tso_count_descs(skb) >= fec_enet_get_free_txdesc_num(fep)) {
+ if (tso_count_descs(skb) >= fec_enet_get_free_txdesc_num(fep, txq)) {
dev_kfree_skb_any(skb);
if (net_ratelimit())
netdev_err(ndev, "NOT enough BD for TSO!\n");
@@ -722,14 +752,14 @@ static int fec_enet_txq_submit_tso(struct sk_buff *skb, struct net_device *ndev)
while (total_len > 0) {
char *hdr;
- index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep);
+ index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
data_left = min_t(int, skb_shinfo(skb)->gso_size, total_len);
total_len -= data_left;
/* prepare packet headers: MAC + IP + TCP */
- hdr = fep->tso_hdrs + index * TSO_HEADER_SIZE;
+ hdr = txq->tso_hdrs + index * TSO_HEADER_SIZE;
tso_build_hdr(skb, hdr, &tso, data_left, total_len == 0);
- ret = fec_enet_txq_put_hdr_tso(skb, ndev, bdp, index);
+ ret = fec_enet_txq_put_hdr_tso(txq, skb, ndev, bdp, index);
if (ret)
goto err_release;
@@ -737,10 +767,13 @@ static int fec_enet_txq_submit_tso(struct sk_buff *skb, struct net_device *ndev)
int size;
size = min_t(int, tso.size, data_left);
- bdp = fec_enet_get_nextdesc(bdp, fep);
- index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep);
- ret = fec_enet_txq_put_data_tso(skb, ndev, bdp, index, tso.data,
- size, size == data_left,
+ bdp = fec_enet_get_nextdesc(bdp, fep, queue);
+ index = fec_enet_get_bd_index(txq->tx_bd_base,
+ bdp, fep);
+ ret = fec_enet_txq_put_data_tso(txq, skb, ndev,
+ bdp, index,
+ tso.data, size,
+ size == data_left,
total_len == 0);
if (ret)
goto err_release;
@@ -749,17 +782,17 @@ static int fec_enet_txq_submit_tso(struct sk_buff *skb, struct net_device *ndev)
tso_build_data(skb, &tso, size);
}
- bdp = fec_enet_get_nextdesc(bdp, fep);
+ bdp = fec_enet_get_nextdesc(bdp, fep, queue);
}
/* Save skb pointer */
- fep->tx_skbuff[index] = skb;
+ txq->tx_skbuff[index] = skb;
skb_tx_timestamp(skb);
- fep->cur_tx = bdp;
+ txq->cur_tx = bdp;
/* Trigger transmission start */
- writel(0, fep->hwp + FEC_X_DES_ACTIVE);
+ writel(0, fep->hwp + FEC_X_DES_ACTIVE(queue));
return 0;
@@ -773,18 +806,25 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
int entries_free;
+ unsigned short queue;
+ struct fec_enet_priv_tx_q *txq;
+ struct netdev_queue *nq;
int ret;
+ queue = skb_get_queue_mapping(skb);
+ txq = fep->tx_queue[queue];
+ nq = netdev_get_tx_queue(ndev, queue);
+
if (skb_is_gso(skb))
- ret = fec_enet_txq_submit_tso(skb, ndev);
+ ret = fec_enet_txq_submit_tso(txq, skb, ndev);
else
- ret = fec_enet_txq_submit_skb(skb, ndev);
+ ret = fec_enet_txq_submit_skb(txq, skb, ndev);
if (ret)
return ret;
- entries_free = fec_enet_get_free_txdesc_num(fep);
- if (entries_free <= fep->tx_stop_threshold)
- netif_stop_queue(ndev);
+ entries_free = fec_enet_get_free_txdesc_num(fep, txq);
+ if (entries_free <= txq->tx_stop_threshold)
+ netif_tx_stop_queue(nq);
return NETDEV_TX_OK;
}
@@ -794,46 +834,101 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
static void fec_enet_bd_init(struct net_device *dev)
{
struct fec_enet_private *fep = netdev_priv(dev);
+ struct fec_enet_priv_tx_q *tx_queue;
+ struct fec_enet_priv_rx_q *rx_queue;
struct bufdesc *bdp;
- unsigned int i;
+ unsigned int i, j;
/* Initialize the receive buffer descriptors. */
- bdp = fep->rx_bd_base;
- for (i = 0; i < fep->rx_ring_size; i++) {
+ for (i = 0; i < fep->num_rx_queues; i++) {
+ rx_queue = fep->rx_queue[i];
+ bdp = rx_queue->rx_bd_base;
- /* Initialize the BD for every fragment in the page. */
- if (bdp->cbd_bufaddr)
- bdp->cbd_sc = BD_ENET_RX_EMPTY;
- else
- bdp->cbd_sc = 0;
- bdp = fec_enet_get_nextdesc(bdp, fep);
- }
+ for (j = 0; j < rx_queue->rx_ring_size; j++) {
- /* Set the last buffer to wrap */
- bdp = fec_enet_get_prevdesc(bdp, fep);
- bdp->cbd_sc |= BD_SC_WRAP;
+ /* Initialize the BD for every fragment in the page. */
+ if (bdp->cbd_bufaddr)
+ bdp->cbd_sc = BD_ENET_RX_EMPTY;
+ else
+ bdp->cbd_sc = 0;
+ bdp = fec_enet_get_nextdesc(bdp, fep, i);
+ }
- fep->cur_rx = fep->rx_bd_base;
+ /* Set the last buffer to wrap */
+ bdp = fec_enet_get_prevdesc(bdp, fep, i);
+ bdp->cbd_sc |= BD_SC_WRAP;
+
+ rx_queue->cur_rx = rx_queue->rx_bd_base;
+ }
/* ...and the same for transmit */
- bdp = fep->tx_bd_base;
- fep->cur_tx = bdp;
- for (i = 0; i < fep->tx_ring_size; i++) {
-
- /* Initialize the BD for every fragment in the page. */
- bdp->cbd_sc = 0;
- if (fep->tx_skbuff[i]) {
- dev_kfree_skb_any(fep->tx_skbuff[i]);
- fep->tx_skbuff[i] = NULL;
+ for (i = 0; i < fep->num_tx_queues; i++) {
+ tx_queue = fep->tx_queue[i];
+ bdp = tx_queue->tx_bd_base;
+ tx_queue->cur_tx = bdp;
+
+ for (j = 0; j < tx_queue->tx_ring_size; j++) {
+ /* Initialize the BD for every fragment in the page. */
+ bdp->cbd_sc = 0;
+ if (tx_queue->tx_skbuff[j]) {
+ dev_kfree_skb_any(tx_queue->tx_skbuff[j]);
+ tx_queue->tx_skbuff[j] = NULL;
+ }
+ bdp->cbd_bufaddr = 0;
+ bdp = fec_enet_get_nextdesc(bdp, fep, i);
}
- bdp->cbd_bufaddr = 0;
- bdp = fec_enet_get_nextdesc(bdp, fep);
+
+ /* Set the last buffer to wrap */
+ bdp = fec_enet_get_prevdesc(bdp, fep, i);
+ bdp->cbd_sc |= BD_SC_WRAP;
+ tx_queue->dirty_tx = bdp;
+ }
+}
+
+static inline void fec_enet_enable_ring(struct net_device *ndev)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+ struct fec_enet_priv_tx_q *tx_queue;
+ struct fec_enet_priv_rx_q *rx_queue;
+ int i;
+
+ for (i = 0; i < fep->num_rx_queues; i++) {
+ rx_queue = fep->rx_queue[i];
+ writel(rx_queue->bd_dma, fep->hwp + FEC_R_DES_START(i));
+
+ /* enable DMA1/2 */
+ if (i)
+ writel(RCMR_MATCHEN | RCMR_CMP(i),
+ fep->hwp + FEC_RCMR(i));
}
- /* Set the last buffer to wrap */
- bdp = fec_enet_get_prevdesc(bdp, fep);
- bdp->cbd_sc |= BD_SC_WRAP;
- fep->dirty_tx = bdp;
+ for (i = 0; i < fep->num_tx_queues; i++) {
+ tx_queue = fep->tx_queue[i];
+ writel(tx_queue->bd_dma, fep->hwp + FEC_X_DES_START(i));
+
+ /* enable DMA1/2 */
+ if (i)
+ writel(DMA_CLASS_EN | IDLE_SLOPE(i),
+ fep->hwp + FEC_DMA_CFG(i));
+ }
+}
+
+static void fec_enet_reset_skb(struct net_device *ndev)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+ struct fec_enet_priv_tx_q *tx_queue;
+ int i, j;
+
+ for (i = 0; i < fep->num_tx_queues; i++) {
+ tx_queue = fep->tx_queue[i];
+
+ for (j = 0; j < tx_queue->tx_ring_size; j++) {
+ if (tx_queue->tx_skbuff[j]) {
+ dev_kfree_skb_any(tx_queue->tx_skbuff[j]);
+ tx_queue->tx_skbuff[j] = NULL;
+ }
+ }
+ }
}
/*
@@ -847,11 +942,11 @@ 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);
- int i;
u32 val;
u32 temp_mac[2];
u32 rcntl = OPT_FRAME_SIZE | 0x04;
u32 ecntl = 0x2; /* ETHEREN */
+ int i;
/* Whack a reset. We should wait for this. */
writel(1, fep->hwp + FEC_ECNTRL);
@@ -876,21 +971,10 @@ fec_restart(struct net_device *ndev)
fec_enet_bd_init(ndev);
/* Set receive and transmit descriptor base. */
- writel(fep->bd_dma, fep->hwp + FEC_R_DES_START);
- if (fep->bufdesc_ex)
- writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc_ex)
- * fep->rx_ring_size, fep->hwp + FEC_X_DES_START);
- else
- writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc)
- * fep->rx_ring_size, fep->hwp + FEC_X_DES_START);
-
+ fec_enet_enable_ring(ndev);
- for (i = 0; i <= TX_RING_MOD_MASK; i++) {
- if (fep->tx_skbuff[i]) {
- dev_kfree_skb_any(fep->tx_skbuff[i]);
- fep->tx_skbuff[i] = NULL;
- }
- }
+ /* Reset tx SKB buffers. */
+ fec_enet_reset_skb(ndev);
/* Enable MII mode */
if (fep->full_duplex == DUPLEX_FULL) {
@@ -1012,7 +1096,8 @@ fec_restart(struct net_device *ndev)
/* And last, enable the transmit and receive processing */
writel(ecntl, fep->hwp + FEC_ECNTRL);
- writel(0, fep->hwp + FEC_R_DES_ACTIVE);
+ for (i = 0; i < fep->num_rx_queues; i++)
+ writel(0, fep->hwp + FEC_R_DES_ACTIVE(i));
if (fep->bufdesc_ex)
fec_ptp_start_cyclecounter(ndev);
@@ -1097,37 +1182,45 @@ fec_enet_hwtstamp(struct fec_enet_private *fep, unsigned ts,
}
static void
-fec_enet_tx(struct net_device *ndev)
+fec_enet_tx_queue(struct net_device *ndev, u16 queue_id)
{
struct fec_enet_private *fep;
struct bufdesc *bdp;
unsigned short status;
struct sk_buff *skb;
+ struct fec_enet_priv_tx_q *txq;
+ struct netdev_queue *nq;
int index = 0;
int entries_free;
fep = netdev_priv(ndev);
- bdp = fep->dirty_tx;
+ queue_id = FEC_ENET_GET_QUQUE(queue_id);
+
+ txq = fep->tx_queue[queue_id];
/* get next bdp of dirty_tx */
- bdp = fec_enet_get_nextdesc(bdp, fep);
+ nq = netdev_get_tx_queue(ndev, queue_id);
+ bdp = txq->dirty_tx;
+
+ /* get next bdp of dirty_tx */
+ bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) {
/* current queue is empty */
- if (bdp == fep->cur_tx)
+ if (bdp == txq->cur_tx)
break;
- index = fec_enet_get_bd_index(fep->tx_bd_base, bdp, fep);
+ index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
- skb = fep->tx_skbuff[index];
- fep->tx_skbuff[index] = NULL;
- if (!IS_TSO_HEADER(fep, bdp->cbd_bufaddr))
+ skb = txq->tx_skbuff[index];
+ txq->tx_skbuff[index] = NULL;
+ if (!IS_TSO_HEADER(txq, bdp->cbd_bufaddr))
dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
bdp->cbd_datlen, DMA_TO_DEVICE);
bdp->cbd_bufaddr = 0;
if (!skb) {
- bdp = fec_enet_get_nextdesc(bdp, fep);
+ bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
continue;
}
@@ -1169,23 +1262,37 @@ fec_enet_tx(struct net_device *ndev)
/* Free the sk buffer associated with this last transmit */
dev_kfree_skb_any(skb);
- fep->dirty_tx = bdp;
+ txq->dirty_tx = bdp;
/* Update pointer to next buffer descriptor to be transmitted */
- bdp = fec_enet_get_nextdesc(bdp, fep);
+ bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
/* Since we have freed up a buffer, the ring is no longer full
*/
if (netif_queue_stopped(ndev)) {
- entries_free = fec_enet_get_free_txdesc_num(fep);
- if (entries_free >= fep->tx_wake_threshold)
- netif_wake_queue(ndev);
+ entries_free = fec_enet_get_free_txdesc_num(fep, txq);
+ if (entries_free >= txq->tx_wake_threshold)
+ netif_tx_wake_queue(nq);
}
}
/* ERR006538: Keep the transmitter going */
- if (bdp != fep->cur_tx && readl(fep->hwp + FEC_X_DES_ACTIVE) == 0)
- writel(0, fep->hwp + FEC_X_DES_ACTIVE);
+ if (bdp != txq->cur_tx &&
+ readl(fep->hwp + FEC_X_DES_ACTIVE(queue_id)) == 0)
+ writel(0, fep->hwp + FEC_X_DES_ACTIVE(queue_id));
+}
+
+static void
+fec_enet_tx(struct net_device *ndev)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+ u16 queue_id;
+ /* First process class A queue, then Class B and Best Effort queue */
+ for_each_set_bit(queue_id, &fep->work_tx, FEC_ENET_MAX_TX_QS) {
+ clear_bit(queue_id, &fep->work_tx);
+ fec_enet_tx_queue(ndev, queue_id);
+ }
+ return;
}
/* During a receive, the cur_rx points to the current incoming buffer.
@@ -1194,11 +1301,12 @@ fec_enet_tx(struct net_device *ndev)
* effectively tossing the packet.
*/
static int
-fec_enet_rx(struct net_device *ndev, int budget)
+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;
struct sk_buff *skb;
@@ -1213,11 +1321,13 @@ fec_enet_rx(struct net_device *ndev, int budget)
#ifdef CONFIG_M532x
flush_cache_all();
#endif
+ queue_id = FEC_ENET_GET_QUQUE(queue_id);
+ rxq = fep->rx_queue[queue_id];
/* First, grab all of the stats for the incoming packet.
* These get messed up if we get called due to a busy condition.
*/
- bdp = fep->cur_rx;
+ bdp = rxq->cur_rx;
while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
@@ -1231,7 +1341,6 @@ fec_enet_rx(struct net_device *ndev, int budget)
if ((status & BD_ENET_RX_LAST) == 0)
netdev_err(ndev, "rcv is not +last\n");
- writel(FEC_ENET_RXF, fep->hwp + FEC_IEVENT);
/* Check for errors. */
if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
@@ -1264,8 +1373,8 @@ fec_enet_rx(struct net_device *ndev, int budget)
pkt_len = bdp->cbd_datlen;
ndev->stats.rx_bytes += pkt_len;
- index = fec_enet_get_bd_index(fep->rx_bd_base, bdp, fep);
- data = fep->rx_skbuff[index]->data;
+ index = fec_enet_get_bd_index(rxq->rx_bd_base, bdp, fep);
+ data = rxq->rx_skbuff[index]->data;
dma_sync_single_for_cpu(&fep->pdev->dev, bdp->cbd_bufaddr,
FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
@@ -1280,7 +1389,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
/* If this is a VLAN packet remove the VLAN Tag */
vlan_packet_rcvd = false;
if ((ndev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
- fep->bufdesc_ex && (ebdp->cbd_esc & BD_ENET_RX_VLAN)) {
+ fep->bufdesc_ex && (ebdp->cbd_esc & BD_ENET_RX_VLAN)) {
/* Push and remove the vlan tag */
struct vlan_hdr *vlan_header =
(struct vlan_hdr *) (data + ETH_HLEN);
@@ -1308,7 +1417,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
skb_copy_to_linear_data(skb, data, (2 * ETH_ALEN));
if (vlan_packet_rcvd)
payload_offset = (2 * ETH_ALEN) + VLAN_HLEN;
- skb_copy_to_linear_data_offset(skb, (2 * ETH_ALEN),
+ skb_copy_to_linear_data_offset(skb, (2 * ETH_ALEN),
data + payload_offset,
pkt_len - 4 - (2 * ETH_ALEN));
@@ -1357,19 +1466,48 @@ rx_processing_done:
}
/* Update BD pointer to next entry */
- bdp = fec_enet_get_nextdesc(bdp, fep);
+ bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
/* Doing this here will keep the FEC running while we process
* incoming frames. On a heavily loaded network, we should be
* able to keep up at the expense of system resources.
*/
- writel(0, fep->hwp + FEC_R_DES_ACTIVE);
+ writel(0, fep->hwp + FEC_R_DES_ACTIVE(queue_id));
}
- fep->cur_rx = bdp;
+ rxq->cur_rx = bdp;
+ return pkt_received;
+}
+static int
+fec_enet_rx(struct net_device *ndev, int budget)
+{
+ int pkt_received = 0;
+ u16 queue_id;
+ struct fec_enet_private *fep = netdev_priv(ndev);
+
+ for_each_set_bit(queue_id, &fep->work_rx, FEC_ENET_MAX_RX_QS) {
+ clear_bit(queue_id, &fep->work_rx);
+ pkt_received += fec_enet_rx_queue(ndev,
+ budget - pkt_received, queue_id);
+ }
return pkt_received;
}
+static bool
+fec_enet_collect_events(struct fec_enet_private *fep, uint int_events)
+{
+ if (int_events == 0)
+ return false;
+
+ if (int_events & FEC_ENET_RXF)
+ fep->work_rx |= (1 << 2);
+
+ if (int_events & FEC_ENET_TXF)
+ fep->work_tx |= (1 << 2);
+
+ return true;
+}
+
static irqreturn_t
fec_enet_interrupt(int irq, void *dev_id)
{
@@ -1381,6 +1519,7 @@ fec_enet_interrupt(int irq, void *dev_id)
int_events = readl(fep->hwp + FEC_IEVENT);
writel(int_events & ~napi_mask, fep->hwp + FEC_IEVENT);
+ fec_enet_collect_events(fep, int_events);
if (int_events & napi_mask) {
ret = IRQ_HANDLED;
@@ -2129,93 +2268,117 @@ static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
static void fec_enet_free_buffers(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- unsigned int i;
+ struct fec_enet_priv_tx_q *tx_queue;
+ struct fec_enet_priv_rx_q *rx_queue;
+ unsigned int i, j;
struct sk_buff *skb;
struct bufdesc *bdp;
- bdp = fep->rx_bd_base;
- for (i = 0; i < fep->rx_ring_size; i++) {
- skb = fep->rx_skbuff[i];
- fep->rx_skbuff[i] = NULL;
- if (skb) {
- dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
- FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
- dev_kfree_skb(skb);
+ for (j = 0; j < fep->num_rx_queues; j++) {
+ rx_queue = fep->rx_queue[j];
+ bdp = rx_queue->rx_bd_base;
+ for (i = 0; i < rx_queue->rx_ring_size; i++) {
+ skb = rx_queue->rx_skbuff[i];
+ rx_queue->rx_skbuff[i] = NULL;
+ if (skb) {
+ dma_unmap_single(&fep->pdev->dev,
+ bdp->cbd_bufaddr,
+ FEC_ENET_RX_FRSIZE,
+ DMA_FROM_DEVICE);
+ dev_kfree_skb(skb);
+ }
+ bdp = fec_enet_get_nextdesc(bdp, fep, j);
}
- bdp = fec_enet_get_nextdesc(bdp, fep);
}
- bdp = fep->tx_bd_base;
- for (i = 0; i < fep->tx_ring_size; i++) {
- kfree(fep->tx_bounce[i]);
- fep->tx_bounce[i] = NULL;
- skb = fep->tx_skbuff[i];
- fep->tx_skbuff[i] = NULL;
- dev_kfree_skb(skb);
+ for (j = 0; j < fep->num_tx_queues; j++) {
+ tx_queue = fep->tx_queue[j];
+ bdp = tx_queue->tx_bd_base;
+ for (i = 0; i < tx_queue->tx_ring_size; i++) {
+ kfree(tx_queue->tx_bounce[i]);
+ tx_queue->tx_bounce[i] = NULL;
+ skb = tx_queue->tx_skbuff[i];
+ tx_queue->tx_skbuff[i] = NULL;
+ dev_kfree_skb(skb);
+ }
}
}
static int fec_enet_alloc_buffers(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- unsigned int i;
+ struct fec_enet_priv_tx_q *tx_queue;
+ struct fec_enet_priv_rx_q *rx_queue;
+ unsigned int i, j;
struct sk_buff *skb;
struct bufdesc *bdp;
- bdp = fep->rx_bd_base;
- for (i = 0; i < fep->rx_ring_size; i++) {
- dma_addr_t addr;
+ for (j = 0; j < fep->num_rx_queues; j++) {
+ rx_queue = fep->rx_queue[j];
+ bdp = rx_queue->rx_bd_base;
+ for (i = 0; i < rx_queue->rx_ring_size; i++) {
+ dma_addr_t addr;
+
+ skb = netdev_alloc_skb(ndev, FEC_ENET_RX_FRSIZE);
+ if (!skb)
+ goto err_alloc;
+
+ addr = dma_map_single(&fep->pdev->dev, skb->data,
+ FEC_ENET_RX_FRSIZE,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(&fep->pdev->dev, addr)) {
+ dev_kfree_skb(skb);
+ if (net_ratelimit())
+ netdev_err(ndev, "Rx DMA memory map failed\n");
+ goto err_alloc;
+ }
- skb = netdev_alloc_skb(ndev, FEC_ENET_RX_FRSIZE);
- if (!skb)
- goto err_alloc;
+ rx_queue->rx_skbuff[i] = skb;
+ bdp->cbd_bufaddr = addr;
+ bdp->cbd_sc = BD_ENET_RX_EMPTY;
- addr = dma_map_single(&fep->pdev->dev, skb->data,
- FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
- if (dma_mapping_error(&fep->pdev->dev, addr)) {
- dev_kfree_skb(skb);
- if (net_ratelimit())
- netdev_err(ndev, "Rx DMA memory map failed\n");
- goto err_alloc;
- }
+ if (fep->bufdesc_ex) {
+ struct bufdesc_ex *ebdp;
- fep->rx_skbuff[i] = skb;
- bdp->cbd_bufaddr = addr;
- bdp->cbd_sc = BD_ENET_RX_EMPTY;
+ ebdp = (struct bufdesc_ex *)bdp;
+ ebdp->cbd_esc = BD_ENET_RX_INT;
+ }
- if (fep->bufdesc_ex) {
- struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
- ebdp->cbd_esc = BD_ENET_RX_INT;
+ bdp = fec_enet_get_nextdesc(bdp, fep, j);
}
- bdp = fec_enet_get_nextdesc(bdp, fep);
+ /* Set the last buffer to wrap. */
+ bdp = fec_enet_get_prevdesc(bdp, fep, j);
+ bdp->cbd_sc |= BD_SC_WRAP;
}
- /* Set the last buffer to wrap. */
- bdp = fec_enet_get_prevdesc(bdp, fep);
- bdp->cbd_sc |= BD_SC_WRAP;
+ for (j = 0; j < fep->num_tx_queues; j++) {
+ tx_queue = fep->tx_queue[j];
+ bdp = tx_queue->tx_bd_base;
- bdp = fep->tx_bd_base;
- for (i = 0; i < fep->tx_ring_size; i++) {
- fep->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE, GFP_KERNEL);
- if (!fep->tx_bounce[i])
- goto err_alloc;
+ for (i = 0; i < tx_queue->tx_ring_size; i++) {
+ tx_queue->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE,
+ GFP_KERNEL);
+ if (!tx_queue->tx_bounce[i])
+ goto err_alloc;
- bdp->cbd_sc = 0;
- bdp->cbd_bufaddr = 0;
+ bdp->cbd_sc = 0;
+ bdp->cbd_bufaddr = 0;
- if (fep->bufdesc_ex) {
- struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
- ebdp->cbd_esc = BD_ENET_TX_INT;
- }
+ if (fep->bufdesc_ex) {
+ struct bufdesc_ex *ebdp;
- bdp = fec_enet_get_nextdesc(bdp, fep);
- }
+ ebdp = (struct bufdesc_ex *)bdp;
+ ebdp->cbd_esc = BD_ENET_TX_INT;
+ }
- /* Set the last buffer to wrap. */
- bdp = fec_enet_get_prevdesc(bdp, fep);
- bdp->cbd_sc |= BD_SC_WRAP;
+ bdp = fec_enet_get_nextdesc(bdp, fep, j);
+ }
+ /* Set the last buffer to wrap. */
+ bdp = fec_enet_get_prevdesc(bdp, fep, j);
+ bdp->cbd_sc |= BD_SC_WRAP;
+ }
return 0;
err_alloc:
@@ -2252,7 +2415,8 @@ fec_enet_open(struct net_device *ndev)
fec_restart(ndev);
napi_enable(&fep->napi);
phy_start(fep->phy_dev);
- netif_start_queue(ndev);
+ netif_tx_start_all_queues(ndev);
+
return 0;
}
@@ -2426,7 +2590,7 @@ static int fec_set_features(struct net_device *netdev,
/* Resume the device after updates */
if (netif_running(netdev) && changed & FEATURES_NEED_QUIESCE) {
fec_restart(netdev);
- netif_wake_queue(netdev);
+ netif_tx_wake_all_queues(netdev);
netif_tx_unlock_bh(netdev);
napi_enable(&fep->napi);
}
@@ -2434,10 +2598,17 @@ static int fec_set_features(struct net_device *netdev,
return 0;
}
+u16 fec_enet_select_queue(struct net_device *ndev, struct sk_buff *skb,
+ void *accel_priv, select_queue_fallback_t fallback)
+{
+ return skb_tx_hash(ndev, skb);
+}
+
static const struct net_device_ops fec_netdev_ops = {
.ndo_open = fec_enet_open,
.ndo_stop = fec_enet_close,
.ndo_start_xmit = fec_enet_start_xmit,
+ .ndo_select_queue = fec_enet_select_queue,
.ndo_set_rx_mode = set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
@@ -2450,6 +2621,76 @@ static const struct net_device_ops fec_netdev_ops = {
.ndo_set_features = fec_set_features,
};
+static void fec_enet_free_queue(struct net_device *ndev)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+ int i;
+
+ for (i = 0; i < fep->num_tx_queues; i++)
+ if (fep->tx_queue[i] && fep->tx_queue[i]->tso_hdrs)
+ dma_free_coherent(NULL,
+ fep->tx_queue[i]->tx_ring_size * TSO_HEADER_SIZE,
+ fep->tx_queue[i]->tso_hdrs,
+ fep->tx_queue[i]->tso_hdrs_dma);
+
+ for (i = 0; i < fep->num_rx_queues; i++)
+ if (fep->rx_queue[i])
+ kfree(fep->rx_queue[i]);
+
+ for (i = 0; i < fep->num_tx_queues; i++)
+ if (fep->tx_queue[i])
+ kfree(fep->tx_queue[i]);
+}
+
+static int fec_enet_alloc_queue(struct net_device *ndev)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+ int i;
+ int ret = 0;
+ struct fec_enet_priv_tx_q *txq;
+
+ for (i = 0; i < fep->num_tx_queues; i++) {
+ txq = kzalloc(sizeof(*txq), GFP_KERNEL);
+ if (!txq) {
+ ret = -ENOMEM;
+ goto alloc_failed;
+ }
+
+ fep->tx_queue[i] = txq;
+ txq->tx_ring_size = TX_RING_SIZE;
+ fep->total_tx_ring_size += fep->tx_queue[i]->tx_ring_size;
+
+ txq->tx_stop_threshold = FEC_MAX_SKB_DESCS;
+ txq->tx_wake_threshold =
+ (txq->tx_ring_size - txq->tx_stop_threshold) / 2;
+
+ txq->tso_hdrs = dma_alloc_coherent(NULL,
+ txq->tx_ring_size * TSO_HEADER_SIZE,
+ &txq->tso_hdrs_dma,
+ GFP_KERNEL);
+ if (!txq->tso_hdrs) {
+ ret = -ENOMEM;
+ goto alloc_failed;
+ }
+ }
+
+ for (i = 0; i < fep->num_rx_queues; i++) {
+ fep->rx_queue[i] = kzalloc(sizeof(*fep->rx_queue[i]),
+ GFP_KERNEL);
+ if (!fep->rx_queue[i]) {
+ ret = -ENOMEM;
+ goto alloc_failed;
+ }
+
+ fep->rx_queue[i]->rx_ring_size = RX_RING_SIZE;
+ fep->total_rx_ring_size += fep->rx_queue[i]->rx_ring_size;
+ }
+ return ret;
+
+alloc_failed:
+ fec_enet_free_queue(ndev);
+ return ret;
+}
/*
* XXX: We need to clean up on failure exits here.
*
@@ -2459,37 +2700,60 @@ 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 *tx_queue;
+ struct fec_enet_priv_rx_q *rx_queue;
struct bufdesc *cbd_base;
+ dma_addr_t bd_dma;
int bd_size;
+ int i;
- /* init the tx & rx ring size */
- fep->tx_ring_size = TX_RING_SIZE;
- fep->rx_ring_size = RX_RING_SIZE;
-
- fep->tx_stop_threshold = FEC_MAX_SKB_DESCS;
- fep->tx_wake_threshold = (fep->tx_ring_size - fep->tx_stop_threshold) / 2;
+ fec_enet_alloc_queue(ndev);
if (fep->bufdesc_ex)
fep->bufdesc_size = sizeof(struct bufdesc_ex);
else
fep->bufdesc_size = sizeof(struct bufdesc);
- bd_size = (fep->tx_ring_size + fep->rx_ring_size) *
+ bd_size = (fep->total_tx_ring_size + fep->total_rx_ring_size) *
fep->bufdesc_size;
/* Allocate memory for buffer descriptors. */
- cbd_base = dma_alloc_coherent(NULL, bd_size, &fep->bd_dma,
+ cbd_base = dma_alloc_coherent(NULL, bd_size, &bd_dma,
GFP_KERNEL);
if (!cbd_base)
return -ENOMEM;
- fep->tso_hdrs = dma_alloc_coherent(NULL, fep->tx_ring_size * TSO_HEADER_SIZE,
- &fep->tso_hdrs_dma, GFP_KERNEL);
- if (!fep->tso_hdrs) {
- dma_free_coherent(NULL, bd_size, cbd_base, fep->bd_dma);
- return -ENOMEM;
+ memset(cbd_base, 0, bd_size);
+
+ for (i = 0; i < fep->num_rx_queues; i++) {
+ rx_queue = fep->rx_queue[i];
+ rx_queue->index = i;
+ rx_queue->rx_bd_base = (struct bufdesc *)cbd_base;
+ rx_queue->bd_dma = bd_dma;
+ if (fep->bufdesc_ex) {
+ bd_dma += sizeof(struct bufdesc_ex) * rx_queue->rx_ring_size;
+ cbd_base = (struct bufdesc *)
+ (((struct bufdesc_ex *)cbd_base) + rx_queue->rx_ring_size);
+ } else {
+ bd_dma += sizeof(struct bufdesc) * rx_queue->rx_ring_size;
+ cbd_base += rx_queue->rx_ring_size;
+ }
+ }
+
+ for (i = 0; i < fep->num_tx_queues; i++) {
+ tx_queue = fep->tx_queue[i];
+ tx_queue->index = i;
+ tx_queue->tx_bd_base = (struct bufdesc *)cbd_base;
+ tx_queue->bd_dma = bd_dma;
+ if (fep->bufdesc_ex) {
+ bd_dma += sizeof(struct bufdesc_ex) * tx_queue->tx_ring_size;
+ cbd_base = (struct bufdesc *)
+ (((struct bufdesc_ex *)cbd_base) + tx_queue->tx_ring_size);
+ } else {
+ bd_dma += sizeof(struct bufdesc) * tx_queue->tx_ring_size;
+ cbd_base += tx_queue->tx_ring_size;
+ }
}
- memset(cbd_base, 0, PAGE_SIZE);
fep->netdev = ndev;
@@ -2498,14 +2762,6 @@ static int fec_enet_init(struct net_device *ndev)
/* make sure MAC we just acquired is programmed into the hw */
fec_set_mac_address(ndev, NULL);
- /* Set receive and transmit descriptor base. */
- fep->rx_bd_base = cbd_base;
- if (fep->bufdesc_ex)
- fep->tx_bd_base = (struct bufdesc *)
- (((struct bufdesc_ex *)cbd_base) + fep->rx_ring_size);
- else
- fep->tx_bd_base = cbd_base + fep->rx_ring_size;
-
/* The FEC Ethernet specific entries in the device structure */
ndev->watchdog_timeo = TX_TIMEOUT;
ndev->netdev_ops = &fec_netdev_ops;
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [Patch net-next 05/11] net:fec: Disable enet-avb MAC instead of reset MAC
From: y @ 2014-09-03 20:34 UTC (permalink / raw)
To: b38611-KZfg59tc24xl57MIdRCFDg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
netdev-u79uwXL29TY76Z2rM5mHXA, lznuaa-Re5JQEeQqe8AvxtiuMwx3w
Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, Fugang Duan, Frank Li
In-Reply-To: <1409776486-1403-1-git-send-email-y>
From: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
For i.MX6SX enet use AXI bus, reset MAC will make system bus dead
if ENET-AXI bus has pending access (AHB bus should not have such issue).
So, disable enet with AVB MAC instead of reset MAC itself.
Signed-off-by: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Signed-off-by: Frank Li <Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---
drivers/net/ethernet/freescale/fec_main.c | 26 ++++++++++++++++++++------
1 file changed, 20 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index f973a92..5dab6a6 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -948,9 +948,16 @@ fec_restart(struct net_device *ndev)
u32 ecntl = 0x2; /* ETHEREN */
int i;
- /* Whack a reset. We should wait for this. */
- writel(1, fep->hwp + FEC_ECNTRL);
- udelay(10);
+ /* Whack a reset. We should wait for this.
+ * 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) {
+ writel(0, fep->hwp + FEC_ECNTRL);
+ } else {
+ writel(1, fep->hwp + FEC_ECNTRL);
+ udelay(10);
+ }
/*
* enet-mac reset will reset mac address registers too,
@@ -1122,9 +1129,16 @@ fec_stop(struct net_device *ndev)
netdev_err(ndev, "Graceful transmit stop did not complete!\n");
}
- /* Whack a reset. We should wait for this. */
- writel(1, fep->hwp + FEC_ECNTRL);
- udelay(10);
+ /* Whack a reset. We should wait for this.
+ * 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) {
+ writel(0, fep->hwp + FEC_ECNTRL);
+ } else {
+ writel(1, fep->hwp + FEC_ECNTRL);
+ udelay(10);
+ }
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [Patch net-next 06/11] net:fec: add enet-avb IP support
From: y @ 2014-09-03 20:34 UTC (permalink / raw)
To: b38611-KZfg59tc24xl57MIdRCFDg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
netdev-u79uwXL29TY76Z2rM5mHXA, lznuaa-Re5JQEeQqe8AvxtiuMwx3w
Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, Frank Li, Fugang Duan
In-Reply-To: <1409776486-1403-1-git-send-email-y>
From: Frank Li <Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
i.MX6SX Enet-AVB support 3 tx queues, 3 rx queues.
For tx queues: ring 0 -> best effort
ring 1 -> Class A
ring 2 -> Class B
For rx queues:
ring 0 -> best effort
ring 1 -> receive VLAN packet with classification match
ring 2 -> receive VLAN packet with classification match
Add enet-avb IP multiqueue support for the driver.
Signed-off-by: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Signed-off-by: Frank Li <Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---
drivers/net/ethernet/freescale/fec.h | 33 +++++++++++++++++++++++++++
drivers/net/ethernet/freescale/fec_main.c | 38 +++++++++++++++----------------
2 files changed, 52 insertions(+), 19 deletions(-)
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 984eaf2..16989bc 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -38,6 +38,12 @@
#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_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 */
#define FEC_HASH_TABLE_HIGH 0x118 /* High 32bits hash table */
#define FEC_HASH_TABLE_LOW 0x11c /* Low 32bits hash table */
#define FEC_GRP_HASH_TABLE_HIGH 0x120 /* High 32bits hash table */
@@ -65,6 +71,7 @@
#define FEC_X_DES_ACTIVE_1 0x1e4 /* Tx descriptor active for ring 1 */
#define FEC_R_DES_ACTIVE_2 0x1e8 /* Rx descriptor active for ring 2 */
#define FEC_X_DES_ACTIVE_2 0x1ec /* Tx descriptor active for ring 2 */
+#define FEC_QOS_SCHEME 0x1f0 /* Set multi queues Qos scheme */
#define FEC_MIIGSK_CFGR 0x300 /* MIIGSK Configuration reg */
#define FEC_MIIGSK_ENR 0x308 /* MIIGSK Enable reg */
@@ -305,6 +312,32 @@ struct bufdesc_ex {
#define FLAG_RX_CSUM_ENABLED (BD_ENET_RX_ICE | BD_ENET_RX_PCR)
#define FLAG_RX_CSUM_ERROR (BD_ENET_RX_ICE | BD_ENET_RX_PCR)
+/* Interrupt events/masks. */
+#define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */
+#define FEC_ENET_BABR ((uint)0x40000000) /* Babbling receiver */
+#define FEC_ENET_BABT ((uint)0x20000000) /* Babbling transmitter */
+#define FEC_ENET_GRA ((uint)0x10000000) /* Graceful stop complete */
+#define FEC_ENET_TXF_0 ((uint)0x08000000) /* Full frame transmitted */
+#define FEC_ENET_TXF_1 ((uint)0x00000008) /* Full frame transmitted */
+#define FEC_ENET_TXF_2 ((uint)0x00000080) /* Full frame transmitted */
+#define FEC_ENET_TXB ((uint)0x04000000) /* A buffer was transmitted */
+#define FEC_ENET_RXF_0 ((uint)0x02000000) /* Full frame received */
+#define FEC_ENET_RXF_1 ((uint)0x00000002) /* Full frame received */
+#define FEC_ENET_RXF_2 ((uint)0x00000020) /* Full frame received */
+#define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */
+#define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */
+#define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */
+#define FEC_ENET_TXF (FEC_ENET_TXF_0 | FEC_ENET_TXF_1 | FEC_ENET_TXF_2)
+#define FEC_ENET_RXF (FEC_ENET_RXF_0 | FEC_ENET_RXF_1 | FEC_ENET_RXF_2)
+#define FEC_ENET_TS_AVAIL ((uint)0x00010000)
+#define FEC_ENET_TS_TIMER ((uint)0x00008000)
+
+#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII | FEC_ENET_TS_TIMER)
+#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
+
+#define FEC_VLAN_TAG_LEN 0x04
+#define FEC_ETHTYPE_LEN 0x02
+
struct fec_enet_priv_tx_q {
int index;
unsigned char *tx_bounce[TX_RING_SIZE];
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 5dab6a6..6aab64b 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -193,21 +193,6 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
#endif
#endif /* CONFIG_M5272 */
-/* Interrupt events/masks. */
-#define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */
-#define FEC_ENET_BABR ((uint)0x40000000) /* Babbling receiver */
-#define FEC_ENET_BABT ((uint)0x20000000) /* Babbling transmitter */
-#define FEC_ENET_GRA ((uint)0x10000000) /* Graceful stop complete */
-#define FEC_ENET_TXF ((uint)0x08000000) /* Full frame transmitted */
-#define FEC_ENET_TXB ((uint)0x04000000) /* A buffer was transmitted */
-#define FEC_ENET_RXF ((uint)0x02000000) /* Full frame received */
-#define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */
-#define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */
-#define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */
-
-#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII)
-#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
-
/* The FEC stores dest/src/type/vlan, data, and checksum for receive packets.
*/
#define PKT_MAXBUF_SIZE 1522
@@ -885,7 +870,16 @@ static void fec_enet_bd_init(struct net_device *dev)
}
}
-static inline void fec_enet_enable_ring(struct net_device *ndev)
+static void fec_enet_active_rxring(struct net_device *ndev)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+ int i;
+
+ for (i = 0; i < fep->num_rx_queues; i++)
+ writel(0, fep->hwp + FEC_R_DES_ACTIVE(i));
+}
+
+static void fec_enet_enable_ring(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
struct fec_enet_priv_tx_q *tx_queue;
@@ -946,7 +940,6 @@ fec_restart(struct net_device *ndev)
u32 temp_mac[2];
u32 rcntl = OPT_FRAME_SIZE | 0x04;
u32 ecntl = 0x2; /* ETHEREN */
- int i;
/* Whack a reset. We should wait for this.
* For i.MX6SX SOC, enet use AXI bus, we use disable MAC
@@ -1103,8 +1096,7 @@ fec_restart(struct net_device *ndev)
/* And last, enable the transmit and receive processing */
writel(ecntl, fep->hwp + FEC_ECNTRL);
- for (i = 0; i < fep->num_rx_queues; i++)
- writel(0, fep->hwp + FEC_R_DES_ACTIVE(i));
+ fec_enet_active_rxring(ndev);
if (fep->bufdesc_ex)
fec_ptp_start_cyclecounter(ndev);
@@ -1515,9 +1507,17 @@ fec_enet_collect_events(struct fec_enet_private *fep, uint int_events)
if (int_events & FEC_ENET_RXF)
fep->work_rx |= (1 << 2);
+ if (int_events & FEC_ENET_RXF_1)
+ fep->work_rx |= (1 << 0);
+ if (int_events & FEC_ENET_RXF_2)
+ fep->work_rx |= (1 << 1);
if (int_events & FEC_ENET_TXF)
fep->work_tx |= (1 << 2);
+ if (int_events & FEC_ENET_TXF_1)
+ fep->work_tx |= (1 << 0);
+ if (int_events & FEC_ENET_TXF_2)
+ fep->work_tx |= (1 << 1);
return true;
}
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [Patch net-next 07/11] net:fec: Add fsl,imx6sx-fec compatible strings
From: y @ 2014-09-03 20:34 UTC (permalink / raw)
To: b38611-KZfg59tc24xl57MIdRCFDg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
netdev-u79uwXL29TY76Z2rM5mHXA, lznuaa-Re5JQEeQqe8AvxtiuMwx3w
Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, Fugang Duan, Frank Li
In-Reply-To: <1409776486-1403-1-git-send-email-y>
From: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Add compatible string "fsl,imx6sx-fec" for i.MX6SX.
Signed-off-by: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Signed-off-by: Frank Li <Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---
drivers/net/ethernet/freescale/fec_main.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 6aab64b..a232245 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -157,6 +157,7 @@ enum imx_fec_type {
IMX28_FEC,
IMX6Q_FEC,
MVF600_FEC,
+ IMX6SX_FEC,
};
static const struct of_device_id fec_dt_ids[] = {
@@ -165,6 +166,7 @@ static const struct of_device_id fec_dt_ids[] = {
{ .compatible = "fsl,imx28-fec", .data = &fec_devtype[IMX28_FEC], },
{ .compatible = "fsl,imx6q-fec", .data = &fec_devtype[IMX6Q_FEC], },
{ .compatible = "fsl,mvf600-fec", .data = &fec_devtype[MVF600_FEC], },
+ { .compatible = "fsl,imx6sx-fec", .data = &fec_devtype[IMX6SX_FEC], },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fec_dt_ids);
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [Patch net-next 08/11] net:fec: change FEC alignment to 64 bytes for ARM platform
From: y @ 2014-09-03 20:34 UTC (permalink / raw)
To: b38611-KZfg59tc24xl57MIdRCFDg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
netdev-u79uwXL29TY76Z2rM5mHXA, lznuaa-Re5JQEeQqe8AvxtiuMwx3w
Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, Fugang Duan, Frank Li
In-Reply-To: <1409776486-1403-1-git-send-email-y>
From: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Since enet-avb has 64 bytes alignment limitation for rx DMA transfer.
The previous enet IP for ARM platform has 16 bytes alignment for tx
DMA transfer. 64 is the an integral number of 16, so change alignment
to 64 bytes for all ARM platform, which don't impact the performance
of previous platform.
Signed-off-by: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Signed-off-by: Frank Li <Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---
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 a232245..b388e29f 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -65,7 +65,7 @@
static void set_multicast_list(struct net_device *ndev);
#if defined(CONFIG_ARM)
-#define FEC_ALIGNMENT 0xf
+#define FEC_ALIGNMENT 0x3f
#else
#define FEC_ALIGNMENT 0x3
#endif
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [Patch net-next 09/11] net:fec: remove unnessary memory copy for address alignment in .xmit()
From: y @ 2014-09-03 20:34 UTC (permalink / raw)
To: b38611-KZfg59tc24xl57MIdRCFDg, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
netdev-u79uwXL29TY76Z2rM5mHXA, lznuaa-Re5JQEeQqe8AvxtiuMwx3w
Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, Fugang Duan, Frank Li
In-Reply-To: <1409776486-1403-1-git-send-email-y>
From: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
i.MX6SX enet-avb IP support buffer address byte alignment for tx DMA
transfer, so remove the unnessary memory copy for the enet avb IP.
Signed-off-by: Fugang Duan <B38611-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
Signed-off-by: Frank Li <Frank.Li-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
---
drivers/net/ethernet/freescale/fec_main.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index b388e29f..d09fe16 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -518,8 +518,9 @@ 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) & FEC_ALIGNMENT ||
- id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) {
+ if (!(id_entry->driver_data & FEC_QUIRK_HAS_AVB) &&
+ ((((unsigned long)bufaddr) & FEC_ALIGNMENT ||
+ id_entry->driver_data & FEC_QUIRK_SWAP_FRAME))) {
memcpy(txq->tx_bounce[index], skb->data, buflen);
bufaddr = txq->tx_bounce[index];
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ 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