* Re: [ethtool PATCH 2/2] Add RX packet classification interface
From: Ben Hutchings @ 2011-03-07 19:00 UTC (permalink / raw)
To: Alexander Duyck
Cc: Dimitris Michailidis, Santwona Behera, netdev@vger.kernel.org
In-Reply-To: <4D752767.9060205@intel.com>
On Mon, 2011-03-07 at 10:43 -0800, Alexander Duyck wrote:
> On 3/7/2011 10:28 AM, Ben Hutchings wrote:
> > On Mon, 2011-03-07 at 10:22 -0800, Dimitris Michailidis wrote:
> >> Ben Hutchings wrote:
> >>> On Mon, 2011-03-07 at 09:04 -0800, Alexander Duyck wrote:
> >>>> The only time where location really matters is if you are attempting to
> >>>> overwrite an existing rule and I am not sure how that would be handled
> >>>> in ntuple anyway since right now adding additional rules via ntuple for
> >>>> ixgbe just results in duplicate rules being defined.
> >>>
> >>> As I understand it, the location also determines the *priority* for the
> >>> rule.
> >>
> >> This is true, at least for TCAMs. But it's relevant only when multiple
> >> filters would match a packet. People often use non-overlapping filters, for
> >> these adding the filter at any available slot is OK.
> >
> > Right. But ethtool would have to determine that the filter was non-
> > overlapping, before ignoring the location. Also it cannot allow
> > deletion by location if it ever ignores the location on insertion. We
> > should make the location optional at both the command-line and API
> > level, but never ignore it.
> >
>
> I wasn't implying that we ignore it for rules inserted via the nfc
> interface. Only for those inserted via the ntuple interface.
We should never fall back to the ntuple interface if a location is
specified!
> My reasoning for that was because it had occurred to me that what my
> patch series had done is allow for ntuples to be displayed via the
> get_rx_nfc interface. As such you would end up with a location being
> implied when displaying the rules since it would give you a list of n
> entities.
We need to sort that out then.
> If you attempted to restore the rules you would probably end up with the
> location information for filters 0..(n-1), and that could be dropped
> since it would just be extra information.
>
> >>> Which is why I wrote that "@fs.@location specifies the index to
> >>> use and must not be ignored."
> >>>
> >>> To support hardware where the filter table is hash-based rather than a
> >>> TCAM, we would need some kind of flag or special value of location that
> >>> means 'wherever'.
> >>
> >> I'd find the 'wherever' option useful for TCAMs too. Maybe even have a few
> >> of those, like 'first available', 'any', and 'last available'. The last one
> >> is quite useful for catch-all rules without requiring one to know the TCAM size.
> >
> > Agreed.
> >
> > Ben.
>
> The first and last options make a lot of sense to me. The one I'm not
> sure about would be the "any" option. It seems like it would be
> redundant with the "first available" option or is there something I'm
> missing?
>
> Also the code I have currently for the user space is just starting at 0
> and filling in the rules on a first available basis for location not
> specified. Is this going to work for most cases or should I look at
> changing it to something like a "last available" approach for the nfc
> based filters?
My *guess* (and this is just a guess) is that users are more likely to
want to specify explicit priorities for the high-priority rules and not
for the low-priority rules. So if the location is not explicitly set
then we should choose the last available (lowest-priority) location in a
TCAM, possibly excluding the very last location so that 'last' will
still work.
Ben.
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* Re: [ethtool PATCH 2/2] Add RX packet classification interface
From: Dimitris Michailidis @ 2011-03-07 18:57 UTC (permalink / raw)
To: Alexander Duyck; +Cc: Ben Hutchings, Santwona Behera, netdev@vger.kernel.org
In-Reply-To: <4D752767.9060205@intel.com>
Alexander Duyck wrote:
> On 3/7/2011 10:28 AM, Ben Hutchings wrote:
>> On Mon, 2011-03-07 at 10:22 -0800, Dimitris Michailidis wrote:
>>> Ben Hutchings wrote:
>>>> On Mon, 2011-03-07 at 09:04 -0800, Alexander Duyck wrote:
>>>>> The only time where location really matters is if you are
>>>>> attempting to
>>>>> overwrite an existing rule and I am not sure how that would be handled
>>>>> in ntuple anyway since right now adding additional rules via ntuple
>>>>> for
>>>>> ixgbe just results in duplicate rules being defined.
>>>>
>>>> As I understand it, the location also determines the *priority* for the
>>>> rule.
>>>
>>> This is true, at least for TCAMs. But it's relevant only when multiple
>>> filters would match a packet. People often use non-overlapping
>>> filters, for
>>> these adding the filter at any available slot is OK.
>>
>> Right. But ethtool would have to determine that the filter was non-
>> overlapping, before ignoring the location. Also it cannot allow
>> deletion by location if it ever ignores the location on insertion. We
>> should make the location optional at both the command-line and API
>> level, but never ignore it.
>>
>
> I wasn't implying that we ignore it for rules inserted via the nfc
> interface. Only for those inserted via the ntuple interface.
>
> My reasoning for that was because it had occurred to me that what my
> patch series had done is allow for ntuples to be displayed via the
> get_rx_nfc interface. As such you would end up with a location being
> implied when displaying the rules since it would give you a list of n
> entities.
>
> If you attempted to restore the rules you would probably end up with the
> location information for filters 0..(n-1), and that could be dropped
> since it would just be extra information.
>
>>>> Which is why I wrote that "@fs.@location specifies the index to
>>>> use and must not be ignored."
>>>>
>>>> To support hardware where the filter table is hash-based rather than a
>>>> TCAM, we would need some kind of flag or special value of location that
>>>> means 'wherever'.
>>>
>>> I'd find the 'wherever' option useful for TCAMs too. Maybe even have
>>> a few
>>> of those, like 'first available', 'any', and 'last available'. The
>>> last one
>>> is quite useful for catch-all rules without requiring one to know the
>>> TCAM size.
>>
>> Agreed.
>>
>> Ben.
>
> The first and last options make a lot of sense to me. The one I'm not
> sure about would be the "any" option. It seems like it would be
> redundant with the "first available" option or is there something I'm
> missing?
Not really. I offered it because we were talking about 'wherever' options.
I too find 'first' and 'last' to be most useful.
> Also the code I have currently for the user space is just starting at 0
> and filling in the rules on a first available basis for location not
> specified. Is this going to work for most cases or should I look at
> changing it to something like a "last available" approach for the nfc
> based filters?
Oh, I hadn't noticed that user space is trying to allocate the index if
unspecified. In my case, some filters need to have special indices, eg
multiple of 4. User space wouldn't know this. I think user space needs to
let the driver allocate indices if the user didn't select one. I'd default
to first available.
^ permalink raw reply
* Re: [Patch] bonding: fix netpoll in active-backup mode
From: Neil Horman @ 2011-03-07 18:50 UTC (permalink / raw)
To: Amerigo Wang
Cc: linux-kernel, Jay Vosburgh, David S. Miller, Herbert Xu,
Paul E. McKenney, John W. Linville, Eric Dumazet, netdev
In-Reply-To: <1299507114-12144-1-git-send-email-amwang@redhat.com>
On Mon, Mar 07, 2011 at 10:11:50PM +0800, Amerigo Wang wrote:
> netconsole doesn't work in active-backup mode, because we don't do anything
> for nic failover in active-backup mode. This patch fixes the problem by:
>
> 1) make slave_enable_netpoll() and slave_disable_netpoll() callable in softirq
> context, that is, moving code after synchronize_rcu_bh() into call_rcu_bh()
> callback function, teaching kzalloc() to use GFP_ATOMIC.
>
> 2) disable netpoll on old slave and enable netpoll on the new slave.
>
> Tested by ifdown the current active slave and ifup it again for several times,
> netconsole works well.
>
> Signed-off-by: WANG Cong <amwang@redhat.com>
>
I may be missing soething but this seems way over-complicated to me. I presume
the problem is that in active backup mode a failover results in the new active
slave not having netpoll setup on it? If thats the case, why not just setup
netpoll on all slaves when ndo_netpoll_setup is called on the bonding interface?
I don't see anything immeidately catastrophic that would happen as a result.
And then you wouldn't have to worry about disabling/enabling anything on a
failover (or during a panic for that matter). As for the rcu bits? Why are
they needed? One would presume that wouldn't (or at least shouldn't) be able to
teardown our netpoll setup until such time as all the pending frames for that
netpoll client have been transmitted. If we're not blocknig on that RCU isn't
really going to help. Seems like the proper fix is take a reference to the
appropriate npinfo struct in netpoll_send_skb, and drop it from the skbs
destructor or some such.
Neil
> ---
> drivers/net/bonding/bond_main.c | 236 +++++++++++++++++++++------------------
> include/linux/netpoll.h | 2 +
> net/core/netpoll.c | 22 ++--
> 3 files changed, 140 insertions(+), 120 deletions(-)
>
> diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
> index 0592e6d..2d6ec1b 100644
> --- a/drivers/net/bonding/bond_main.c
> +++ b/drivers/net/bonding/bond_main.c
> @@ -907,6 +907,121 @@ static void bond_mc_list_flush(struct net_device *bond_dev,
> }
> }
>
> +/*--------------------------- Netpoll code ---------------------------*/
> +#ifdef CONFIG_NET_POLL_CONTROLLER
> +static inline int slave_enable_netpoll(struct slave *slave)
> +{
> + struct netpoll *np;
> + int err = 0;
> +
> + np = kzalloc(sizeof(*np), GFP_ATOMIC);
> + err = -ENOMEM;
> + if (!np)
> + goto out;
> +
> + np->dev = slave->dev;
> + err = __netpoll_setup(np);
> + if (err) {
> + kfree(np);
> + goto out;
> + }
> + slave->np = np;
> +out:
> + return err;
> +}
> +static void slave_netpoll_reclaim(struct rcu_head *rp)
> +{
> + struct netpoll *np = container_of(rp, struct netpoll, rcu);
> + __netpoll_cleanup(np);
> + kfree(np);
> +}
> +static inline void slave_disable_netpoll(struct slave *slave)
> +{
> + struct netpoll *np = slave->np;
> +
> + if (!np)
> + return;
> +
> + slave->np = NULL;
> + call_rcu_bh(&np->rcu, slave_netpoll_reclaim);
> +}
> +static inline bool slave_dev_support_netpoll(struct net_device *slave_dev)
> +{
> + if (slave_dev->priv_flags & IFF_DISABLE_NETPOLL)
> + return false;
> + if (!slave_dev->netdev_ops->ndo_poll_controller)
> + return false;
> + return true;
> +}
> +
> +static void bond_poll_controller(struct net_device *bond_dev)
> +{
> +}
> +
> +static void __bond_netpoll_cleanup(struct bonding *bond)
> +{
> + struct slave *slave;
> + int i;
> +
> + bond_for_each_slave(bond, slave, i)
> + if (IS_UP(slave->dev))
> + slave_disable_netpoll(slave);
> +}
> +static void bond_netpoll_cleanup(struct net_device *bond_dev)
> +{
> + struct bonding *bond = netdev_priv(bond_dev);
> +
> + read_lock(&bond->lock);
> + __bond_netpoll_cleanup(bond);
> + read_unlock(&bond->lock);
> +}
> +
> +static int bond_netpoll_setup(struct net_device *dev, struct netpoll_info *ni)
> +{
> + struct bonding *bond = netdev_priv(dev);
> + struct slave *slave;
> + int i, err = 0;
> +
> + read_lock(&bond->lock);
> + bond_for_each_slave(bond, slave, i) {
> + if (!IS_UP(slave->dev))
> + continue;
> + err = slave_enable_netpoll(slave);
> + if (err) {
> + __bond_netpoll_cleanup(bond);
> + break;
> + }
> + }
> + read_unlock(&bond->lock);
> + return err;
> +}
> +
> +static struct netpoll_info *bond_netpoll_info(struct bonding *bond)
> +{
> + return bond->dev->npinfo;
> +}
> +
> +#else
> +static inline int slave_enable_netpoll(struct slave *slave)
> +{
> + return 0;
> +}
> +static inline void slave_disable_netpoll(struct slave *slave)
> +{
> +}
> +static void bond_netpoll_cleanup(struct net_device *bond_dev)
> +{
> +}
> +static int bond_netpoll_setup(struct net_device *dev, struct netpoll_info *ni)
> +{
> + return 0;
> +}
> +static struct netpoll_info *bond_netpoll_info(struct bonding *bond)
> +{
> + return NULL;
> +}
> +#endif
> +
> /*--------------------------- Active slave change ---------------------------*/
>
> /*
> @@ -1155,11 +1270,20 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
> }
>
> if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
> - if (old_active)
> + if (old_active) {
> bond_set_slave_inactive_flags(old_active);
> + if (bond_netpoll_info(bond))
> + slave_disable_netpoll(old_active);
> + }
>
> if (new_active) {
> + struct netpoll_info *ni;
> bond_set_slave_active_flags(new_active);
> + ni = bond_netpoll_info(bond);
> + if (ni) {
> + new_active->dev->npinfo = ni;
> + slave_enable_netpoll(new_active);
> + }
>
> if (bond->params.fail_over_mac)
> bond_do_fail_over_mac(bond, new_active,
> @@ -1280,116 +1404,6 @@ static void bond_detach_slave(struct bonding *bond, struct slave *slave)
> bond->slave_cnt--;
> }
>
> -#ifdef CONFIG_NET_POLL_CONTROLLER
> -static inline int slave_enable_netpoll(struct slave *slave)
> -{
> - struct netpoll *np;
> - int err = 0;
> -
> - np = kzalloc(sizeof(*np), GFP_KERNEL);
> - err = -ENOMEM;
> - if (!np)
> - goto out;
> -
> - np->dev = slave->dev;
> - err = __netpoll_setup(np);
> - if (err) {
> - kfree(np);
> - goto out;
> - }
> - slave->np = np;
> -out:
> - return err;
> -}
> -static inline void slave_disable_netpoll(struct slave *slave)
> -{
> - struct netpoll *np = slave->np;
> -
> - if (!np)
> - return;
> -
> - slave->np = NULL;
> - synchronize_rcu_bh();
> - __netpoll_cleanup(np);
> - kfree(np);
> -}
> -static inline bool slave_dev_support_netpoll(struct net_device *slave_dev)
> -{
> - if (slave_dev->priv_flags & IFF_DISABLE_NETPOLL)
> - return false;
> - if (!slave_dev->netdev_ops->ndo_poll_controller)
> - return false;
> - return true;
> -}
> -
> -static void bond_poll_controller(struct net_device *bond_dev)
> -{
> -}
> -
> -static void __bond_netpoll_cleanup(struct bonding *bond)
> -{
> - struct slave *slave;
> - int i;
> -
> - bond_for_each_slave(bond, slave, i)
> - if (IS_UP(slave->dev))
> - slave_disable_netpoll(slave);
> -}
> -static void bond_netpoll_cleanup(struct net_device *bond_dev)
> -{
> - struct bonding *bond = netdev_priv(bond_dev);
> -
> - read_lock(&bond->lock);
> - __bond_netpoll_cleanup(bond);
> - read_unlock(&bond->lock);
> -}
> -
> -static int bond_netpoll_setup(struct net_device *dev, struct netpoll_info *ni)
> -{
> - struct bonding *bond = netdev_priv(dev);
> - struct slave *slave;
> - int i, err = 0;
> -
> - read_lock(&bond->lock);
> - bond_for_each_slave(bond, slave, i) {
> - if (!IS_UP(slave->dev))
> - continue;
> - err = slave_enable_netpoll(slave);
> - if (err) {
> - __bond_netpoll_cleanup(bond);
> - break;
> - }
> - }
> - read_unlock(&bond->lock);
> - return err;
> -}
> -
> -static struct netpoll_info *bond_netpoll_info(struct bonding *bond)
> -{
> - return bond->dev->npinfo;
> -}
> -
> -#else
> -static inline int slave_enable_netpoll(struct slave *slave)
> -{
> - return 0;
> -}
> -static inline void slave_disable_netpoll(struct slave *slave)
> -{
> -}
> -static void bond_netpoll_cleanup(struct net_device *bond_dev)
> -{
> -}
> -static int bond_netpoll_setup(struct net_device *dev, struct netpoll_info *ni)
> -{
> - return 0;
> -}
> -static struct netpoll_info *bond_netpoll_info(struct bonding *bond)
> -{
> - return NULL;
> -}
> -#endif
> -
> /*---------------------------------- IOCTL ----------------------------------*/
>
> static int bond_sethwaddr(struct net_device *bond_dev,
> diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
> index 79358bb..9412aa5 100644
> --- a/include/linux/netpoll.h
> +++ b/include/linux/netpoll.h
> @@ -23,6 +23,7 @@ struct netpoll {
> u8 remote_mac[ETH_ALEN];
>
> struct list_head rx; /* rx_np list element */
> + struct rcu_head rcu;
> };
>
> struct netpoll_info {
> @@ -38,6 +39,7 @@ struct netpoll_info {
> struct delayed_work tx_work;
>
> struct netpoll *netpoll;
> + struct rcu_head rcu;
> };
>
> void netpoll_poll_dev(struct net_device *dev);
> diff --git a/net/core/netpoll.c b/net/core/netpoll.c
> index 06be243..9870dac 100644
> --- a/net/core/netpoll.c
> +++ b/net/core/netpoll.c
> @@ -901,6 +901,18 @@ static int __init netpoll_init(void)
> }
> core_initcall(netpoll_init);
>
> +static void netpoll_reclaim(struct rcu_head *rp)
> +{
> + struct netpoll_info *npinfo = container_of(rp, struct netpoll_info, rcu);
> + skb_queue_purge(&npinfo->arp_tx);
> + skb_queue_purge(&npinfo->txq);
> + cancel_delayed_work_sync(&npinfo->tx_work);
> +
> + /* clean after last, unfinished work */
> + __skb_queue_purge(&npinfo->txq);
> + kfree(npinfo);
> +}
> +
> void __netpoll_cleanup(struct netpoll *np)
> {
> struct netpoll_info *npinfo;
> @@ -928,15 +940,7 @@ void __netpoll_cleanup(struct netpoll *np)
> rcu_assign_pointer(np->dev->npinfo, NULL);
>
> /* avoid racing with NAPI reading npinfo */
> - synchronize_rcu_bh();
> -
> - skb_queue_purge(&npinfo->arp_tx);
> - skb_queue_purge(&npinfo->txq);
> - cancel_delayed_work_sync(&npinfo->tx_work);
> -
> - /* clean after last, unfinished work */
> - __skb_queue_purge(&npinfo->txq);
> - kfree(npinfo);
> + call_rcu_bh(&npinfo->rcu, netpoll_reclaim);
> }
> }
> EXPORT_SYMBOL_GPL(__netpoll_cleanup);
>
^ permalink raw reply
* Re: [ethtool PATCH 2/2] Add RX packet classification interface
From: Alexander Duyck @ 2011-03-07 18:43 UTC (permalink / raw)
To: Ben Hutchings
Cc: Dimitris Michailidis, Santwona Behera, netdev@vger.kernel.org
In-Reply-To: <1299522481.2522.24.camel@bwh-desktop>
On 3/7/2011 10:28 AM, Ben Hutchings wrote:
> On Mon, 2011-03-07 at 10:22 -0800, Dimitris Michailidis wrote:
>> Ben Hutchings wrote:
>>> On Mon, 2011-03-07 at 09:04 -0800, Alexander Duyck wrote:
>>>> The only time where location really matters is if you are attempting to
>>>> overwrite an existing rule and I am not sure how that would be handled
>>>> in ntuple anyway since right now adding additional rules via ntuple for
>>>> ixgbe just results in duplicate rules being defined.
>>>
>>> As I understand it, the location also determines the *priority* for the
>>> rule.
>>
>> This is true, at least for TCAMs. But it's relevant only when multiple
>> filters would match a packet. People often use non-overlapping filters, for
>> these adding the filter at any available slot is OK.
>
> Right. But ethtool would have to determine that the filter was non-
> overlapping, before ignoring the location. Also it cannot allow
> deletion by location if it ever ignores the location on insertion. We
> should make the location optional at both the command-line and API
> level, but never ignore it.
>
I wasn't implying that we ignore it for rules inserted via the nfc
interface. Only for those inserted via the ntuple interface.
My reasoning for that was because it had occurred to me that what my
patch series had done is allow for ntuples to be displayed via the
get_rx_nfc interface. As such you would end up with a location being
implied when displaying the rules since it would give you a list of n
entities.
If you attempted to restore the rules you would probably end up with the
location information for filters 0..(n-1), and that could be dropped
since it would just be extra information.
>>> Which is why I wrote that "@fs.@location specifies the index to
>>> use and must not be ignored."
>>>
>>> To support hardware where the filter table is hash-based rather than a
>>> TCAM, we would need some kind of flag or special value of location that
>>> means 'wherever'.
>>
>> I'd find the 'wherever' option useful for TCAMs too. Maybe even have a few
>> of those, like 'first available', 'any', and 'last available'. The last one
>> is quite useful for catch-all rules without requiring one to know the TCAM size.
>
> Agreed.
>
> Ben.
The first and last options make a lot of sense to me. The one I'm not
sure about would be the "any" option. It seems like it would be
redundant with the "first available" option or is there something I'm
missing?
Also the code I have currently for the user space is just starting at 0
and filling in the rules on a first available basis for location not
specified. Is this going to work for most cases or should I look at
changing it to something like a "last available" approach for the nfc
based filters?
Thanks,
Alex
^ permalink raw reply
* [PATCH] bridge: control carrier based on ports online
From: Stephen Hemminger @ 2011-03-07 18:34 UTC (permalink / raw)
To: David S. Miller
Cc: Nicolas de Pesloüan, Adam Majer, Alexey Kuznetsov,
Pekka Savola (ipv6), James Morris, Hideaki YOSHIFUJI,
Patrick McHardy, bridge, netdev, Andy Gospodarek, Jay Vosburgh
In-Reply-To: <4D748CC3.8060603@gmail.com>
This makes the bridge device behave like a physical device.
In earlier releases the bridge always asserted carrier. This
changes the behavior so that bridge device carrier is on only
if one or more ports are in the forwarding state. This
should help IPv6 autoconfiguration, DHCP, and routing daemons.
I did brief testing with Network and Virt manager and they
seem fine, but since this changes behavior of bridge, it should
wait until net-next (2.6.39).
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
net/bridge/br_device.c | 4 ++++
net/bridge/br_stp.c | 35 ++++++++++++++++++++++-------------
net/bridge/br_stp_timer.c | 1 +
3 files changed, 27 insertions(+), 13 deletions(-)
--- a/net/bridge/br_device.c 2011-03-07 08:40:08.913599513 -0800
+++ b/net/bridge/br_device.c 2011-03-07 08:40:48.382377389 -0800
@@ -78,6 +78,8 @@ static int br_dev_open(struct net_device
{
struct net_bridge *br = netdev_priv(dev);
+ netif_carrier_off(dev);
+
br_features_recompute(br);
netif_start_queue(dev);
br_stp_enable_bridge(br);
@@ -94,6 +96,8 @@ static int br_dev_stop(struct net_device
{
struct net_bridge *br = netdev_priv(dev);
+ netif_carrier_off(dev);
+
br_stp_disable_bridge(br);
br_multicast_stop(br);
--- a/net/bridge/br_stp.c 2011-03-07 08:41:58.619783678 -0800
+++ b/net/bridge/br_stp.c 2011-03-07 08:53:58.953558810 -0800
@@ -397,28 +397,37 @@ static void br_make_forwarding(struct ne
void br_port_state_selection(struct net_bridge *br)
{
struct net_bridge_port *p;
+ unsigned int liveports = 0;
/* Don't change port states if userspace is handling STP */
if (br->stp_enabled == BR_USER_STP)
return;
list_for_each_entry(p, &br->port_list, list) {
- if (p->state != BR_STATE_DISABLED) {
- if (p->port_no == br->root_port) {
- p->config_pending = 0;
- p->topology_change_ack = 0;
- br_make_forwarding(p);
- } else if (br_is_designated_port(p)) {
- del_timer(&p->message_age_timer);
- br_make_forwarding(p);
- } else {
- p->config_pending = 0;
- p->topology_change_ack = 0;
- br_make_blocking(p);
- }
+ if (p->state == BR_STATE_DISABLED)
+ continue;
+
+ if (p->port_no == br->root_port) {
+ p->config_pending = 0;
+ p->topology_change_ack = 0;
+ br_make_forwarding(p);
+ } else if (br_is_designated_port(p)) {
+ del_timer(&p->message_age_timer);
+ br_make_forwarding(p);
+ } else {
+ p->config_pending = 0;
+ p->topology_change_ack = 0;
+ br_make_blocking(p);
}
+ if (p->state == BR_STATE_FORWARDING)
+ ++liveports;
}
+
+ if (liveports == 0)
+ netif_carrier_off(br->dev);
+ else
+ netif_carrier_on(br->dev);
}
/* called under bridge lock */
--- a/net/bridge/br_stp_timer.c 2011-03-07 08:53:25.728770710 -0800
+++ b/net/bridge/br_stp_timer.c 2011-03-07 08:53:40.273116636 -0800
@@ -94,6 +94,7 @@ static void br_forward_delay_timer_expir
p->state = BR_STATE_FORWARDING;
if (br_is_designated_for_some_port(br))
br_topology_change_detection(br);
+ netif_carrier_on(br->dev);
}
br_log_state(p);
spin_unlock(&br->lock);
^ permalink raw reply
* Re: [ethtool PATCH 2/2] Add RX packet classification interface
From: Ben Hutchings @ 2011-03-07 18:28 UTC (permalink / raw)
To: Dimitris Michailidis
Cc: Alexander Duyck, Santwona Behera, netdev@vger.kernel.org
In-Reply-To: <4D75225B.3010008@chelsio.com>
On Mon, 2011-03-07 at 10:22 -0800, Dimitris Michailidis wrote:
> Ben Hutchings wrote:
> > On Mon, 2011-03-07 at 09:04 -0800, Alexander Duyck wrote:
> >> The only time where location really matters is if you are attempting to
> >> overwrite an existing rule and I am not sure how that would be handled
> >> in ntuple anyway since right now adding additional rules via ntuple for
> >> ixgbe just results in duplicate rules being defined.
> >
> > As I understand it, the location also determines the *priority* for the
> > rule.
>
> This is true, at least for TCAMs. But it's relevant only when multiple
> filters would match a packet. People often use non-overlapping filters, for
> these adding the filter at any available slot is OK.
Right. But ethtool would have to determine that the filter was non-
overlapping, before ignoring the location. Also it cannot allow
deletion by location if it ever ignores the location on insertion. We
should make the location optional at both the command-line and API
level, but never ignore it.
> > Which is why I wrote that "@fs.@location specifies the index to
> > use and must not be ignored."
> >
> > To support hardware where the filter table is hash-based rather than a
> > TCAM, we would need some kind of flag or special value of location that
> > means 'wherever'.
>
> I'd find the 'wherever' option useful for TCAMs too. Maybe even have a few
> of those, like 'first available', 'any', and 'last available'. The last one
> is quite useful for catch-all rules without requiring one to know the TCAM size.
Agreed.
Ben.
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* Re: [PATCH] dsa/mv88e6060: support nonzero mii base address
From: Lennert Buytenhek @ 2011-03-07 18:24 UTC (permalink / raw)
To: Peter Korsgaard; +Cc: davem, netdev
In-Reply-To: <1299512987-11152-1-git-send-email-jacmet@sunsite.dk>
On Mon, Mar 07, 2011 at 04:49:47PM +0100, Peter Korsgaard wrote:
> The mv88e6060 uses either the lower 16 or upper 16 mii addresses,
> depending on the value of the EE_CLK/ADDR4 pin. Support both
> configurations by using the sw_addr setting as base address.
>
> Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
Looks good!
Acked-by: Lennert Buytenhek <buytenh@wantstofly.org>
^ permalink raw reply
* Re: RFC: dsa slave open handling
From: Lennert Buytenhek @ 2011-03-07 18:23 UTC (permalink / raw)
To: Peter Korsgaard; +Cc: davem, netdev
In-Reply-To: <871v2inajz.fsf@macbook.be.48ers.dk>
On Mon, Mar 07, 2011 at 05:46:08PM +0100, Peter Korsgaard wrote:
> Hi,
Hello,
> Currently the state of the dsa master device and slave devices are not
> synchronized which leads to various issues. With dsa, the master device
> needs to be running before you can use the slave devices, but it
> shouldn't be used directly for I/O.
I think this should not be handled any differently than VLAN interfaces,
where eth0 needs to be up before you can exchange packets over eth0.123.
IOW, if you want to do DHCP over wan (a DSA-tunneled interface over
eth0), then just use an initramfs that sets eth0 up and then runs a
DHCP client on wan.
The fact that in-kernel IP autoconfiguration can't deal with DSA just
means that you shouldn't use the in-kernel IP autoconfiguration -- you
could "fix" this with one of your proposed patches, but then the next
thing will be someone wanting to do in-kernel IP autoconfig over a VLAN
interface stacked onto a DSA interface, etc, which then still wouldn't
work.
cheers,
Lennert
^ permalink raw reply
* Re: [ethtool PATCH 2/2] Add RX packet classification interface
From: Dimitris Michailidis @ 2011-03-07 18:22 UTC (permalink / raw)
To: Ben Hutchings; +Cc: Alexander Duyck, Santwona Behera, netdev@vger.kernel.org
In-Reply-To: <1299520664.2522.21.camel@bwh-desktop>
Ben Hutchings wrote:
> On Mon, 2011-03-07 at 09:04 -0800, Alexander Duyck wrote:
>> The only time where location really matters is if you are attempting to
>> overwrite an existing rule and I am not sure how that would be handled
>> in ntuple anyway since right now adding additional rules via ntuple for
>> ixgbe just results in duplicate rules being defined.
>
> As I understand it, the location also determines the *priority* for the
> rule.
This is true, at least for TCAMs. But it's relevant only when multiple
filters would match a packet. People often use non-overlapping filters, for
these adding the filter at any available slot is OK.
> Which is why I wrote that "@fs.@location specifies the index to
> use and must not be ignored."
>
> To support hardware where the filter table is hash-based rather than a
> TCAM, we would need some kind of flag or special value of location that
> means 'wherever'.
I'd find the 'wherever' option useful for TCAMs too. Maybe even have a few
of those, like 'first available', 'any', and 'last available'. The last one
is quite useful for catch-all rules without requiring one to know the TCAM size.
^ permalink raw reply
* Re: [PATCH V4] Export ACPI _DSM provided firmware instance number and string name to sysfs
From: Alexander Beregalov @ 2011-03-07 18:04 UTC (permalink / raw)
To: Jesse Barnes
Cc: Narendra_K, linux-pci, linux-hotplug, netdev, mjg, Matt_Domsch,
Charles_Rose, Jordan_Hargrave, Shyam_Iyer, sfr
In-Reply-To: <20110304104314.26265021@jbarnes-desktop>
On 4 March 2011 21:43, Jesse Barnes <jbarnes@virtuousgeek.org> wrote:
> On Wed, 2 Mar 2011 22:34:17 +0530
> <Narendra_K@Dell.com> wrote:
>
>> On Wed, Feb 23, 2011 at 06:06:42PM +0530, K, Narendra wrote:
>> > Hello,
>> >
>> > This patch exports ACPI _DSM provided firmware instance number and
>> > string name to sysfs.
>> >
>> > V1 -> V2:
>> > The attribute 'index' is changed to 'acpi_index' as the semantics of
>> > SMBIOS provided device type instance and ACPI _DSM provided firmware
>> > instance number are different.
>> >
>> > V2 -> V3:
>> > Matthew Garrett pointed out that 'sysfs_create_groups' does return an
>> > error when there are no ACPI _DSM attributes available and because of
>> > that the fallback to SMBIOS will not happen. As a result SMBIOS provided
>> > attributes are not created. This version of the patch addresses the issue.
>> >
>>
>> V3 -> V4:
>> Select NLS if (DMI || ACPI) in drivers/pci/Kconfig to prevent build
>> breakage from an 'allmodconfig'
>
> Applied, fingers crossed this time. :)
>
Hi,
It cannot be compiled if CONFIG_ACPI is not set.
drivers/pci/pci-label.c: In function 'pci_create_firmware_label_files':
drivers/pci/pci-label.c:366:2: error: implicit declaration of function
'device_has_dsm'
^ permalink raw reply
* Re: [ethtool PATCH 2/2] Add RX packet classification interface
From: Ben Hutchings @ 2011-03-07 17:57 UTC (permalink / raw)
To: Alexander Duyck; +Cc: Santwona Behera, netdev@vger.kernel.org
In-Reply-To: <4D751038.9040804@intel.com>
On Mon, 2011-03-07 at 09:04 -0800, Alexander Duyck wrote:
> On 3/7/2011 7:57 AM, Ben Hutchings wrote:
> > On Fri, 2011-03-04 at 11:09 -0800, Alexander Duyck wrote:
> >> On 2/28/2011 4:35 PM, Ben Hutchings wrote:
> >>> On Tue, 2011-02-22 at 12:52 -0800, Alexander Duyck wrote:
> >>
> >> [...]
> >>
> >>>>>> } else
> >>>>>> show_usage(1);
> >>>>>> break;
> >>>>>
> >>>>> I don't think the same options (-n, -N) should be used both for flow
> >>>>> hashing and n-tuple flow steering/filtering. This command-line
> >>>>> interface and the structure used in the ethtool API just seem to reflect
> >>>>> the implementation in the niu driver.
> >>>>>
> >>>>> (In fact I would much prefer it if the -u and -U options could be used
> >>>>> for both the rxnfc and rxntuple interfaces. But I haven't thought about
> >>>>> how the differences in functionality would be exposed to or hidden from
> >>>>> the user.)
> >>>>
> >>>> I was kind of thinking about merging the two interfaces too, but I was
> >>>> looking at it more from the perspective of moving away from ntuple more
> >>>> towards this newer interface. My main motivation being that the filter
> >>>> display option is so badly broken for ntuple that it would be easier to
> >>>> make ntuple a subset of the flow classifier instead of the other way around.
> >>>>
> >>>> What would you think of using the "flow-type" keyword to indicate legacy
> >>>> ntuple support, and then adding something like "class-rule-add", and
> >>>> "class-rule-del" to add support for the network flow classifier calls?
> >>>
> >>> I really don't want to introduce different syntax for functionality that
> >>> is common between the two command sets. The user should not have to
> >>> know that driver A implements interface I and driver B implements
> >>> interface J, except that since version 2.6.y driver A implements
> >>> interface J too.
> >>>
> >>> Surely it is possible to try one interface, then the other, when the
> >>> requested filter can be implemented either way?
> >>
> >> The problem is that the interfaces are different in the way they
> >> implement their masks. N-tuple defines the mask as 0s mean inclusion,
> >> 1s, mean exclusion.
> >
> > You have got to be kidding me!
> >
> > If this is the case, then the current kernel-doc for
> > ethtool_rx_flow_spec::m_u is incorrect.
>
> That would be the case. The m_u for ethtool_rx_flow_spec is 0 for bits
> to be ignored. It is one of the things I really liked about that since
> in combination with the way the original patch generated the masks it
> would mean no goofy bit setting workarounds.
>
> I think the documentation was added after the ethtool_rx_flow_spec and
> ethtool_rx_ntuple_flow_spec were and it looks like whoever added it
> probably assumed it worked the same way as ntuple. I can probably
> submit an updated patch to correct the kernel-doc for that.
I added that documentation. Since I missed the original rxnfc patch for
ethtool, from which I could have inferred the correct semantics of the
masks, I assumed that they were interrpeted the same as in
ethtool_rx_ntuple_flow_spec.
[...]
> Actually now that I am thinking about it I could probably just ignore
> location for rules that end up being processed via ntuple.
>
> The only time where location really matters is if you are attempting to
> overwrite an existing rule and I am not sure how that would be handled
> in ntuple anyway since right now adding additional rules via ntuple for
> ixgbe just results in duplicate rules being defined.
As I understand it, the location also determines the *priority* for the
rule. Which is why I wrote that "@fs.@location specifies the index to
use and must not be ignored."
To support hardware where the filter table is hash-based rather than a
TCAM, we would need some kind of flag or special value of location that
means 'wherever'.
> The idea I have for this now is to just record everything using the
> ethtool_rx_flow_spec. With it extended to support VLAN and 64 bytes of
> data we should be able to just store everything in the one structure,
> try recording it to the hardware via the nfc interface, if that fails
> then copy the values except for location into a ntuple structure, and
> attempt to write it via the ntuple interface.
Right.
Ben.
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* Re: [ethtool PATCH 2/2] Add RX packet classification interface
From: Alexander Duyck @ 2011-03-07 17:04 UTC (permalink / raw)
To: Ben Hutchings; +Cc: Santwona Behera, netdev@vger.kernel.org
In-Reply-To: <1299513430.2522.9.camel@bwh-desktop>
On 3/7/2011 7:57 AM, Ben Hutchings wrote:
> On Fri, 2011-03-04 at 11:09 -0800, Alexander Duyck wrote:
>> On 2/28/2011 4:35 PM, Ben Hutchings wrote:
>>> On Tue, 2011-02-22 at 12:52 -0800, Alexander Duyck wrote:
>>
>> [...]
>>
>>>>>> } else
>>>>>> show_usage(1);
>>>>>> break;
>>>>>
>>>>> I don't think the same options (-n, -N) should be used both for flow
>>>>> hashing and n-tuple flow steering/filtering. This command-line
>>>>> interface and the structure used in the ethtool API just seem to reflect
>>>>> the implementation in the niu driver.
>>>>>
>>>>> (In fact I would much prefer it if the -u and -U options could be used
>>>>> for both the rxnfc and rxntuple interfaces. But I haven't thought about
>>>>> how the differences in functionality would be exposed to or hidden from
>>>>> the user.)
>>>>
>>>> I was kind of thinking about merging the two interfaces too, but I was
>>>> looking at it more from the perspective of moving away from ntuple more
>>>> towards this newer interface. My main motivation being that the filter
>>>> display option is so badly broken for ntuple that it would be easier to
>>>> make ntuple a subset of the flow classifier instead of the other way around.
>>>>
>>>> What would you think of using the "flow-type" keyword to indicate legacy
>>>> ntuple support, and then adding something like "class-rule-add", and
>>>> "class-rule-del" to add support for the network flow classifier calls?
>>>
>>> I really don't want to introduce different syntax for functionality that
>>> is common between the two command sets. The user should not have to
>>> know that driver A implements interface I and driver B implements
>>> interface J, except that since version 2.6.y driver A implements
>>> interface J too.
>>>
>>> Surely it is possible to try one interface, then the other, when the
>>> requested filter can be implemented either way?
>>
>> The problem is that the interfaces are different in the way they
>> implement their masks. N-tuple defines the mask as 0s mean inclusion,
>> 1s, mean exclusion.
>
> You have got to be kidding me!
>
> If this is the case, then the current kernel-doc for
> ethtool_rx_flow_spec::m_u is incorrect.
That would be the case. The m_u for ethtool_rx_flow_spec is 0 for bits
to be ignored. It is one of the things I really liked about that since
in combination with the way the original patch generated the masks it
would mean no goofy bit setting workarounds.
I think the documentation was added after the ethtool_rx_flow_spec and
ethtool_rx_ntuple_flow_spec were and it looks like whoever added it
probably assumed it worked the same way as ntuple. I can probably
submit an updated patch to correct the kernel-doc for that.
>> The network flow classifier filters are the exact
>> opposite. As such we really need to know which type of filter we are
>> dealing with before we start setting up values.
>
> This is nonsense; it's not hard to flip the bits later.
Sorry about that I was probably thinking a bit too literally. So what
you are suggesting is that I store the values as a 1's compliment of
what the user set as input for ethtool_rx_flow_spec. I think I can
manage that.
>> In addition there are
>> options such as location which exist in network flow classifier rules,
>> but not in ntuple rules.
>
> Sure, and when those are specified then there can be no fallback.
>
> Ben.
>
Actually now that I am thinking about it I could probably just ignore
location for rules that end up being processed via ntuple.
The only time where location really matters is if you are attempting to
overwrite an existing rule and I am not sure how that would be handled
in ntuple anyway since right now adding additional rules via ntuple for
ixgbe just results in duplicate rules being defined.
The idea I have for this now is to just record everything using the
ethtool_rx_flow_spec. With it extended to support VLAN and 64 bytes of
data we should be able to just store everything in the one structure,
try recording it to the hardware via the nfc interface, if that fails
then copy the values except for location into a ntuple structure, and
attempt to write it via the ntuple interface.
Thanks,
Alex
^ permalink raw reply
* [PATCH] vxge: update MAINTAINERS
From: Jon Mason @ 2011-03-07 17:02 UTC (permalink / raw)
To: davem; +Cc: netdev, Jon Mason
Exar has exited the 10G Ethernet NIC market, orphaning both the s2io and
vxge drivers. With the promise of free hardware, I'll take over
maintainership.
Signed-off-by: Jon Mason <jdmason@kudzu.us>
---
MAINTAINERS | 5 +----
1 files changed, 1 insertions(+), 4 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index 75760e7..c069c45 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4284,10 +4284,7 @@ S: Maintained
F: net/sched/sch_netem.c
NETERION 10GbE DRIVERS (s2io/vxge)
-M: Ramkrishna Vepa <ramkrishna.vepa@exar.com>
-M: Sivakumar Subramani <sivakumar.subramani@exar.com>
-M: Sreenivasa Honnur <sreenivasa.honnur@exar.com>
-M: Jon Mason <jon.mason@exar.com>
+M: Jon Mason <jdmason@kudzu.us>
L: netdev@vger.kernel.org
W: http://trac.neterion.com/cgi-bin/trac.cgi/wiki/Linux?Anonymous
W: http://trac.neterion.com/cgi-bin/trac.cgi/wiki/X3100Linux?Anonymous
--
1.7.0.4
^ permalink raw reply related
* RFC: dsa slave open handling
From: Peter Korsgaard @ 2011-03-07 16:46 UTC (permalink / raw)
To: davem, buytenh, netdev
Hi,
Currently the state of the dsa master device and slave devices are not
synchronized which leads to various issues. With dsa, the master device
needs to be running before you can use the slave devices, but it
shouldn't be used directly for I/O.
As an example, I have a device with a single network interface connected
to a mv88e6060 switch. This is nicely handled through dsa, but with this
setup, IP autoconfiguration doesn't work:
If you boot with ip=on (E.G. use any device) eth0 is first brought up
and then the dsa slave devices. DHCP/bootp requests are sent out on both
the dsa slaves and the master eth0 interface. This is not optimal as the
mv88e6060 uses the trailer tag format, so it ends up stripping the
trailing 4 bytes of the requests sent directly on eth0 (and then sends
out on port 0), which leads to invalid UDP checksum, but that's worse -
Once a reply has been received on one of the dsa ports, autoconfig
closes all other devices including eth0, which also brings down the dsa
ports so nfs mount fails.
If on the other hand you boot with ip=:::::<dsa port name>
(E.G. explicitly force autoconfig to use that port), then it fails when
it tries to open the device because eth0 isn't up:
static int dsa_slave_open(struct net_device *dev)
{
struct dsa_slave_priv *p = netdev_priv(dev);
struct net_device *master = p->parent->dst->master_netdev;
int err;
if (!(master->flags & IFF_UP))
return -ENETDOWN;
How should this preferably be handled? We could either automatically
bring up the master device whenever a dsa slave is brought up:
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 64ca2a6..dfc7558 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -63,8 +63,9 @@ static int dsa_slave_open(struct net_device *dev)
struct net_device *master = p->parent->dst->master_netdev;
int err;
- if (!(master->flags & IFF_UP))
- return -ENETDOWN;
+ err = dev_change_flags(master, master->flags | IFF_UP);
+ if (err < 0)
+ return err;
if (compare_ether_addr(dev->dev_addr, master->dev_addr)) {
err = dev_uc_add(master, dev->dev_addr);
dev_change_flags(master, master->flags | IFF_UP);
Or we could simply handle it in ipconfig by not closing dsa master devices:
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index 2b09775..4d4474b 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -277,6 +277,11 @@ static void __init ic_close_devs(void)
next = d->next;
dev = d->dev;
if (dev != ic_dev) {
+#ifdef CONFIG_NET_DSA
+ /* master device might be needed for dsa access */
+ if (dev->dsa_ptr)
+ continue;
+#endif
DBG(("IP-Config: Downing %s\n", dev->name));
dev_change_flags(dev, d->flags);
}
Which is preferred?
--
Bye, Peter Korsgaard
^ permalink raw reply related
* Re: [PATCH net-next-2.6] net: enhance the documentation for rx_handler.
From: Stephen Hemminger @ 2011-03-07 16:36 UTC (permalink / raw)
To: Nicolas de Pesloüan; +Cc: netdev, davem, eric.dumazet, kaber, fubar, andy
In-Reply-To: <1299441608-25482-1-git-send-email-nicolas.2p.debian@free.fr>
On Sun, 6 Mar 2011 21:00:08 +0100
Nicolas de Pesloüan <nicolas.2p.debian@free.fr> wrote:
> Signed-off-by: Nicolas de Pesloüan <nicolas.2p.debian@free.fr>
> ---
> This apply on top of Jiri's last patch serie, including the last one that
> commented the RX_HANDLER_* values.
>
> include/linux/netdevice.h | 53 ++++++++++++++++++++++++++++++++++++++------
> net/core/dev.c | 2 +
> 2 files changed, 47 insertions(+), 8 deletions(-)
>
> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index 26e03f9..0c9dc93 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -390,15 +390,52 @@ enum gro_result {
> };
> typedef enum gro_result gro_result_t;
>
> +/**
> + * enum rx_handler_result - Possible return values for rx_handlers.
> + * @RX_HANDLER_CONSUMED: skb was consumed by rx_handler, do not process it
> + * further.
> + * @RX_HANDLER_ANOTHER: Do another round in receive path. This is indicated in
> + * case skb->dev was changed by rx_handler.
> + * @RX_HANDLER_EXACT: Force exact delivery, no wildcard.
> + * @RX_HANDLER_PASS: Do nothing, passe the skb as if no rx_handler was called.
s/passe/process/
^ permalink raw reply
* Re: [V2 Patch] bonding: move procfs code into bond_procfs.c
From: Andy Gospodarek @ 2011-03-07 16:17 UTC (permalink / raw)
To: Amerigo Wang; +Cc: linux-kernel, davem, Jay Vosburgh, netdev
In-Reply-To: <1299484726-29905-1-git-send-email-amwang@redhat.com>
On Mon, Mar 07, 2011 at 03:58:46PM +0800, Amerigo Wang wrote:
> V2: Move #ifdef CONFIG_PROC_FS into bonding.h, as suggested by David.
>
> bond_main.c is bloating, separate the procfs code out,
> move them to bond_procfs.c
>
> Signed-off-by: WANG Cong <amwang@redhat.com>
>
Looks good and works as expected.
Signed-off-by: Andy Gospodarek <andy@greyhouse.net>
^ permalink raw reply
* Re: [PATCH 2/2] Define ENONAMESERVICE and ENAMEUNKNOWN to indicate name service errors
From: Alan Cox @ 2011-03-07 16:00 UTC (permalink / raw)
To: David Howells
Cc: linux-security-module-u79uwXL29TY76Z2rM5mHXA,
keyrings-6DNke4IJHB0gsBAKwltoeQ, linux-nfs-u79uwXL29TY76Z2rM5mHXA,
linux-cifs-u79uwXL29TY76Z2rM5mHXA,
linux-afs-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20110307150218.28218.84916.stgit-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
> Define ENONAMESERVICE to indicate "Network name service unavailable". This can
> be used to indicate, for example, that an attempt was made by dns_query() to
> make a query, but the name server (e.g. a DNS server) it is supposed to contact
> didn't answer or that it couldn't determine the location of a suitable server.
Are these in glibc and are there glibc patches submitted and accepted for
this ?
(I only ask because I know its previously taken years for glibc to catch
up with stuff)
^ permalink raw reply
* Re: [ethtool PATCH 2/2] Add RX packet classification interface
From: Ben Hutchings @ 2011-03-07 15:57 UTC (permalink / raw)
To: Alexander Duyck; +Cc: Santwona Behera, netdev@vger.kernel.org
In-Reply-To: <4D7138EF.7050606@intel.com>
On Fri, 2011-03-04 at 11:09 -0800, Alexander Duyck wrote:
> On 2/28/2011 4:35 PM, Ben Hutchings wrote:
> > On Tue, 2011-02-22 at 12:52 -0800, Alexander Duyck wrote:
>
> [...]
>
> >>>> } else
> >>>> show_usage(1);
> >>>> break;
> >>>
> >>> I don't think the same options (-n, -N) should be used both for flow
> >>> hashing and n-tuple flow steering/filtering. This command-line
> >>> interface and the structure used in the ethtool API just seem to reflect
> >>> the implementation in the niu driver.
> >>>
> >>> (In fact I would much prefer it if the -u and -U options could be used
> >>> for both the rxnfc and rxntuple interfaces. But I haven't thought about
> >>> how the differences in functionality would be exposed to or hidden from
> >>> the user.)
> >>
> >> I was kind of thinking about merging the two interfaces too, but I was
> >> looking at it more from the perspective of moving away from ntuple more
> >> towards this newer interface. My main motivation being that the filter
> >> display option is so badly broken for ntuple that it would be easier to
> >> make ntuple a subset of the flow classifier instead of the other way around.
> >>
> >> What would you think of using the "flow-type" keyword to indicate legacy
> >> ntuple support, and then adding something like "class-rule-add", and
> >> "class-rule-del" to add support for the network flow classifier calls?
> >
> > I really don't want to introduce different syntax for functionality that
> > is common between the two command sets. The user should not have to
> > know that driver A implements interface I and driver B implements
> > interface J, except that since version 2.6.y driver A implements
> > interface J too.
> >
> > Surely it is possible to try one interface, then the other, when the
> > requested filter can be implemented either way?
>
> The problem is that the interfaces are different in the way they
> implement their masks. N-tuple defines the mask as 0s mean inclusion,
> 1s, mean exclusion.
You have got to be kidding me!
If this is the case, then the current kernel-doc for
ethtool_rx_flow_spec::m_u is incorrect.
> The network flow classifier filters are the exact
> opposite. As such we really need to know which type of filter we are
> dealing with before we start setting up values.
This is nonsense; it's not hard to flip the bits later.
> In addition there are
> options such as location which exist in network flow classifier rules,
> but not in ntuple rules.
Sure, and when those are specified then there can be no fallback.
Ben.
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* [PATCH] dsa/mv88e6060: support nonzero mii base address
From: Peter Korsgaard @ 2011-03-07 15:49 UTC (permalink / raw)
To: davem, buytenh, netdev; +Cc: Peter Korsgaard
The mv88e6060 uses either the lower 16 or upper 16 mii addresses,
depending on the value of the EE_CLK/ADDR4 pin. Support both
configurations by using the sw_addr setting as base address.
Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
---
net/dsa/mv88e6060.c | 7 ++++---
1 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/net/dsa/mv88e6060.c b/net/dsa/mv88e6060.c
index 83277f4..8f4ff5a 100644
--- a/net/dsa/mv88e6060.c
+++ b/net/dsa/mv88e6060.c
@@ -18,7 +18,7 @@
static int reg_read(struct dsa_switch *ds, int addr, int reg)
{
- return mdiobus_read(ds->master_mii_bus, addr, reg);
+ return mdiobus_read(ds->master_mii_bus, ds->pd->sw_addr + addr, reg);
}
#define REG_READ(addr, reg) \
@@ -34,7 +34,8 @@ static int reg_read(struct dsa_switch *ds, int addr, int reg)
static int reg_write(struct dsa_switch *ds, int addr, int reg, u16 val)
{
- return mdiobus_write(ds->master_mii_bus, addr, reg, val);
+ return mdiobus_write(ds->master_mii_bus, ds->pd->sw_addr + addr,
+ reg, val);
}
#define REG_WRITE(addr, reg, val) \
@@ -50,7 +51,7 @@ static char *mv88e6060_probe(struct mii_bus *bus, int sw_addr)
{
int ret;
- ret = mdiobus_read(bus, REG_PORT(0), 0x03);
+ ret = mdiobus_read(bus, sw_addr + REG_PORT(0), 0x03);
if (ret >= 0) {
ret &= 0xfff0;
if (ret == 0x0600)
--
1.7.2.3
^ permalink raw reply related
* [PATCH 2/2] Define ENONAMESERVICE and ENAMEUNKNOWN to indicate name service errors
From: David Howells @ 2011-03-07 15:02 UTC (permalink / raw)
To: linux-security-module-u79uwXL29TY76Z2rM5mHXA,
keyrings-6DNke4IJHB0gsBAKwltoeQ, linux-nfs-u79uwXL29TY76Z2rM5mHXA,
linux-cifs-u79uwXL29TY76Z2rM5mHXA,
linux-afs-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-api-u79uwXL29TY76Z2rM5mHXA
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20110307150208.28218.89348.stgit-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
Now that the kernel has filesystems (and possibly other services) that want to
look up internet addresses corresponding to arbitrary hostnames retrieved from
the server, it would seem useful to provide a couple of error codes to indicate
problems with the look up, rather than overloading some other error code.
Define ENONAMESERVICE to indicate "Network name service unavailable". This can
be used to indicate, for example, that an attempt was made by dns_query() to
make a query, but the name server (e.g. a DNS server) it is supposed to contact
didn't answer or that it couldn't determine the location of a suitable server.
Define ENAMEUNKNOWN to indicate "Network name unknown". This can be used to
indicate, for example, that an attempt was made by dns_query() to make a query,
but the name server (e.g. a DNS server) replied indicating that it had no
matching records.
The DNS query upcall program can report these to keyctl_reject() so that cached
failed queries will respond with these errors until they expire.
Signed-off-by: David Howells <dhowells-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
arch/alpha/include/asm/errno.h | 2 ++
arch/mips/include/asm/errno.h | 2 ++
arch/parisc/include/asm/errno.h | 2 ++
arch/sparc/include/asm/errno.h | 2 ++
include/asm-generic/errno.h | 2 ++
5 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/arch/alpha/include/asm/errno.h b/arch/alpha/include/asm/errno.h
index 519663c..ee8a3f0 100644
--- a/arch/alpha/include/asm/errno.h
+++ b/arch/alpha/include/asm/errno.h
@@ -122,5 +122,7 @@
#define ERFKILL 138 /* Operation not possible due to RF-kill */
#define ENOAUTHSERVICE 139 /* Authentication service not available */
+#define ENONAMESERVICE 140 /* Network name service unavailable */
+#define ENAMEUNKNOWN 141 /* Network name unknown */
#endif
diff --git a/arch/mips/include/asm/errno.h b/arch/mips/include/asm/errno.h
index 5fa7fed..faed965 100644
--- a/arch/mips/include/asm/errno.h
+++ b/arch/mips/include/asm/errno.h
@@ -121,6 +121,8 @@
#define ERFKILL 167 /* Operation not possible due to RF-kill */
#define ENOAUTHSERVICE 168 /* Authentication service not available */
+#define ENONAMESERVICE 169 /* Network name service unavailable */
+#define ENAMEUNKNOWN 170 /* Network name unknown */
#define EDQUOT 1133 /* Quota exceeded */
diff --git a/arch/parisc/include/asm/errno.h b/arch/parisc/include/asm/errno.h
index 6a19346..63ee0bc 100644
--- a/arch/parisc/include/asm/errno.h
+++ b/arch/parisc/include/asm/errno.h
@@ -122,5 +122,7 @@
#define ERFKILL 256 /* Operation not possible due to RF-kill */
#define ENOAUTHSERVICE 257 /* Authentication service not available */
+#define ENONAMESERVICE 258 /* Network name service unavailable */
+#define ENAMEUNKNOWN 259 /* Network name unknown */
#endif
diff --git a/arch/sparc/include/asm/errno.h b/arch/sparc/include/asm/errno.h
index ab3a26a..f40d5ae 100644
--- a/arch/sparc/include/asm/errno.h
+++ b/arch/sparc/include/asm/errno.h
@@ -112,5 +112,7 @@
#define ERFKILL 134 /* Operation not possible due to RF-kill */
#define ENOAUTHSERVICE 135 /* Authentication service not available */
+#define ENONAMESERVICE 136 /* Network name service unavailable */
+#define ENAMEUNKNOWN 137 /* Network name unknown */
#endif
diff --git a/include/asm-generic/errno.h b/include/asm-generic/errno.h
index bcf1908..25878f1 100644
--- a/include/asm-generic/errno.h
+++ b/include/asm-generic/errno.h
@@ -108,5 +108,7 @@
#define ERFKILL 132 /* Operation not possible due to RF-kill */
#define ENOAUTHSERVICE 133 /* Authentication service not available */
+#define ENONAMESERVICE 134 /* Network name service unavailable */
+#define ENAMEUNKNOWN 135 /* Network name unknown */
#endif
^ permalink raw reply related
* [PATCH 1/2] Define ENOAUTHSERVICE to indicate "Authentication service unavailable"
From: David Howells @ 2011-03-07 15:02 UTC (permalink / raw)
To: linux-security-module-u79uwXL29TY76Z2rM5mHXA,
keyrings-6DNke4IJHB0gsBAKwltoeQ, linux-nfs-u79uwXL29TY76Z2rM5mHXA,
linux-cifs-u79uwXL29TY76Z2rM5mHXA,
linux-afs-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-api-u79uwXL29TY76Z2rM5mHXA
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
As the kernel has or will have filesystems (and possibly other services) that
want to obtain authentication tokens and/or encryption data on demand (via
GSSAPI for example), it would seem useful to provide an additional error code
to indicate a problem with the lookup, rather than overloading some other error
code.
We already have EKEYREJECTED, EKEYREVOKED and EKEYEXPIRED to indicate problems
with a token that we already have, but what if the authentication server just
isn't available?
Define ENOAUTHSERVICE to indicate "Authentication service unavailable". This
can be used to indicate, for example, that an attempt was made by request_key()
to retrieve a key, but the authentication server (e.g. a KDC) it is supposed to
contact didn't answer or that it couldn't determine the location of a suitable
server.
One way this can be used is that the user of a network filesystem can get a TGT
from the KDC and stash it in their session keyring, then the filesystem can
attempt to automatically get a ticket for accessing the filesystem - but if the
server is uncontactable then the ticket can be negatively instantiated with
KEYCTL_REJECT, giving the error to be handed to future requests as
ENOAUTHSERVICE and a small timeout so that the key will expire from the cache
and allow a retry after a short while to prevent thrashing.
Signed-off-by: David Howells <dhowells-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
arch/alpha/include/asm/errno.h | 1 +
arch/mips/include/asm/errno.h | 1 +
arch/parisc/include/asm/errno.h | 1 +
arch/sparc/include/asm/errno.h | 1 +
include/asm-generic/errno.h | 1 +
5 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/arch/alpha/include/asm/errno.h b/arch/alpha/include/asm/errno.h
index 98099bd..519663c 100644
--- a/arch/alpha/include/asm/errno.h
+++ b/arch/alpha/include/asm/errno.h
@@ -121,5 +121,6 @@
#define ENOTRECOVERABLE 137 /* State not recoverable */
#define ERFKILL 138 /* Operation not possible due to RF-kill */
+#define ENOAUTHSERVICE 139 /* Authentication service not available */
#endif
diff --git a/arch/mips/include/asm/errno.h b/arch/mips/include/asm/errno.h
index a0efc73..5fa7fed 100644
--- a/arch/mips/include/asm/errno.h
+++ b/arch/mips/include/asm/errno.h
@@ -120,6 +120,7 @@
#define ENOTRECOVERABLE 166 /* State not recoverable */
#define ERFKILL 167 /* Operation not possible due to RF-kill */
+#define ENOAUTHSERVICE 168 /* Authentication service not available */
#define EDQUOT 1133 /* Quota exceeded */
diff --git a/arch/parisc/include/asm/errno.h b/arch/parisc/include/asm/errno.h
index 9992abd..6a19346 100644
--- a/arch/parisc/include/asm/errno.h
+++ b/arch/parisc/include/asm/errno.h
@@ -121,5 +121,6 @@
#define ENOTRECOVERABLE 255 /* State not recoverable */
#define ERFKILL 256 /* Operation not possible due to RF-kill */
+#define ENOAUTHSERVICE 257 /* Authentication service not available */
#endif
diff --git a/arch/sparc/include/asm/errno.h b/arch/sparc/include/asm/errno.h
index 4e2bc49..ab3a26a 100644
--- a/arch/sparc/include/asm/errno.h
+++ b/arch/sparc/include/asm/errno.h
@@ -111,5 +111,6 @@
#define ENOTRECOVERABLE 133 /* State not recoverable */
#define ERFKILL 134 /* Operation not possible due to RF-kill */
+#define ENOAUTHSERVICE 135 /* Authentication service not available */
#endif
diff --git a/include/asm-generic/errno.h b/include/asm-generic/errno.h
index 28cc03b..bcf1908 100644
--- a/include/asm-generic/errno.h
+++ b/include/asm-generic/errno.h
@@ -107,5 +107,6 @@
#define ENOTRECOVERABLE 131 /* State not recoverable */
#define ERFKILL 132 /* Operation not possible due to RF-kill */
+#define ENOAUTHSERVICE 133 /* Authentication service not available */
#endif
^ permalink raw reply related
* [PATCH 12/17] mlx4: Add an ability to attach to QPs to GIDS by priority.
From: Yevgeny Petrilin @ 2011-03-07 10:17 UTC (permalink / raw)
To: davem; +Cc: netdev, yevgenyp, nirmu
Add an ability to attach to QPs to GIDS by priority.
The basic flow: Upon receiving a high priority attach request,
Make sure that it is put before all other low priority entries in the same
MGM hash bucket. if a low priority entry already exists for the given GID,
we'll have two entries with the same GID, which means that the low priority
entry will be ignored.
Signed-off-by: Nir Muchtar <nirmu@mellanox.co.il>
Signed-off-by: Yevgeny Petrilin <yevgenyp@mellanox.co.il>
---
drivers/infiniband/hw/mlx4/main.c | 6 +-
drivers/net/mlx4/en_netdev.c | 10 +-
drivers/net/mlx4/mcg.c | 248 +++++++++++++++++++++++++++++++++----
drivers/net/mlx4/mlx4.h | 4 +-
drivers/net/mlx4/port.c | 4 +-
include/linux/mlx4/device.h | 5 +-
6 files changed, 241 insertions(+), 36 deletions(-)
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index ecd7c95..dc6e686 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -633,7 +633,7 @@ static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
}
err = mlx4_multicast_attach(mdev->dev, &mqp->mqp, gid->raw,
!!(mqp->flags & MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK),
- MLX4_PROT_IB_IPV6);
+ MLX4_PROT_IB_IPV6, 0);
if (err)
return err;
@@ -644,7 +644,7 @@ static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
return 0;
err_add:
- mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw, MLX4_PROT_IB_IPV6);
+ mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw, MLX4_PROT_IB_IPV6, 0);
return err;
}
@@ -682,7 +682,7 @@ static int mlx4_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
}
}
err = mlx4_multicast_detach(mdev->dev,
- &mqp->mqp, gid->raw, MLX4_PROT_IB_IPV6);
+ &mqp->mqp, gid->raw, MLX4_PROT_IB_IPV6, 0);
if (err)
return err;
diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c
index 0da4b7b..4a30047 100644
--- a/drivers/net/mlx4/en_netdev.c
+++ b/drivers/net/mlx4/en_netdev.c
@@ -345,7 +345,7 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
memcpy(&mc_list[10], priv->mc_addrs + i * ETH_ALEN, ETH_ALEN);
mc_list[5] = priv->port;
mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp,
- mc_list, MLX4_PROT_ETH);
+ mc_list, MLX4_PROT_ETH, 0);
}
/* Flush mcast filter and init it with broadcast address */
mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, ETH_BCAST,
@@ -362,7 +362,7 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
memcpy(&mc_list[10], priv->mc_addrs + i * ETH_ALEN, ETH_ALEN);
mc_list[5] = priv->port;
mlx4_multicast_attach(mdev->dev, &priv->rss_map.indir_qp,
- mc_list, 0, MLX4_PROT_ETH);
+ mc_list, 0, MLX4_PROT_ETH, 0);
mlx4_SET_MCAST_FLTR(mdev->dev, priv->port,
mcast_addr, 0, MLX4_MCAST_CONFIG);
}
@@ -739,7 +739,7 @@ int mlx4_en_start_port(struct net_device *dev)
memset(&mc_list[10], 0xff, ETH_ALEN);
mc_list[5] = priv->port;
if (mlx4_multicast_attach(mdev->dev, &priv->rss_map.indir_qp, mc_list,
- 0, MLX4_PROT_ETH))
+ 0, MLX4_PROT_ETH, 0))
mlx4_warn(mdev, "Failed Attaching Broadcast\n");
/* Schedule multicast task to populate multicast list */
@@ -792,12 +792,12 @@ void mlx4_en_stop_port(struct net_device *dev)
memset(&mc_list[10], 0xff, ETH_ALEN);
mc_list[5] = priv->port;
mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp, mc_list,
- MLX4_PROT_ETH);
+ MLX4_PROT_ETH, 0);
for (i = 0; i < priv->mc_addrs_cnt; i++) {
memcpy(&mc_list[10], priv->mc_addrs + i * ETH_ALEN, ETH_ALEN);
mc_list[5] = priv->port;
mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp,
- mc_list, MLX4_PROT_ETH);
+ mc_list, MLX4_PROT_ETH, 0);
}
mlx4_en_clear_list(dev);
/* Flush multicast filter */
diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c
index e71372a..5b00b15 100644
--- a/drivers/net/mlx4/mcg.c
+++ b/drivers/net/mlx4/mcg.c
@@ -43,6 +43,12 @@
static const u8 zero_gid[16]; /* automatically initialized to 0 */
+struct mlx4_steer_prio {
+ struct list_head list;
+ int hash;
+ u32 num_high_prio;
+};
+
static int mlx4_READ_ENTRY(struct mlx4_dev *dev, int index,
struct mlx4_cmd_mailbox *mailbox)
{
@@ -331,6 +337,25 @@ out:
return ret;
}
+/* Adjust the index of an existing steering entry*/
+static void adjust_steering_entry(struct mlx4_dev *dev, u8 vep_num, u8 port,
+ enum mlx4_steer_type steer,
+ unsigned int old_index, unsigned int new_index)
+{
+ struct mlx4_steer *s_steer;
+ u8 pf_num;
+ struct mlx4_steer_index *entry;
+
+ pf_num = (dev->caps.num_ports == 1) ? vep_num : (vep_num << 1) | (port - 1);
+ s_steer = &mlx4_priv(dev)->steer[pf_num];
+ list_for_each_entry(entry, &s_steer->steer_entries[steer], list) {
+ if (entry->index == old_index) {
+ entry->index = new_index;
+ return;
+ }
+ }
+}
+
static int add_promisc_qp(struct mlx4_dev *dev, u8 vep_num, u8 port,
enum mlx4_steer_type steer, u32 qpn)
{
@@ -533,6 +558,125 @@ out_mutex:
return err;
}
+static int set_num_high_prio(struct mlx4_dev *dev, u8 port, int hash, int val,
+ enum mlx4_protocol prot)
+{
+ struct mlx4_steer_prio *high_prio, *prev_high_prio;
+ struct list_head *high_prios;
+
+ if (prot != MLX4_PROT_ETH || port > dev->caps.num_ports)
+ return -EINVAL;
+
+ high_prios = &mlx4_priv(dev)->steer[port - 1].high_prios;
+ list_for_each_entry_safe(high_prio, prev_high_prio, high_prios, list) {
+ if (high_prio->hash == hash) {
+ high_prio->num_high_prio += val;
+ if (!high_prio->num_high_prio) {
+ list_del(&high_prio->list);
+ kfree(high_prio);
+ }
+ return 0;
+ }
+ }
+ high_prio = kmalloc(sizeof *high_prio, GFP_KERNEL);
+ if (!high_prio)
+ return -ENOMEM;
+ high_prio->hash = hash;
+ high_prio->num_high_prio = val;
+ list_add_tail(&high_prio->list, high_prios);
+ return 0;
+}
+
+static int inc_num_high_prio(struct mlx4_dev *dev, u8 port, int hash,
+ enum mlx4_protocol prot)
+{
+ return set_num_high_prio(dev, port, hash, 1, prot);
+}
+
+static int dec_num_high_prio(struct mlx4_dev *dev, u8 port, int hash,
+ enum mlx4_protocol prot)
+{
+ return set_num_high_prio(dev, port, hash, -1, prot);
+}
+
+static u32 get_num_high_prio(struct mlx4_dev *dev, u8 port, int hash,
+ enum mlx4_protocol prot)
+{
+ struct mlx4_steer_prio *high_prio;
+ struct list_head *high_prios;
+
+ if (prot != MLX4_PROT_ETH || port > dev->caps.num_ports)
+ return 0;
+ high_prios = &mlx4_priv(dev)->steer[port - 1].high_prios;
+ list_for_each_entry(high_prio, high_prios, list) {
+ if (high_prio->hash == hash)
+ return high_prio->num_high_prio;
+ }
+ return 0;
+}
+
+/* Find and return the first MGM/AMGM entry which is not of high priority */
+/* TODO merge with find_entry */
+static int find_first_low_entry(struct mlx4_dev *dev, u8 port,
+ u8 *gid, enum mlx4_protocol prot,
+ struct mlx4_cmd_mailbox *mgm_mailbox,
+ u16 *hash, int *prev, int *index)
+{
+ struct mlx4_cmd_mailbox *mailbox;
+ struct mlx4_mgm *mgm = mgm_mailbox->buf;
+ u8 *mgid;
+ int err;
+ u8 op_mod = (prot == MLX4_PROT_ETH) ? !!(dev->caps.vep_mc_steering) : 0;
+ int high_prio_left;
+
+ mailbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(mailbox))
+ return -ENOMEM;
+ mgid = mailbox->buf;
+
+ memcpy(mgid, gid, 16);
+
+ err = mlx4_GID_HASH(dev, mailbox, hash, op_mod);
+ mlx4_free_cmd_mailbox(dev, mailbox);
+ if (err)
+ return err;
+
+ *index = *hash;
+ *prev = -1;
+
+ high_prio_left = get_num_high_prio(dev, port, *index, prot);
+
+ do {
+ err = mlx4_READ_ENTRY(dev, *index, mgm_mailbox);
+ if (err)
+ return err;
+
+ if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) {
+ if (*index != *hash) {
+ mlx4_err(dev, "Found zero MGID in AMGM.\n");
+ err = -EINVAL;
+ } else if (high_prio_left) {
+ mlx4_err(dev, "Invalid high prio entries.\n");
+ err = -EINVAL;
+ }
+ return err;
+ }
+
+ if (!high_prio_left)
+ return err;
+
+ *prev = *index;
+ *index = be32_to_cpu(mgm->next_gid_index) >> 6;
+ high_prio_left--;
+ } while (*index);
+ if (high_prio_left) {
+ mlx4_err(dev, "Not enough high prio MGIDs in MGM.\n");
+ return -EINVAL;
+ }
+ *index = -1;
+ return err;
+}
+
/*
* Caller must hold MCG table semaphore. gid and mgm parameters must
* be properly aligned for command interface.
@@ -550,7 +694,7 @@ out_mutex:
*/
static int find_entry(struct mlx4_dev *dev, u8 port,
u8 *gid, enum mlx4_protocol prot,
- enum mlx4_steer_type steer,
+ enum mlx4_steer_type steer, u8 high_prio,
struct mlx4_cmd_mailbox *mgm_mailbox,
u16 *hash, int *prev, int *index)
{
@@ -559,6 +703,7 @@ static int find_entry(struct mlx4_dev *dev, u8 port,
u8 *mgid;
int err;
u8 op_mod = (prot == MLX4_PROT_ETH) ? !!(dev->caps.vep_mc_steering) : 0;
+ int high_prio_left = 0;
mailbox = mlx4_alloc_cmd_mailbox(dev);
if (IS_ERR(mailbox))
@@ -578,6 +723,11 @@ static int find_entry(struct mlx4_dev *dev, u8 port,
*index = *hash;
*prev = -1;
+ /* We distinguish low from high priority entries by keeping the high
+ entries before the low entries and saving their number */
+
+ high_prio_left = get_num_high_prio(dev, port, *hash, prot);
+
do {
err = mlx4_READ_ENTRY(dev, *index, mgm_mailbox);
if (err)
@@ -592,11 +742,14 @@ static int find_entry(struct mlx4_dev *dev, u8 port,
}
if (!memcmp(mgm->gid, gid, 16) &&
- be32_to_cpu(mgm->members_count) >> 30 == prot)
+ (be32_to_cpu(mgm->members_count) >> 30 == prot) &&
+ ((high_prio && high_prio_left > 0) ||
+ (!high_prio && high_prio_left <= 0)))
return err;
*prev = *index;
*index = be32_to_cpu(mgm->next_gid_index) >> 6;
+ high_prio_left--;
} while (*index);
*index = -1;
@@ -605,19 +758,21 @@ static int find_entry(struct mlx4_dev *dev, u8 port,
int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
int block_mcast_loopback, enum mlx4_protocol prot,
- enum mlx4_steer_type steer)
+ enum mlx4_steer_type steer, u8 high_prio)
{
struct mlx4_priv *priv = mlx4_priv(dev);
- struct mlx4_cmd_mailbox *mailbox;
- struct mlx4_mgm *mgm;
+ struct mlx4_cmd_mailbox *mailbox, *low_mailbox = NULL;
+ struct mlx4_mgm *mgm, *low_mgm;
u32 members_count;
u16 hash;
int index, prev;
+ int low_index = -1, low_prev;
int link = 0;
int i;
int err;
u8 port = gid[5];
u8 new_entry = 0;
+ u8 low_to_high = 0;
mailbox = mlx4_alloc_cmd_mailbox(dev);
if (IS_ERR(mailbox))
@@ -625,7 +780,7 @@ int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
mgm = mailbox->buf;
mutex_lock(&priv->mcg_table.mutex);
- err = find_entry(dev, port, gid, prot, steer,
+ err = find_entry(dev, port, gid, prot, steer, high_prio,
mailbox, &hash, &prev, &index);
if (err)
goto out;
@@ -637,6 +792,7 @@ int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
}
} else {
link = 1;
+ new_entry = 1;
index = mlx4_bitmap_alloc(&priv->mcg_table.bitmap);
if (index == -1) {
@@ -648,31 +804,68 @@ int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
memset(mgm, 0, sizeof *mgm);
memcpy(mgm->gid, gid, 16);
+
+ /* if High priority attach was requested, we want to keep it
+ before low entries, so we take the first low priority entry
+ and swap it for our newly created entry (which is last) */
+ if (high_prio) {
+ mlx4_dbg(dev, "High priority steer was requested\n");
+ low_mailbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(low_mailbox)) {
+ err = PTR_ERR(low_mailbox);
+ low_mailbox = NULL;
+ goto out;
+ }
+ err = find_first_low_entry(dev, port, gid, prot,
+ low_mailbox, &hash,
+ &low_prev, &low_index);
+ if (!err && low_index != -1) {
+ low_to_high = 1;
+ low_mgm = low_mailbox->buf;
+ mlx4_dbg(dev, "Found a low prio steering entry. Switching entries\n");
+ memcpy(mgm->gid, low_mgm->gid, 16);
+ mgm->members_count = low_mgm->members_count;
+ memcpy(mgm->qp, low_mgm->qp,
+ (be32_to_cpu(mgm->members_count) & 0xffffff) * sizeof low_mgm->qp[0]);
+ low_mgm->members_count = 0;
+ memcpy(low_mgm->gid, gid, 16);
+ err = mlx4_WRITE_ENTRY(dev, index, mailbox);
+ if (err)
+ goto out;
+ adjust_steering_entry(dev, 0, port, steer, low_index, index);
+ }
+ }
}
- members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
+ if (!low_to_high) {
+ low_mgm = mgm;
+ low_index = index;
+ low_mailbox = mailbox;
+ }
+
+ members_count = be32_to_cpu(low_mgm->members_count) & 0xffffff;
if (members_count == MLX4_QP_PER_MGM) {
- mlx4_err(dev, "MGM at index %x is full.\n", index);
+ mlx4_err(dev, "MGM at index %x is full.\n", low_index);
err = -ENOMEM;
goto out;
}
for (i = 0; i < members_count; ++i)
- if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) {
+ if ((be32_to_cpu(low_mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) {
mlx4_dbg(dev, "QP %06x already a member of MGM\n", qp->qpn);
err = 0;
goto out;
}
if (block_mcast_loopback)
- mgm->qp[members_count++] = cpu_to_be32((qp->qpn & MGM_QPN_MASK) |
+ low_mgm->qp[members_count++] = cpu_to_be32((qp->qpn & MGM_QPN_MASK) |
(1U << MGM_BLCK_LB_BIT));
else
- mgm->qp[members_count++] = cpu_to_be32(qp->qpn & MGM_QPN_MASK);
+ low_mgm->qp[members_count++] = cpu_to_be32(qp->qpn & MGM_QPN_MASK);
- mgm->members_count = cpu_to_be32(members_count | (u32) prot << 30);
+ low_mgm->members_count = cpu_to_be32(members_count | (u32) prot << 30);
- err = mlx4_WRITE_ENTRY(dev, index, mailbox);
+ err = mlx4_WRITE_ENTRY(dev, low_index, low_mailbox);
if (err)
goto out;
@@ -688,15 +881,19 @@ int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
err = mlx4_WRITE_ENTRY(dev, prev, mailbox);
if (err)
goto out;
+ if (high_prio)
+ err = inc_num_high_prio(dev, port, hash, prot);
+ if (err)
+ goto out;
out:
if (prot == MLX4_PROT_ETH) {
/* manage the steering entry for promisc mode */
if (new_entry)
- new_steering_entry(dev, 0, port, steer, index, qp->qpn);
+ new_steering_entry(dev, 0, port, steer, low_index, qp->qpn);
else
existing_steering_entry(dev, 0, port, steer,
- index, qp->qpn);
+ low_index, qp->qpn);
}
if (err && link && index != -1) {
if (index < dev->caps.num_mgms)
@@ -709,11 +906,14 @@ out:
mutex_unlock(&priv->mcg_table.mutex);
mlx4_free_cmd_mailbox(dev, mailbox);
+ if (low_to_high && low_mailbox)
+ mlx4_free_cmd_mailbox(dev, low_mailbox);
return err;
}
int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
- enum mlx4_protocol prot, enum mlx4_steer_type steer)
+ enum mlx4_protocol prot, enum mlx4_steer_type steer,
+ u8 high_prio)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_cmd_mailbox *mailbox;
@@ -733,7 +933,7 @@ int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
mutex_lock(&priv->mcg_table.mutex);
- err = find_entry(dev, port, gid, prot, steer,
+ err = find_entry(dev, port, gid, prot, steer, high_prio,
mailbox, &hash, &prev, &index);
if (err)
goto out;
@@ -780,6 +980,8 @@ int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6;
if (amgm_index) {
err = mlx4_READ_ENTRY(dev, amgm_index, mailbox);
+ if (!memcmp(mgm->gid, gid, 16))
+ adjust_steering_entry(dev, 0, port, steer, amgm_index, index);
if (err)
goto out;
} else
@@ -817,7 +1019,8 @@ int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
mlx4_bitmap_free(&priv->mcg_table.bitmap,
index - dev->caps.num_mgms);
}
-
+ if (high_prio)
+ dec_num_high_prio(dev, port, hash, prot);
out:
mutex_unlock(&priv->mcg_table.mutex);
@@ -827,7 +1030,8 @@ out:
int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
- int block_mcast_loopback, enum mlx4_protocol prot)
+ int block_mcast_loopback, enum mlx4_protocol prot,
+ u8 high_prio)
{
enum mlx4_steer_type steer;
@@ -841,12 +1045,12 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
return mlx4_qp_attach_common(dev, qp, gid,
block_mcast_loopback, prot,
- steer);
+ steer, high_prio);
}
EXPORT_SYMBOL_GPL(mlx4_multicast_attach);
int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
- enum mlx4_protocol prot)
+ enum mlx4_protocol prot, u8 high_prio)
{
enum mlx4_steer_type steer;
@@ -859,7 +1063,7 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
gid[7] |= (steer << 1);
}
- return mlx4_qp_detach_common(dev, qp, gid, prot, steer);
+ return mlx4_qp_detach_common(dev, qp, gid, prot, steer, high_prio);
}
EXPORT_SYMBOL_GPL(mlx4_multicast_detach);
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
index d8bb441..a50923a 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/mlx4/mlx4.h
@@ -444,8 +444,8 @@ int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port);
int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps);
int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
- enum mlx4_protocol prot, enum mlx4_steer_type steer);
+ enum mlx4_protocol prot, enum mlx4_steer_type steer, u8 high_prio);
int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
int block_mcast_loopback, enum mlx4_protocol prot,
- enum mlx4_steer_type steer);
+ enum mlx4_steer_type steer, u8 high_prio);
#endif /* MLX4_H */
diff --git a/drivers/net/mlx4/port.c b/drivers/net/mlx4/port.c
index eca7d85..6148195 100644
--- a/drivers/net/mlx4/port.c
+++ b/drivers/net/mlx4/port.c
@@ -113,7 +113,7 @@ static int mlx4_uc_steer_add(struct mlx4_dev *dev, u8 port,
gid[7] = MLX4_UC_STEER << 1;
err = mlx4_qp_attach_common(dev, &qp, gid, 0,
- MLX4_PROT_ETH, MLX4_UC_STEER);
+ MLX4_PROT_ETH, MLX4_UC_STEER, 0);
if (err && reserve)
mlx4_qp_release_range(dev, *qpn, 1);
@@ -133,7 +133,7 @@ static void mlx4_uc_steer_release(struct mlx4_dev *dev, u8 port,
gid[5] = port;
gid[7] = MLX4_UC_STEER << 1;
- mlx4_qp_detach_common(dev, &qp, gid, MLX4_PROT_ETH, MLX4_UC_STEER);
+ mlx4_qp_detach_common(dev, &qp, gid, MLX4_PROT_ETH, MLX4_UC_STEER, 0);
if (free)
mlx4_qp_release_range(dev, qpn, 1);
}
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index 56fa5e1..f1cb31b 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -522,9 +522,10 @@ int mlx4_INIT_PORT(struct mlx4_dev *dev, int port);
int mlx4_CLOSE_PORT(struct mlx4_dev *dev, int port);
int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
- int block_mcast_loopback, enum mlx4_protocol protocol);
+ int block_mcast_loopback, enum mlx4_protocol protocol,
+ u8 high_prio);
int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
- enum mlx4_protocol protocol);
+ enum mlx4_protocol protocol, u8 high_prio);
int mlx4_multicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port);
int mlx4_multicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port);
int mlx4_unicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port);
--
1.6.0.2
^ permalink raw reply related
* [PATCH 03/17] mlx4_en: optimize adaptive moderation algorithm for better latency
From: Yevgeny Petrilin @ 2011-03-07 10:17 UTC (permalink / raw)
To: davem; +Cc: netdev, yevgenyp
Signed-off-by: Yevgeny Petrilin <yevgenyp@mellanox.co.il>
---
drivers/net/mlx4/en_netdev.c | 18 +++++-------------
drivers/net/mlx4/mlx4_en.h | 1 +
2 files changed, 6 insertions(+), 13 deletions(-)
diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c
index 56627c2..b1180dd 100644
--- a/drivers/net/mlx4/en_netdev.c
+++ b/drivers/net/mlx4/en_netdev.c
@@ -417,7 +417,6 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv)
unsigned long avg_pkt_size;
unsigned long rx_packets;
unsigned long rx_bytes;
- unsigned long rx_byte_diff;
unsigned long tx_packets;
unsigned long tx_pkt_diff;
unsigned long rx_pkt_diff;
@@ -441,25 +440,20 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv)
rx_pkt_diff = ((unsigned long) (rx_packets -
priv->last_moder_packets));
packets = max(tx_pkt_diff, rx_pkt_diff);
- rx_byte_diff = rx_bytes - priv->last_moder_bytes;
- rx_byte_diff = rx_byte_diff ? rx_byte_diff : 1;
rate = packets * HZ / period;
avg_pkt_size = packets ? ((unsigned long) (rx_bytes -
priv->last_moder_bytes)) / packets : 0;
/* Apply auto-moderation only when packet rate exceeds a rate that
* it matters */
- if (rate > MLX4_EN_RX_RATE_THRESH) {
+ if (rate > MLX4_EN_RX_RATE_THRESH && avg_pkt_size > MLX4_EN_AVG_PKT_SMALL) {
/* If tx and rx packet rates are not balanced, assume that
* traffic is mainly BW bound and apply maximum moderation.
* Otherwise, moderate according to packet rate */
- if (2 * tx_pkt_diff > 3 * rx_pkt_diff &&
- rx_pkt_diff / rx_byte_diff <
- MLX4_EN_SMALL_PKT_SIZE)
- moder_time = priv->rx_usecs_low;
- else if (2 * rx_pkt_diff > 3 * tx_pkt_diff)
+ if (2 * tx_pkt_diff > 3 * rx_pkt_diff ||
+ 2 * rx_pkt_diff > 3 * tx_pkt_diff) {
moder_time = priv->rx_usecs_high;
- else {
+ } else {
if (rate < priv->pkt_rate_low)
moder_time = priv->rx_usecs_low;
else if (rate > priv->pkt_rate_high)
@@ -471,9 +465,7 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv)
priv->rx_usecs_low;
}
} else {
- /* When packet rate is low, use default moderation rather than
- * 0 to prevent interrupt storms if traffic suddenly increases */
- moder_time = priv->rx_usecs;
+ moder_time = priv->rx_usecs_low;
}
en_dbg(INTR, priv, "tx rate:%lu rx_rate:%lu\n",
diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h
index dfed6a0..5387c4e 100644
--- a/drivers/net/mlx4/mlx4_en.h
+++ b/drivers/net/mlx4/mlx4_en.h
@@ -124,6 +124,7 @@ enum {
#define MLX4_EN_RX_SIZE_THRESH 1024
#define MLX4_EN_RX_RATE_THRESH (1000000 / MLX4_EN_RX_COAL_TIME_HIGH)
#define MLX4_EN_SAMPLE_INTERVAL 0
+#define MLX4_EN_AVG_PKT_SMALL 256
#define MLX4_EN_AUTO_CONF 0xffff
--
1.6.0.2
^ permalink raw reply related
* [PATCH 14/17] mlx4_core: maintain available field in bitmap allocator
From: Yevgeny Petrilin @ 2011-03-07 10:17 UTC (permalink / raw)
To: davem; +Cc: netdev, yevgenyp, eli
From: Eli Cohen <eli@mellanox.co.il>
Add mlx4_bitmap_avail() to give the number of available resources. We want to
use this as a hint to whether to allocate a resources or not. This patch is
introduced to be used with allocation blue flame registers.
Signed-off-by: Eli Cohen <eli@mellanox.co.il>
Signed-off-by: Yevgeny Petrilin <yevgenyp@mellanox.co.il>
---
drivers/net/mlx4/alloc.c | 13 +++++++++++++
drivers/net/mlx4/mlx4.h | 2 ++
2 files changed, 15 insertions(+), 0 deletions(-)
diff --git a/drivers/net/mlx4/alloc.c b/drivers/net/mlx4/alloc.c
index 3a4277f..116cae3 100644
--- a/drivers/net/mlx4/alloc.c
+++ b/drivers/net/mlx4/alloc.c
@@ -62,6 +62,9 @@ u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap)
} else
obj = -1;
+ if (obj != -1)
+ --bitmap->avail;
+
spin_unlock(&bitmap->lock);
return obj;
@@ -101,11 +104,19 @@ u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align)
} else
obj = -1;
+ if (obj != -1)
+ bitmap->avail -= cnt;
+
spin_unlock(&bitmap->lock);
return obj;
}
+u32 mlx4_bitmap_avail(struct mlx4_bitmap *bitmap)
+{
+ return bitmap->avail;
+}
+
void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt)
{
obj &= bitmap->max + bitmap->reserved_top - 1;
@@ -115,6 +126,7 @@ void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt)
bitmap->last = min(bitmap->last, obj);
bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top)
& bitmap->mask;
+ bitmap->avail += cnt;
spin_unlock(&bitmap->lock);
}
@@ -130,6 +142,7 @@ int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask,
bitmap->max = num - reserved_top;
bitmap->mask = mask;
bitmap->reserved_top = reserved_top;
+ bitmap->avail = num - reserved_top - reserved_bot;
spin_lock_init(&bitmap->lock);
bitmap->table = kzalloc(BITS_TO_LONGS(bitmap->max) *
sizeof (long), GFP_KERNEL);
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
index 008bf95..6277133 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/mlx4/mlx4.h
@@ -105,6 +105,7 @@ struct mlx4_bitmap {
u32 max;
u32 reserved_top;
u32 mask;
+ u32 avail;
spinlock_t lock;
unsigned long *table;
};
@@ -371,6 +372,7 @@ u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap);
void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj);
u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align);
void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt);
+u32 mlx4_bitmap_avail(struct mlx4_bitmap *bitmap);
int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask,
u32 reserved_bot, u32 resetrved_top);
void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap);
--
1.6.0.2
^ permalink raw reply related
* [PATCH 10/17] mlx4: Add support for promiscuous mode in the new steering model.
From: Yevgeny Petrilin @ 2011-03-07 10:17 UTC (permalink / raw)
To: davem; +Cc: netdev, yevgenyp, vlad
For Ethernet mode only,
When we want to register QP as promiscuous, it must be added to all the
existing steering entries and also to the default one.
The promiscuous QP might also be on of "real" QPs,
which means we need to monitor every entry to avoid duplicates and ensure
we close an entry when all it has is promiscuous QPs.
Same mechanism both for unicast and multicast.
Signed-off-by: Vladimir Sokolovsky <vlad@mellanox.co.il>
Signed-off-by: Yevgeny Petrilin <yevgenyp@mellanox.co.il>
---
drivers/net/mlx4/main.c | 63 ++++++-
drivers/net/mlx4/mcg.c | 535 ++++++++++++++++++++++++++++++++++++++++++++++-
drivers/net/mlx4/mlx4.h | 33 +++
3 files changed, 620 insertions(+), 11 deletions(-)
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index da0da28..c8e2761 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -1063,6 +1063,59 @@ static void mlx4_cleanup_port_info(struct mlx4_port_info *info)
device_remove_file(&info->dev->pdev->dev, &info->port_attr);
}
+static int mlx4_init_steering(struct mlx4_dev *dev)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ int num_entries = dev->caps.num_ports;
+ int i, j;
+
+ priv->steer = kzalloc(sizeof(struct mlx4_steer) * num_entries, GFP_KERNEL);
+ if (!priv->steer)
+ return -ENOMEM;
+
+ for (i = 0; i < num_entries; i++) {
+ for (j = 0; j < MLX4_NUM_STEERS; j++) {
+ INIT_LIST_HEAD(&priv->steer[i].promisc_qps[j]);
+ INIT_LIST_HEAD(&priv->steer[i].steer_entries[j]);
+ }
+ INIT_LIST_HEAD(&priv->steer[i].high_prios);
+ }
+ return 0;
+}
+
+static void mlx4_clear_steering(struct mlx4_dev *dev)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_steer_index *entry, *tmp_entry;
+ struct mlx4_promisc_qp *pqp, *tmp_pqp;
+ int num_entries = dev->caps.num_ports;
+ int i, j;
+
+ for (i = 0; i < num_entries; i++) {
+ for (j = 0; j < MLX4_NUM_STEERS; j++) {
+ list_for_each_entry_safe(pqp, tmp_pqp,
+ &priv->steer[i].promisc_qps[j],
+ list) {
+ list_del(&pqp->list);
+ kfree(pqp);
+ }
+ list_for_each_entry_safe(entry, tmp_entry,
+ &priv->steer[i].steer_entries[j],
+ list) {
+ list_del(&entry->list);
+ list_for_each_entry_safe(pqp, tmp_pqp,
+ &entry->duplicates,
+ list) {
+ list_del(&pqp->list);
+ kfree(pqp);
+ }
+ kfree(entry);
+ }
+ }
+ }
+ kfree(priv->steer);
+}
+
static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct mlx4_priv *priv;
@@ -1172,6 +1225,10 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
mlx4_enable_msi_x(dev);
+ err = mlx4_init_steering(dev);
+ if (err)
+ goto err_free_eq;
+
err = mlx4_setup_hca(dev);
if (err == -EBUSY && (dev->flags & MLX4_FLAG_MSI_X)) {
dev->flags &= ~MLX4_FLAG_MSI_X;
@@ -1180,7 +1237,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
}
if (err)
- goto err_free_eq;
+ goto err_steer;
for (port = 1; port <= dev->caps.num_ports; port++) {
err = mlx4_init_port_info(dev, port);
@@ -1213,6 +1270,9 @@ err_port:
mlx4_cleanup_pd_table(dev);
mlx4_cleanup_uar_table(dev);
+err_steer:
+ mlx4_clear_steering(dev);
+
err_free_eq:
mlx4_free_eq_table(dev);
@@ -1272,6 +1332,7 @@ static void mlx4_remove_one(struct pci_dev *pdev)
iounmap(priv->kar);
mlx4_uar_free(dev, &priv->driver_uar);
mlx4_cleanup_uar_table(dev);
+ mlx4_clear_steering(dev);
mlx4_free_eq_table(dev);
mlx4_close_hca(dev);
mlx4_cmd_cleanup(dev);
diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c
index b103ad2..e71372a 100644
--- a/drivers/net/mlx4/mcg.c
+++ b/drivers/net/mlx4/mcg.c
@@ -41,14 +41,6 @@
#define MGM_QPN_MASK 0x00FFFFFF
#define MGM_BLCK_LB_BIT 30
-struct mlx4_mgm {
- __be32 next_gid_index;
- __be32 members_count;
- u32 reserved[2];
- u8 gid[16];
- __be32 qp[MLX4_QP_PER_MGM];
-};
-
static const u8 zero_gid[16]; /* automatically initialized to 0 */
static int mlx4_READ_ENTRY(struct mlx4_dev *dev, int index,
@@ -65,6 +57,16 @@ static int mlx4_WRITE_ENTRY(struct mlx4_dev *dev, int index,
MLX4_CMD_TIME_CLASS_A);
}
+static int mlx4_WRITE_PROMISC(struct mlx4_dev *dev, u8 vep_num, u8 port, u8 steer,
+ struct mlx4_cmd_mailbox *mailbox)
+{
+ u32 in_mod;
+
+ in_mod = (u32) vep_num << 24 | (u32) port << 16 | steer << 1;
+ return mlx4_cmd(dev, mailbox->dma, in_mod, 0x1,
+ MLX4_CMD_WRITE_MCG, MLX4_CMD_TIME_CLASS_A);
+}
+
static int mlx4_GID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
u16 *hash, u8 op_mod)
{
@@ -80,6 +82,457 @@ static int mlx4_GID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
return err;
}
+static struct mlx4_promisc_qp *get_promisc_qp(struct mlx4_dev *dev, u8 pf_num,
+ enum mlx4_steer_type steer,
+ u32 qpn)
+{
+ struct mlx4_steer *s_steer = &mlx4_priv(dev)->steer[pf_num];
+ struct mlx4_promisc_qp *pqp;
+
+ list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) {
+ if (pqp->qpn == qpn)
+ return pqp;
+ }
+ /* not found */
+ return NULL;
+}
+
+/*
+ * Add new entry to steering data structure.
+ * All promisc QPs should be added as well
+ */
+static int new_steering_entry(struct mlx4_dev *dev, u8 vep_num, u8 port,
+ enum mlx4_steer_type steer,
+ unsigned int index, u32 qpn)
+{
+ struct mlx4_steer *s_steer;
+ struct mlx4_cmd_mailbox *mailbox;
+ struct mlx4_mgm *mgm;
+ u32 members_count;
+ struct mlx4_steer_index *new_entry;
+ struct mlx4_promisc_qp *pqp;
+ struct mlx4_promisc_qp *dqp;
+ u32 prot;
+ int err;
+ u8 pf_num;
+
+ pf_num = (dev->caps.num_ports == 1) ? vep_num : (vep_num << 1) | (port - 1);
+ s_steer = &mlx4_priv(dev)->steer[pf_num];
+ new_entry = kzalloc(sizeof *new_entry, GFP_KERNEL);
+ if (!new_entry)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&new_entry->duplicates);
+ new_entry->index = index;
+ list_add_tail(&new_entry->list, &s_steer->steer_entries[steer]);
+
+ /* If the given qpn is also a promisc qp,
+ * it should be inserted to duplicates list
+ */
+ pqp = get_promisc_qp(dev, pf_num, steer, qpn);
+ if (pqp) {
+ dqp = kmalloc(sizeof *dqp, GFP_KERNEL);
+ if (!dqp) {
+ err = -ENOMEM;
+ goto out_alloc;
+ }
+ dqp->qpn = qpn;
+ list_add_tail(&dqp->list, &new_entry->duplicates);
+ }
+
+ /* if no promisc qps for this vep, we are done */
+ if (list_empty(&s_steer->promisc_qps[steer]))
+ return 0;
+
+ /* now need to add all the promisc qps to the new
+ * steering entry, as they should also receive the packets
+ * destined to this address */
+ mailbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(mailbox)) {
+ err = -ENOMEM;
+ goto out_alloc;
+ }
+ mgm = mailbox->buf;
+
+ err = mlx4_READ_ENTRY(dev, index, mailbox);
+ if (err)
+ goto out_mailbox;
+
+ members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
+ prot = be32_to_cpu(mgm->members_count) >> 30;
+ list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) {
+ /* don't add already existing qpn */
+ if (pqp->qpn == qpn)
+ continue;
+ if (members_count == MLX4_QP_PER_MGM) {
+ /* out of space */
+ err = -ENOMEM;
+ goto out_mailbox;
+ }
+
+ /* add the qpn */
+ mgm->qp[members_count++] = cpu_to_be32(pqp->qpn & MGM_QPN_MASK);
+ }
+ /* update the qps count and update the entry with all the promisc qps*/
+ mgm->members_count = cpu_to_be32(members_count | (prot << 30));
+ err = mlx4_WRITE_ENTRY(dev, index, mailbox);
+
+out_mailbox:
+ mlx4_free_cmd_mailbox(dev, mailbox);
+ if (!err)
+ return 0;
+out_alloc:
+ if (dqp) {
+ list_del(&dqp->list);
+ kfree(&dqp);
+ }
+ list_del(&new_entry->list);
+ kfree(new_entry);
+ return err;
+}
+
+/* update the data structures with existing steering entry */
+static int existing_steering_entry(struct mlx4_dev *dev, u8 vep_num, u8 port,
+ enum mlx4_steer_type steer,
+ unsigned int index, u32 qpn)
+{
+ struct mlx4_steer *s_steer;
+ struct mlx4_steer_index *tmp_entry, *entry = NULL;
+ struct mlx4_promisc_qp *pqp;
+ struct mlx4_promisc_qp *dqp;
+ u8 pf_num;
+
+ pf_num = (dev->caps.num_ports == 1) ? vep_num : (vep_num << 1) | (port - 1);
+ s_steer = &mlx4_priv(dev)->steer[pf_num];
+
+ pqp = get_promisc_qp(dev, pf_num, steer, qpn);
+ if (!pqp)
+ return 0; /* nothing to do */
+
+ list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) {
+ if (tmp_entry->index == index) {
+ entry = tmp_entry;
+ break;
+ }
+ }
+ if (unlikely(!entry)) {
+ mlx4_warn(dev, "Steering entry at index %x is not registered\n", index);
+ return -EINVAL;
+ }
+
+ /* the given qpn is listed as a promisc qpn
+ * we need to add it as a duplicate to this entry
+ * for future refernce */
+ list_for_each_entry(dqp, &entry->duplicates, list) {
+ if (qpn == dqp->qpn)
+ return 0; /* qp is already duplicated */
+ }
+
+ /* add the qp as a duplicate on this index */
+ dqp = kmalloc(sizeof *dqp, GFP_KERNEL);
+ if (!dqp)
+ return -ENOMEM;
+ dqp->qpn = qpn;
+ list_add_tail(&dqp->list, &entry->duplicates);
+
+ return 0;
+}
+
+/* Check whether a qpn is a duplicate on steering entry
+ * If so, it should not be removed from mgm */
+static bool check_duplicate_entry(struct mlx4_dev *dev, u8 vep_num, u8 port,
+ enum mlx4_steer_type steer,
+ unsigned int index, u32 qpn)
+{
+ struct mlx4_steer *s_steer;
+ struct mlx4_steer_index *tmp_entry, *entry = NULL;
+ struct mlx4_promisc_qp *dqp, *tmp_dqp;
+ u8 pf_num;
+
+ pf_num = (dev->caps.num_ports == 1) ? vep_num : (vep_num << 1) | (port - 1);
+ s_steer = &mlx4_priv(dev)->steer[pf_num];
+
+ /* if qp is not promisc, it cannot be duplicated */
+ if (!get_promisc_qp(dev, pf_num, steer, qpn))
+ return false;
+
+ /* The qp is promisc qp so it is a duplicate on this index
+ * Find the index entry, and remove the duplicate */
+ list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) {
+ if (tmp_entry->index == index) {
+ entry = tmp_entry;
+ break;
+ }
+ }
+ if (unlikely(!entry)) {
+ mlx4_warn(dev, "Steering entry for index %x is not registered\n", index);
+ return false;
+ }
+ list_for_each_entry_safe(dqp, tmp_dqp, &entry->duplicates, list) {
+ if (dqp->qpn == qpn) {
+ list_del(&dqp->list);
+ kfree(dqp);
+ }
+ }
+ return true;
+}
+
+/* I a steering entry contains only promisc QPs, it can be removed. */
+static bool can_remove_steering_entry(struct mlx4_dev *dev, u8 vep_num, u8 port,
+ enum mlx4_steer_type steer,
+ unsigned int index, u32 tqpn)
+{
+ struct mlx4_steer *s_steer;
+ struct mlx4_cmd_mailbox *mailbox;
+ struct mlx4_mgm *mgm;
+ struct mlx4_steer_index *entry = NULL, *tmp_entry;
+ u32 qpn;
+ u32 members_count;
+ bool ret = false;
+ int i;
+ u8 pf_num;
+
+ pf_num = (dev->caps.num_ports == 1) ? vep_num : (vep_num << 1) | (port - 1);
+ s_steer = &mlx4_priv(dev)->steer[pf_num];
+
+ mailbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(mailbox))
+ return false;
+ mgm = mailbox->buf;
+
+ if (mlx4_READ_ENTRY(dev, index, mailbox))
+ goto out;
+ members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
+ for (i = 0; i < members_count; i++) {
+ qpn = be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK;
+ if (!get_promisc_qp(dev, pf_num, steer, qpn) && qpn != tqpn) {
+ /* the qp is not promisc, the entry can't be removed */
+ goto out;
+ }
+ }
+ /* All the qps currently registered for this entry are promiscuous,
+ * Checking for duplicates */
+ ret = true;
+ list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) {
+ if (entry->index == index) {
+ if (list_empty(&entry->duplicates)) {
+ list_del(&entry->list);
+ kfree(entry);
+ } else {
+ /* This entry contains duplicates so it shouldn't be removed */
+ ret = false;
+ goto out;
+ }
+ }
+ }
+
+out:
+ mlx4_free_cmd_mailbox(dev, mailbox);
+ return ret;
+}
+
+static int add_promisc_qp(struct mlx4_dev *dev, u8 vep_num, u8 port,
+ enum mlx4_steer_type steer, u32 qpn)
+{
+ struct mlx4_steer *s_steer;
+ struct mlx4_cmd_mailbox *mailbox;
+ struct mlx4_mgm *mgm;
+ struct mlx4_steer_index *entry;
+ struct mlx4_promisc_qp *pqp;
+ struct mlx4_promisc_qp *dqp;
+ u32 members_count;
+ u32 prot;
+ int i;
+ bool found;
+ int last_index;
+ int err;
+ u8 pf_num;
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ pf_num = (dev->caps.num_ports == 1) ? vep_num : (vep_num << 1) | (port - 1);
+ s_steer = &mlx4_priv(dev)->steer[pf_num];
+
+ mutex_lock(&priv->mcg_table.mutex);
+
+ if (get_promisc_qp(dev, pf_num, steer, qpn)) {
+ err = 0; /* Noting to do, already exists */
+ goto out_mutex;
+ }
+
+ pqp = kmalloc(sizeof *pqp, GFP_KERNEL);
+ if (!pqp) {
+ err = -ENOMEM;
+ goto out_mutex;
+ }
+ pqp->qpn = qpn;
+
+ mailbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(mailbox)) {
+ err = -ENOMEM;
+ goto out_alloc;
+ }
+ mgm = mailbox->buf;
+
+ /* the promisc qp needs to be added for each one of the steering
+ * entries, if it already exists, needs to be added as a duplicate
+ * for this entry */
+ list_for_each_entry(entry, &s_steer->steer_entries[steer], list) {
+ err = mlx4_READ_ENTRY(dev, entry->index, mailbox);
+ if (err)
+ goto out_mailbox;
+
+ members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
+ prot = be32_to_cpu(mgm->members_count) >> 30;
+ found = false;
+ for (i = 0; i < members_count; i++) {
+ if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) {
+ /* Entry already exists, add to duplicates */
+ dqp = kmalloc(sizeof *dqp, GFP_KERNEL);
+ if (!dqp)
+ goto out_mailbox;
+ dqp->qpn = qpn;
+ list_add_tail(&dqp->list, &entry->duplicates);
+ found = true;
+ }
+ }
+ if (!found) {
+ /* Need to add the qpn to mgm */
+ if (members_count == MLX4_QP_PER_MGM) {
+ /* entry is full */
+ err = -ENOMEM;
+ goto out_mailbox;
+ }
+ mgm->qp[members_count++] = cpu_to_be32(qpn & MGM_QPN_MASK);
+ mgm->members_count = cpu_to_be32(members_count | (prot << 30));
+ err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox);
+ if (err)
+ goto out_mailbox;
+ }
+ last_index = entry->index;
+ }
+
+ /* add the new qpn to list of promisc qps */
+ list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]);
+ /* now need to add all the promisc qps to default entry */
+ memset(mgm, 0, sizeof *mgm);
+ members_count = 0;
+ list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list)
+ mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK);
+ mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30);
+
+ err = mlx4_WRITE_PROMISC(dev, vep_num, port, steer, mailbox);
+ if (err)
+ goto out_list;
+
+ mlx4_free_cmd_mailbox(dev, mailbox);
+ mutex_unlock(&priv->mcg_table.mutex);
+ return 0;
+
+out_list:
+ list_del(&pqp->list);
+out_mailbox:
+ mlx4_free_cmd_mailbox(dev, mailbox);
+out_alloc:
+ kfree(pqp);
+out_mutex:
+ mutex_unlock(&priv->mcg_table.mutex);
+ return err;
+}
+
+static int remove_promisc_qp(struct mlx4_dev *dev, u8 vep_num, u8 port,
+ enum mlx4_steer_type steer, u32 qpn)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_steer *s_steer;
+ struct mlx4_cmd_mailbox *mailbox;
+ struct mlx4_mgm *mgm;
+ struct mlx4_steer_index *entry;
+ struct mlx4_promisc_qp *pqp;
+ struct mlx4_promisc_qp *dqp;
+ u32 members_count;
+ bool found;
+ bool back_to_list = false;
+ int loc, i;
+ int err;
+ u8 pf_num;
+
+ pf_num = (dev->caps.num_ports == 1) ? vep_num : (vep_num << 1) | (port - 1);
+ s_steer = &mlx4_priv(dev)->steer[pf_num];
+ mutex_lock(&priv->mcg_table.mutex);
+
+ pqp = get_promisc_qp(dev, pf_num, steer, qpn);
+ if (unlikely(!pqp)) {
+ mlx4_warn(dev, "QP %x is not promiscuous QP\n", qpn);
+ /* nothing to do */
+ err = 0;
+ goto out_mutex;
+ }
+
+ /*remove from list of promisc qps */
+ list_del(&pqp->list);
+ kfree(pqp);
+
+ /* set the default entry not to include the removed one */
+ mailbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(mailbox)) {
+ err = -ENOMEM;
+ back_to_list = true;
+ goto out_list;
+ }
+ mgm = mailbox->buf;
+ members_count = 0;
+ list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list)
+ mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK);
+ mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30);
+
+ err = mlx4_WRITE_PROMISC(dev, vep_num, port, steer, mailbox);
+ if (err)
+ goto out_mailbox;
+
+ /* remove the qp from all the steering entries*/
+ list_for_each_entry(entry, &s_steer->steer_entries[steer], list) {
+ found = false;
+ list_for_each_entry(dqp, &entry->duplicates, list) {
+ if (dqp->qpn == qpn) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ /* a duplicate, no need to change the mgm,
+ * only update the duplicates list */
+ list_del(&dqp->list);
+ kfree(dqp);
+ } else {
+ err = mlx4_READ_ENTRY(dev, entry->index, mailbox);
+ if (err)
+ goto out_mailbox;
+ members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
+ for (loc = -1, i = 0; i < members_count; ++i)
+ if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn)
+ loc = i;
+
+ mgm->members_count = cpu_to_be32(--members_count |
+ (MLX4_PROT_ETH << 30));
+ mgm->qp[loc] = mgm->qp[i - 1];
+ mgm->qp[i - 1] = 0;
+
+ err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox);
+ if (err)
+ goto out_mailbox;
+ }
+
+ }
+
+out_mailbox:
+ mlx4_free_cmd_mailbox(dev, mailbox);
+out_list:
+ if (back_to_list)
+ list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]);
+out_mutex:
+ mutex_unlock(&priv->mcg_table.mutex);
+ return err;
+}
+
/*
* Caller must hold MCG table semaphore. gid and mgm parameters must
* be properly aligned for command interface.
@@ -164,6 +617,7 @@ int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
int i;
int err;
u8 port = gid[5];
+ u8 new_entry = 0;
mailbox = mlx4_alloc_cmd_mailbox(dev);
if (IS_ERR(mailbox))
@@ -177,8 +631,10 @@ int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
goto out;
if (index != -1) {
- if (!(be32_to_cpu(mgm->members_count) & 0xffffff))
+ if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) {
+ new_entry = 1;
memcpy(mgm->gid, gid, 16);
+ }
} else {
link = 1;
@@ -234,6 +690,14 @@ int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
goto out;
out:
+ if (prot == MLX4_PROT_ETH) {
+ /* manage the steering entry for promisc mode */
+ if (new_entry)
+ new_steering_entry(dev, 0, port, steer, index, qp->qpn);
+ else
+ existing_steering_entry(dev, 0, port, steer,
+ index, qp->qpn);
+ }
if (err && link && index != -1) {
if (index < dev->caps.num_mgms)
mlx4_warn(dev, "Got AMGM index %d < %d",
@@ -260,6 +724,7 @@ int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
int i, loc;
int err;
u8 port = gid[5];
+ bool removed_entry = false;
mailbox = mlx4_alloc_cmd_mailbox(dev);
if (IS_ERR(mailbox))
@@ -279,6 +744,11 @@ int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
goto out;
}
+ /* if this pq is also a promisc qp, it shouldn't be removed */
+ if (prot == MLX4_PROT_ETH &&
+ check_duplicate_entry(dev, 0, port, steer, index, qp->qpn))
+ goto out;
+
members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
for (loc = -1, i = 0; i < members_count; ++i)
if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn)
@@ -295,11 +765,16 @@ int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
mgm->qp[loc] = mgm->qp[i - 1];
mgm->qp[i - 1] = 0;
- if (i != 1) {
+ if (prot == MLX4_PROT_ETH)
+ removed_entry = can_remove_steering_entry(dev, 0, port, steer, index, qp->qpn);
+ if (i != 1 && (prot != MLX4_PROT_ETH || !removed_entry)) {
err = mlx4_WRITE_ENTRY(dev, index, mailbox);
goto out;
}
+ /* We are going to delete the entry, members count should be 0 */
+ mgm->members_count = cpu_to_be32((u32) prot << 30);
+
if (prev == -1) {
/* Remove entry from MGM */
int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6;
@@ -388,6 +863,46 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
}
EXPORT_SYMBOL_GPL(mlx4_multicast_detach);
+
+int mlx4_multicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port)
+{
+ if (!dev->caps.vep_mc_steering)
+ return 0;
+
+
+ return add_promisc_qp(dev, 0, port, MLX4_MC_STEER, qpn);
+}
+EXPORT_SYMBOL_GPL(mlx4_multicast_promisc_add);
+
+int mlx4_multicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port)
+{
+ if (!dev->caps.vep_mc_steering)
+ return 0;
+
+
+ return remove_promisc_qp(dev, 0, port, MLX4_MC_STEER, qpn);
+}
+EXPORT_SYMBOL_GPL(mlx4_multicast_promisc_remove);
+
+int mlx4_unicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port)
+{
+ if (!dev->caps.vep_mc_steering)
+ return 0;
+
+
+ return add_promisc_qp(dev, 0, port, MLX4_UC_STEER, qpn);
+}
+EXPORT_SYMBOL_GPL(mlx4_unicast_promisc_add);
+
+int mlx4_unicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port)
+{
+ if (!dev->caps.vep_mc_steering)
+ return 0;
+
+ return remove_promisc_qp(dev, 0, port, MLX4_UC_STEER, qpn);
+}
+EXPORT_SYMBOL_GPL(mlx4_unicast_promisc_remove);
+
int mlx4_init_mcg_table(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
index 67ee8da..1513a91 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/mlx4/mlx4.h
@@ -162,6 +162,27 @@ struct mlx4_fw {
u8 catas_bar;
};
+#define MGM_QPN_MASK 0x00FFFFFF
+#define MGM_BLCK_LB_BIT 30
+
+struct mlx4_promisc_qp {
+ struct list_head list;
+ u32 qpn;
+};
+
+struct mlx4_steer_index {
+ struct list_head list;
+ unsigned int index;
+ struct list_head duplicates;
+};
+
+struct mlx4_mgm {
+ __be32 next_gid_index;
+ __be32 members_count;
+ u32 reserved[2];
+ u8 gid[16];
+ __be32 qp[MLX4_QP_PER_MGM];
+};
struct mlx4_cmd {
struct pci_pool *pool;
void __iomem *hcr;
@@ -287,6 +308,12 @@ struct mlx4_msix_ctl {
spinlock_t pool_lock;
};
+struct mlx4_steer {
+ struct list_head promisc_qps[MLX4_NUM_STEERS];
+ struct list_head steer_entries[MLX4_NUM_STEERS];
+ struct list_head high_prios;
+};
+
struct mlx4_priv {
struct mlx4_dev dev;
@@ -319,6 +346,7 @@ struct mlx4_priv {
struct mlx4_sense sense;
struct mutex port_mutex;
struct mlx4_msix_ctl msix_ctl;
+ struct mlx4_steer *steer;
};
static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev)
@@ -409,4 +437,9 @@ void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table);
int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port);
int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps);
+int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
+ enum mlx4_protocol prot, enum mlx4_steer_type steer);
+int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
+ int block_mcast_loopback, enum mlx4_protocol prot,
+ enum mlx4_steer_type steer);
#endif /* MLX4_H */
--
1.6.0.2
^ 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