* Re: [PATCH] e1000: the power down when running ifdown command
From: Naohiro Ooiwa @ 2009-11-04 10:27 UTC (permalink / raw)
To: Jeff Kirsher
Cc: jesse.brandeburg, peter.p.waskiewicz.jr, john.ronciak, davem,
Andrew Morton, netdev, svaidy, e1000-devel
In-Reply-To: <9929d2390911031337p6115fef0wc1b94e5141ead341@mail.gmail.com>
Jeff Kirsher wrote:
> 2009/11/3 Naohiro Ooiwa <nooiwa@miraclelinux.com>:
>> Jeff Kirsher wrote:
>>> 2009/10/31 Naohiro Ooiwa <nooiwa@miraclelinux.com>:
>>>
>>> I have added this patch to my tree for testing. This patch requires a
>>> fair amount of regression testing, so once its passed testing I will
>>> push the patch to David/netdev.
>> I appreciate the marge your tree.
>> If there is anything I can do, please let me know.
>>
>> And I know this patch is good for e100 driver too.
>> I would really like to create patch for it.
>> How do you think about e100 driver.
>>
>>
>> Thanks,
>> Naohiro Ooiwa
>>
>
> Patches are always welcome (referring to a e100 patch).
I am happy that you should say that.
I will try to create a patch for e100, e1000e, igb and ixgbe.
Before that, I should fix the following problems.
> As far as the e1000 patch goes, it has a number of issues which were
> found in testing. Here are just a few problems we saw:
> 1. ethtool -t - crashes the system
> 2. ethtool eth0 - always shows link/speed as 1000/Full even when there
> is no cable
> 3. ethtool -s eth0 autoneg on/off - system hang. Sometimes a copper
> interface will show up as fiber after this.
> 4. ethtool -d/-S/-g etc - will corrupt the stats of the interface
> while doing ifup/down
Thank you for your tests.
Oh, My patch is full of problem.
The rest is my work.
I will resend the patch after test of all ethtool's options.
At that time, I will tell you contents of my tests.
And I sad WOL works on my patch in previous mail.
But WOL doesn't work. Sorry, I wasn't myself.
I will fix it too.
>
> So it appears that more needs to be done to the driver to get this to
> work as expected.
>
> NAK
>
^ permalink raw reply
* Re: [Patch] net: fix incorrect counting in __scm_destroy()
From: Eric Dumazet @ 2009-11-04 10:29 UTC (permalink / raw)
To: Amerigo Wang; +Cc: linux-kernel, netdev, David S. Miller
In-Reply-To: <20091104100717.4785.57149.sendpatchset@localhost.localdomain>
Amerigo Wang a écrit :
> It seems that in __scm_destroy() we forgot to decrease
> the ->count after fput(->fp[i]), this may cause some
> problem when we recursively call fput() again.
>
> Signed-off-by: WANG Cong <amwang@redhat.com>
> Cc: David S. Miller <davem@davemloft.net>
>
> ---
> diff --git a/net/core/scm.c b/net/core/scm.c
> index b7ba91b..fa53219 100644
> --- a/net/core/scm.c
> +++ b/net/core/scm.c
> @@ -120,8 +120,10 @@ void __scm_destroy(struct scm_cookie *scm)
> fpl = list_first_entry(&work_list, struct scm_fp_list, list);
>
> list_del(&fpl->list);
> - for (i=fpl->count-1; i>=0; i--)
> + for (i = fpl->count-1; i >= 0; i--) {
> fput(fpl->fp[i]);
> + fpl->count--;
> + }
> kfree(fpl);
> }
>
Hmm, your patch seems suspicious.
Are you fixing a real crash/bug, or is it something you discovered in a code review ?
Given we kfree(fpl) at the end of loop, we cannot recursively call __scm_destroy()
on same fpl, it would be a bug anyway ?
So you probably need something better, like testing fpl->list being not re-included
in current->scm_work_list before kfree() it
^ permalink raw reply
* Re: [PATCH] sch_htb.c consume the classes's tokens bellow the HTB_CAN_SEND level
From: Jarek Poplawski @ 2009-11-04 10:42 UTC (permalink / raw)
To: Changli Gao; +Cc: Jamal Hadi Salim, devik, netdev
In-Reply-To: <412e6f7f0911040116q6b25b705k83e5a45464698af1@mail.gmail.com>
On Wed, Nov 04, 2009 at 05:16:42PM +0800, Changli Gao wrote:
...
> It is just correct. You focus on 1 second fairness, while I focus on 2
> seconds fairness.
The whole example was very simplified, so it all would certainly
differ in time and real sends, especially with an interaction of
more classes. But, generally, main HTB algorithm seems to be quite
well tested against various fair and unfair cases, starting from
the author's examples:
http://luxik.cdi.cz/~devik/qos/htb/manual/userg.htm
so, I guess, this type of a bug would really show somewhere long time
ago.
> The token bucket and ctoken bucket both use cl->mbuffer to control
> rate granularities. If we don't account token bucket when the
> corresponding class in HTB_MAY_BORROW mode, the cl->mbuffer will
> become useless.
cl->mbuffer is only to limit some extreme effects, so more of an
exception, not a main tool of rate control. (It really should be
useless most of the time if classes don't stop sending and aren't
deprived of their full rate for really long time.)
Regards,
Jarek P.
^ permalink raw reply
* Re: [PATCH] sch_htb.c consume the classes's tokens bellow the HTB_CAN_SEND level
From: Martin Devera @ 2009-11-04 10:58 UTC (permalink / raw)
To: Jarek Poplawski; +Cc: Changli Gao, Jamal Hadi Salim, netdev
In-Reply-To: <20091104104245.GB6224@ff.dom.local>
Jarek Poplawski wrote:
> On Wed, Nov 04, 2009 at 05:16:42PM +0800, Changli Gao wrote:
> ...
>> It is just correct. You focus on 1 second fairness, while I focus on 2
>> seconds fairness.
>
> The whole example was very simplified, so it all would certainly
> differ in time and real sends, especially with an interaction of
> more classes. But, generally, main HTB algorithm seems to be quite
> well tested against various fair and unfair cases, starting from
> the author's examples:
> http://luxik.cdi.cz/~devik/qos/htb/manual/userg.htm
> so, I guess, this type of a bug would really show somewhere long time
> ago.
>
>> The token bucket and ctoken bucket both use cl->mbuffer to control
>> rate granularities. If we don't account token bucket when the
>> corresponding class in HTB_MAY_BORROW mode, the cl->mbuffer will
>> become useless.
>
> cl->mbuffer is only to limit some extreme effects, so more of an
> exception, not a main tool of rate control. (It really should be
> useless most of the time if classes don't stop sending and aren't
> deprived of their full rate for really long time.)
Hello,
yes you are right. If I remember correctly, I tried to charge "rate"
tokens up to root in early versions (which makes some sense) but problem
is with many interior classes stuck at extreme mbuffer value, losing
responsivity. Also it didn't played well with prio settings (class
stalls).
Bacause we don't charge "rate" now, some amount of burst can accumulate
in each interior class and decrease fairness at the same prio level a
bit. However from measurments I did, these bursts of unfairness are
hidded by regular "bursting" of rate and ceil token buckets.
devik
^ permalink raw reply
* Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server
From: Andi Kleen @ 2009-11-04 11:08 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: netdev, virtualization, kvm, linux-kernel, mingo, linux-mm, akpm
In-Reply-To: <20091103172422.GD5591@redhat.com>
"Michael S. Tsirkin" <mst@redhat.com> writes:
Haven't really read the whole thing, just noticed something at a glance.
> +/* Expects to be always run from workqueue - which acts as
> + * read-size critical section for our kind of RCU. */
> +static void handle_tx(struct vhost_net *net)
> +{
> + struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX];
> + unsigned head, out, in, s;
> + struct msghdr msg = {
> + .msg_name = NULL,
> + .msg_namelen = 0,
> + .msg_control = NULL,
> + .msg_controllen = 0,
> + .msg_iov = vq->iov,
> + .msg_flags = MSG_DONTWAIT,
> + };
> + size_t len, total_len = 0;
> + int err, wmem;
> + size_t hdr_size;
> + struct socket *sock = rcu_dereference(vq->private_data);
> + if (!sock)
> + return;
> +
> + wmem = atomic_read(&sock->sk->sk_wmem_alloc);
> + if (wmem >= sock->sk->sk_sndbuf)
> + return;
> +
> + use_mm(net->dev.mm);
I haven't gone over all this code in detail, but that isolated reference count
use looks suspicious. What prevents the mm from going away before
you increment, if it's not the current one?
-Andi
--
ak@linux.intel.com -- Speaking for myself only.
^ permalink raw reply
* Re: [PATCH] sch_htb.c consume the classes's tokens bellow the HTB_CAN_SEND level
From: Changli Gao @ 2009-11-04 11:21 UTC (permalink / raw)
To: Jarek Poplawski; +Cc: Jamal Hadi Salim, devik, netdev
In-Reply-To: <20091104104245.GB6224@ff.dom.local>
On Wed, Nov 4, 2009 at 6:42 PM, Jarek Poplawski <jarkao2@gmail.com> wrote:
> On Wed, Nov 04, 2009 at 05:16:42PM +0800, Changli Gao wrote:
> ...
>> It is just correct. You focus on 1 second fairness, while I focus on 2
>> seconds fairness.
>
> The whole example was very simplified, so it all would certainly
> differ in time and real sends, especially with an interaction of
> more classes. But, generally, main HTB algorithm seems to be quite
> well tested against various fair and unfair cases, starting from
> the author's examples:
> http://luxik.cdi.cz/~devik/qos/htb/manual/userg.htm
> so, I guess, this type of a bug would really show somewhere long time
> ago.
>
This documentation is old, and after the last update 5.5.2002, there
were still bugs: http://luxik.cdi.cz/~devik/qos/htb/ .
>> The token bucket and ctoken bucket both use cl->mbuffer to control
>> rate granularities. If we don't account token bucket when the
>> corresponding class in HTB_MAY_BORROW mode, the cl->mbuffer will
>> become useless.
>
> cl->mbuffer is only to limit some extreme effects, so more of an
> exception, not a main tool of rate control. (It really should be
> useless most of the time if classes don't stop sending and aren't
> deprived of their full rate for really long time.)
>
I don't think so. Although a class's tokens may be negative, but its
ctokens may be positive. Charging its tokens is to prevent its cmode
from being changed to HTB_CAN_SEND from HTB_CANT_SEND directly.
--
Regards,
Changli Gao(xiaosuo@gmail.com)
^ permalink raw reply
* Re: [PATCH] sch_htb.c consume the classes's tokens bellow the HTB_CAN_SEND level
From: Changli Gao @ 2009-11-04 11:30 UTC (permalink / raw)
To: Martin Devera; +Cc: Jarek Poplawski, Jamal Hadi Salim, netdev
In-Reply-To: <4AF15E73.30806@cdi.cz>
On Wed, Nov 4, 2009 at 6:58 PM, Martin Devera <martin.devera@cdi.cz> wrote:
>
> Hello,
>
> yes you are right. If I remember correctly, I tried to charge "rate"
> tokens up to root in early versions (which makes some sense) but problem
> is with many interior classes stuck at extreme mbuffer value, losing
> responsivity.
It is strange. Would you like describe it more clearly?
> Also it didn't played well with prio settings (class
> stalls).
Was it the cause?
> Bacause we don't charge "rate" now, some amount of burst can accumulate
> in each interior class and decrease fairness at the same prio level a bit.
> However from measurments I did, these bursts of unfairness are
> hidded by regular "bursting" of rate and ceil token buckets.
>
One case for unfairness.
--
Regards,
Changli Gao(xiaosuo@gmail.com)
^ permalink raw reply
* Re: HTB accuracy on 10GbE
From: Eric Dumazet @ 2009-11-04 11:31 UTC (permalink / raw)
To: Ryousei Takano
Cc: Stephen Hemminger, Patrick McHardy, Linux Netdev List,
takano-ryousei
In-Reply-To: <b30d1c3b0911040019q14a007d4lbd1b695db8884b27@mail.gmail.com>
Ryousei Takano a écrit :
>
> I tried iperf with 60 seconds samples. I got the almost same result.
>
> Here is the result:
> sender receiver
> 1.000 1.00 1.00
> 2.000 2.01 2.01
> 3.000 3.03 3.02
> 4.000 4.07 4.07
> 5.000 5.05 5.05
> 6.000 6.16 6.16
> 7.000 7.22 7.22
> 8.000 8.15 8.15
> 9.000 9.23 9.23
> 9.900 9.69 9.69
>
One thing to consider is the estimation error in qdisc_l2t(), rate table has only 256 slots
static inline u32 qdisc_l2t(struct qdisc_rate_table* rtab, unsigned int pktlen)
{
int slot = pktlen + rtab->rate.cell_align + rtab->rate.overhead;
if (slot < 0)
slot = 0;
slot >>= rtab->rate.cell_log;
if (slot > 255)
return (rtab->data[255]*(slot >> 8) + rtab->data[slot & 0xFF]);
return rtab->data[slot];
}
Maybe you can try changing class mtu to 40000 instead of 9000, and quantum to 60000 too
tc class add dev $DEV parent 1: classid 1:1 htb rate ${rate}mbit mtu 40000 quantum 60000
(because your tcp stack sends large buffers ( ~ 60000 bytes) as your NIC can offload tcp segmentation)
^ permalink raw reply
* Re: [PATCH] sch_htb.c consume the classes's tokens bellow the HTB_CAN_SEND level
From: Jarek Poplawski @ 2009-11-04 11:49 UTC (permalink / raw)
To: Changli Gao; +Cc: Jamal Hadi Salim, devik, netdev
In-Reply-To: <412e6f7f0911040321o22c536fdid078f6d2225a90a0@mail.gmail.com>
On Wed, Nov 04, 2009 at 07:21:48PM +0800, Changli Gao wrote:
...
> > cl->mbuffer is only to limit some extreme effects, so more of an
> > exception, not a main tool of rate control. (It really should be
> > useless most of the time if classes don't stop sending and aren't
> > deprived of their full rate for really long time.)
> >
>
> I don't think so. Although a class's tokens may be negative, but its
> ctokens may be positive. Charging its tokens is to prevent its cmode
> from being changed to HTB_CAN_SEND from HTB_CANT_SEND directly.
I think, you should really better show some tests proving your patch
is needed and doesn't affect a case I described, instead of trying to
discuss the meaninig of all HTB variables here.
Regards,
Jarek P.
^ permalink raw reply
* Re: [PATCH] sch_htb.c consume the classes's tokens bellow the HTB_CAN_SEND level
From: Martin Devera @ 2009-11-04 11:51 UTC (permalink / raw)
To: Changli Gao; +Cc: Jarek Poplawski, Jamal Hadi Salim, netdev
In-Reply-To: <412e6f7f0911040330uc5ebbcekfef57854fce501f@mail.gmail.com>
Changli Gao wrote:
> On Wed, Nov 4, 2009 at 6:58 PM, Martin Devera <martin.devera@cdi.cz> wrote:
>> Hello,
>>
>> yes you are right. If I remember correctly, I tried to charge "rate"
>> tokens up to root in early versions (which makes some sense) but problem
>> is with many interior classes stuck at extreme mbuffer value, losing
>> responsivity.
>
> It is strange. Would you like describe it more clearly?
oops, forget it, I mixed it with different problem I remember :-)
The idea is to charge classe's tokens when it sends.
It always must be under ceil thus when it sends we can charge
ctokens (it must have some in order to be in CAN_SEND).
If it borrows, we don't charge it because doesn't send from
its own rate but rather from parent's rate. Thus charge
only parent. Because parent gave it rate as gift, free of charge,
it has it in addition to its own rate.
^ permalink raw reply
* Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server
From: Michael S. Tsirkin @ 2009-11-04 11:57 UTC (permalink / raw)
To: Paul E. McKenney
Cc: Gregory Haskins, Eric Dumazet, netdev, virtualization, kvm,
linux-kernel, mingo, linux-mm, akpm, hpa, Rusty Russell, s.hetze
In-Reply-To: <20091103235744.GF6726@linux.vnet.ibm.com>
On Tue, Nov 03, 2009 at 03:57:44PM -0800, Paul E. McKenney wrote:
> On Tue, Nov 03, 2009 at 01:14:06PM -0500, Gregory Haskins wrote:
> > Gregory Haskins wrote:
> > > Eric Dumazet wrote:
> > >> Michael S. Tsirkin a écrit :
> > >>> +static void handle_tx(struct vhost_net *net)
> > >>> +{
> > >>> + struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX];
> > >>> + unsigned head, out, in, s;
> > >>> + struct msghdr msg = {
> > >>> + .msg_name = NULL,
> > >>> + .msg_namelen = 0,
> > >>> + .msg_control = NULL,
> > >>> + .msg_controllen = 0,
> > >>> + .msg_iov = vq->iov,
> > >>> + .msg_flags = MSG_DONTWAIT,
> > >>> + };
> > >>> + size_t len, total_len = 0;
> > >>> + int err, wmem;
> > >>> + size_t hdr_size;
> > >>> + struct socket *sock = rcu_dereference(vq->private_data);
> > >>> + if (!sock)
> > >>> + return;
> > >>> +
> > >>> + wmem = atomic_read(&sock->sk->sk_wmem_alloc);
> > >>> + if (wmem >= sock->sk->sk_sndbuf)
> > >>> + return;
> > >>> +
> > >>> + use_mm(net->dev.mm);
> > >>> + mutex_lock(&vq->mutex);
> > >>> + vhost_no_notify(vq);
> > >>> +
> > >> using rcu_dereference() and mutex_lock() at the same time seems wrong, I suspect
> > >> that your use of RCU is not correct.
> > >>
> > >> 1) rcu_dereference() should be done inside a read_rcu_lock() section, and
> > >> we are not allowed to sleep in such a section.
> > >> (Quoting Documentation/RCU/whatisRCU.txt :
> > >> It is illegal to block while in an RCU read-side critical section, )
> > >>
> > >> 2) mutex_lock() can sleep (ie block)
> > >>
> > >
> > >
> > > Michael,
> > > I warned you that this needed better documentation ;)
> > >
> > > Eric,
> > > I think I flagged this once before, but Michael convinced me that it
> > > was indeed "ok", if but perhaps a bit unconventional. I will try to
> > > find the thread.
> > >
> > > Kind Regards,
> > > -Greg
> > >
> >
> > Here it is:
> >
> > http://lkml.org/lkml/2009/8/12/173
>
> What was happening in that case was that the rcu_dereference()
> was being used in a workqueue item. The role of rcu_read_lock()
> was taken on be the start of execution of the workqueue item, of
> rcu_read_unlock() by the end of execution of the workqueue item, and
> of synchronize_rcu() by flush_workqueue(). This does work, at least
> assuming that flush_workqueue() operates as advertised, which it appears
> to at first glance.
>
> The above code looks somewhat different, however -- I don't see
> handle_tx() being executed in the context of a work queue. Instead
> it appears to be in an interrupt handler.
> So what is the story? Using synchronize_irq() or some such?
>
> Thanx, Paul
No, there has been no change (I won't be able to use a mutex in an
interrupt handler, will I?). handle_tx is still called in the context
of a work queue: either from handle_tx_kick or from handle_tx_net which
are work queue items.
Can you ack this usage please?
--
MST
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [PATCH] sch_htb.c consume the classes's tokens bellow the HTB_CAN_SEND level
From: Martin Devera @ 2009-11-04 11:58 UTC (permalink / raw)
To: Changli Gao; +Cc: Jarek Poplawski, Jamal Hadi Salim, netdev
In-Reply-To: <412e6f7f0911040330uc5ebbcekfef57854fce501f@mail.gmail.com>
Changli Gao wrote:
> On Wed, Nov 4, 2009 at 6:58 PM, Martin Devera <martin.devera@cdi.cz> wrote:
>> Hello,
>>
>> yes you are right. If I remember correctly, I tried to charge "rate"
>> tokens up to root in early versions (which makes some sense) but problem
>> is with many interior classes stuck at extreme mbuffer value, losing
>> responsivity.
>
> It is strange. Would you like describe it more clearly?
Ahh I'm starting to understand. You are concerned mainly with
cl->tokens += diff; /* we moved t_c; update tokens */
am I right ?
^ permalink raw reply
* Re: [PATCH] sch_htb.c consume the classes's tokens bellow the HTB_CAN_SEND level
From: Changli Gao @ 2009-11-04 12:01 UTC (permalink / raw)
To: Jarek Poplawski; +Cc: Jamal Hadi Salim, devik, netdev
In-Reply-To: <20091104114922.GA8176@ff.dom.local>
On Wed, Nov 4, 2009 at 7:49 PM, Jarek Poplawski <jarkao2@gmail.com> wrote:
> On Wed, Nov 04, 2009 at 07:21:48PM +0800, Changli Gao wrote:
>>
>> I don't think so. Although a class's tokens may be negative, but its
>> ctokens may be positive. Charging its tokens is to prevent its cmode
>> from being changed to HTB_CAN_SEND from HTB_CANT_SEND directly.
>
> I think, you should really better show some tests proving your patch
> is needed and doesn't affect a case I described, instead of trying to
> discuss the meaninig of all HTB variables here.
>
I test it before sending it here, but it doesn't show any obvious
difference as Martin said, no worse and no better. I don't know how to
construct a test to show you the bad effect you worry about. Any
suggestion about the test?
--
Regards,
Changli Gao(xiaosuo@gmail.com)
^ permalink raw reply
* Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server
From: Michael S. Tsirkin @ 2009-11-04 12:04 UTC (permalink / raw)
To: Eric Dumazet
Cc: Gregory Haskins, netdev, virtualization, kvm, linux-kernel, mingo,
linux-mm, akpm, hpa, Rusty Russell, s.hetze, Paul E. McKenney
In-Reply-To: <4AF09C70.6090505@gmail.com>
On Tue, Nov 03, 2009 at 10:11:12PM +0100, Eric Dumazet wrote:
> Michael S. Tsirkin a écrit :
> >
> > Paul, you acked this previously. Should I add you acked-by line so
> > people calm down? If you would rather I replace
> > rcu_dereference/rcu_assign_pointer with rmb/wmb, I can do this.
> > Or maybe patch Documentation to explain this RCU usage?
> >
>
> So you believe I am over-reacting to this dubious use of RCU ?
>
> RCU documentation is already very complex, we dont need to add yet another
> subtle use, and makes it less readable.
>
> It seems you use 'RCU api' in drivers/vhost/net.c as convenient macros :
>
> #define rcu_dereference(p) ({ \
> typeof(p) _________p1 = ACCESS_ONCE(p); \
> smp_read_barrier_depends(); \
> (_________p1); \
> })
>
> #define rcu_assign_pointer(p, v) \
> ({ \
> if (!__builtin_constant_p(v) || \
> ((v) != NULL)) \
> smp_wmb(); \
> (p) = (v); \
> })
>
>
> There are plenty regular uses of smp_wmb() in kernel, not related to Read Copy Update,
> there is nothing wrong to use barriers with appropriate comments.
Well, what I do has classic RCU characteristics: readers do not take
locks, writers take a lock and flush after update. This is why I believe
rcu_dereference and rcu_assign_pointer are more appropriate here than
open-coding barriers.
Before deciding whether it's a good idea to open-code barriers
instead, I would like to hear Paul's opinion.
>
> (And you already use mb(), wmb(), rmb(), smp_wmb() in your patch)
Yes, virtio guest pretty much forces this, there's no way to share
a lock with the guest.
> BTW there is at least one locking bug in vhost_net_set_features()
>
> Apparently, mutex_unlock() doesnt trigger a fault if mutex is not locked
> by current thread... even with DEBUG_MUTEXES / DEBUG_LOCK_ALLOC
>
>
> static void vhost_net_set_features(struct vhost_net *n, u64 features)
> {
> size_t hdr_size = features & (1 << VHOST_NET_F_VIRTIO_NET_HDR) ?
> sizeof(struct virtio_net_hdr) : 0;
> int i;
> <<!>> mutex_unlock(&n->dev.mutex);
> n->dev.acked_features = features;
> smp_wmb();
> for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {
> mutex_lock(&n->vqs[i].mutex);
> n->vqs[i].hdr_size = hdr_size;
> mutex_unlock(&n->vqs[i].mutex);
> }
> mutex_unlock(&n->dev.mutex);
> vhost_net_flush(n);
> }
Thanks very much for spotting this! Will fix.
--
MST
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [PATCH] sch_htb.c consume the classes's tokens bellow the HTB_CAN_SEND level
From: Changli Gao @ 2009-11-04 12:08 UTC (permalink / raw)
To: Martin Devera; +Cc: Jarek Poplawski, Jamal Hadi Salim, netdev
In-Reply-To: <4AF16C49.409@cdi.cz>
On Wed, Nov 4, 2009 at 7:58 PM, Martin Devera <martin.devera@cdi.cz> wrote:
>
> Ahh I'm starting to understand. You are concerned mainly with
>
> cl->tokens += diff; /* we moved t_c; update tokens */
>
> am I right ?
>
If we don't need to charge the tokens, updating it is necessary. I am
arguing the tokens isn't updated with the ctokens when the
corresponding class is in HTB_MAY_BORROW mode.
--
Regards,
Changli Gao(xiaosuo@gmail.com)
^ permalink raw reply
* Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server
From: Michael S. Tsirkin @ 2009-11-04 12:10 UTC (permalink / raw)
To: Andi Kleen
Cc: netdev, virtualization, kvm, linux-kernel, mingo, linux-mm, akpm
In-Reply-To: <878wema6o0.fsf@basil.nowhere.org>
On Wed, Nov 04, 2009 at 12:08:47PM +0100, Andi Kleen wrote:
> "Michael S. Tsirkin" <mst@redhat.com> writes:
>
> Haven't really read the whole thing, just noticed something at a glance.
>
> > +/* Expects to be always run from workqueue - which acts as
> > + * read-size critical section for our kind of RCU. */
> > +static void handle_tx(struct vhost_net *net)
> > +{
> > + struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX];
> > + unsigned head, out, in, s;
> > + struct msghdr msg = {
> > + .msg_name = NULL,
> > + .msg_namelen = 0,
> > + .msg_control = NULL,
> > + .msg_controllen = 0,
> > + .msg_iov = vq->iov,
> > + .msg_flags = MSG_DONTWAIT,
> > + };
> > + size_t len, total_len = 0;
> > + int err, wmem;
> > + size_t hdr_size;
> > + struct socket *sock = rcu_dereference(vq->private_data);
> > + if (!sock)
> > + return;
> > +
> > + wmem = atomic_read(&sock->sk->sk_wmem_alloc);
> > + if (wmem >= sock->sk->sk_sndbuf)
> > + return;
> > +
> > + use_mm(net->dev.mm);
>
> I haven't gone over all this code in detail, but that isolated reference count
> use looks suspicious. What prevents the mm from going away before
> you increment, if it's not the current one?
We take a reference to it before we start any virtqueues,
and stop all virtqueues before we drop the reference:
/* Caller should have device mutex */
static long vhost_dev_set_owner(struct vhost_dev *dev)
{
/* Is there an owner already? */
if (dev->mm)
return -EBUSY;
/* No owner, become one */
dev->mm = get_task_mm(current);
return 0;
}
And
vhost_dev_cleanup:
....
if (dev->mm)
mmput(dev->mm);
dev->mm = NULL;
}
Fine?
> -Andi
>
> --
> ak@linux.intel.com -- Speaking for myself only.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [PATCH] sch_htb.c consume the classes's tokens bellow the HTB_CAN_SEND level
From: Jarek Poplawski @ 2009-11-04 12:11 UTC (permalink / raw)
To: Changli Gao; +Cc: Jamal Hadi Salim, devik, netdev
In-Reply-To: <412e6f7f0911040401g5a8d58b0yc8c1637d419094f2@mail.gmail.com>
On Wed, Nov 04, 2009 at 08:01:23PM +0800, Changli Gao wrote:
> On Wed, Nov 4, 2009 at 7:49 PM, Jarek Poplawski <jarkao2@gmail.com> wrote:
> > On Wed, Nov 04, 2009 at 07:21:48PM +0800, Changli Gao wrote:
> >>
> >> I don't think so. Although a class's tokens may be negative, but its
> >> ctokens may be positive. Charging its tokens is to prevent its cmode
> >> from being changed to HTB_CAN_SEND from HTB_CANT_SEND directly.
> >
> > I think, you should really better show some tests proving your patch
> > is needed and doesn't affect a case I described, instead of trying to
> > discuss the meaninig of all HTB variables here.
> >
>
> I test it before sending it here, but it doesn't show any obvious
> difference as Martin said, no worse and no better.
Strange... How this patch could be needed or even "necessary", and
do "no worse and no better" at the same time.
> I don't know how to
> construct a test to show you the bad effect you worry about. Any
> suggestion about the test?
E.g. something like I described, but only rates 50kbit and 100kbit
instead of 5 and 10 packets/sec.
Regards,
Jarek P.
^ permalink raw reply
* Re: [PATCH] sch_htb.c consume the classes's tokens bellow the HTB_CAN_SEND level
From: Martin Devera @ 2009-11-04 12:15 UTC (permalink / raw)
To: Changli Gao; +Cc: Jarek Poplawski, Jamal Hadi Salim, netdev
In-Reply-To: <412e6f7f0911040408w5adcdde8yc1add4a561e90e40@mail.gmail.com>
Changli Gao wrote:
> On Wed, Nov 4, 2009 at 7:58 PM, Martin Devera <martin.devera@cdi.cz> wrote:
>> Ahh I'm starting to understand. You are concerned mainly with
>>
>> cl->tokens += diff; /* we moved t_c; update tokens */
>>
>> am I right ?
>>
>
> If we don't need to charge the tokens, updating it is necessary. I am
> arguing the tokens isn't updated with the ctokens when the
> corresponding class is in HTB_MAY_BORROW mode.
>
Ok, then the reason is in "logic". When you have parent P and children
A,B each with half of rate and only A is sending, than we want A to use
its own rate and also B's rate. B's rate is available as excess in P.
Here I see correct to charge part to A and part to P, while you want
to charge one P and twice A. Only mbuffer will limit the duplicity.
And it is not good idea because tokens can go very negative and then
ittroduce A's stall for some time.
I see no principial benefit...
^ permalink raw reply
* Re: pull request: wireless-next-2.6 2009-10-28
From: Pavel Machek @ 2009-11-02 21:16 UTC (permalink / raw)
To: Luis Correia
Cc: John W. Linville, Ingo Molnar, Johannes Berg, Jarek Poplawski,
Bartlomiej Zolnierkiewicz, Pekka Enberg, David Miller,
linux-wireless, netdev, linux-kernel
In-Reply-To: <efe7343f0911020932l21a570c8u9478568329d38e2c@mail.gmail.com>
> About Bartlomiej, there is only one more thing that I'll say:
>
> I've searched on my GMail archives and the only patch Bart has
> provided so far for the rt2x00 project is this:
>
> [PATCH] MAINTAINERS: rt2x00 list is moderated
>
> Which, while technically correct, adds nothing to the project.
>
> So, I will personally continue to ignore Bart's comments, regards and
> rants, until he provides patches for rt2x00 that actually make the
> driver better.
Well, he provided review feedback... he should be thanked for that,
not flamed for it.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply
* [PATCH 04/25] mlx4_core: add WRITE_MTT support
From: Yevgeny Petrilin @ 2009-11-04 15:30 UTC (permalink / raw)
To: rdreier; +Cc: linux-rdma, netdev, liranl, tziporet, yevgenyp
Used by vfs to modify mtts, since they cannot access in-memory mtts directly.
Signed-off-by: Liran Liss <liranl@mellanox.co.il>
---
drivers/net/mlx4/cmd.c | 3 +-
drivers/net/mlx4/mlx4.h | 5 ++++
drivers/net/mlx4/mr.c | 62 ++++++++++++++++++++++++++++++++++++++++++----
3 files changed, 62 insertions(+), 8 deletions(-)
diff --git a/drivers/net/mlx4/cmd.c b/drivers/net/mlx4/cmd.c
index 03dfdfc..96462f7 100644
--- a/drivers/net/mlx4/cmd.c
+++ b/drivers/net/mlx4/cmd.c
@@ -36,8 +36,6 @@
#include <linux/pci.h>
#include <linux/errno.h>
-#include <linux/mlx4/cmd.h>
-
#include <asm/io.h>
#include "mlx4.h"
@@ -441,6 +439,7 @@ static struct mlx4_cmd_info {
{MLX4_CMD_QUERY_MPT, 0, 1, 0, NULL, NULL}, /* need verifier */
{MLX4_CMD_HW2SW_MPT, 0, 0, 0, NULL, NULL}, /* need verifier */
{MLX4_CMD_READ_MTT, 0, 1, 0, NULL, NULL}, /* need verifier */
+ {MLX4_CMD_WRITE_MTT, 1, 0, 0, NULL, mlx4_WRITE_MTT_wrapper},
{MLX4_CMD_SYNC_TPT, 1, 0, 0, NULL, NULL}, /* need verifier */
{MLX4_CMD_HW2SW_EQ, 0, 0, 0, NULL, NULL}, /* need verifier */
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
index 88b4ff4..4796982 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/mlx4/mlx4.h
@@ -45,6 +45,7 @@
#include <linux/mlx4/device.h>
#include <linux/mlx4/driver.h>
#include <linux/mlx4/doorbell.h>
+#include <linux/mlx4/cmd.h>
#define DRV_NAME "mlx4_core"
#define PFX DRV_NAME ": "
@@ -421,6 +422,10 @@ void mlx4_cleanup_qp_table(struct mlx4_dev *dev);
void mlx4_cleanup_srq_table(struct mlx4_dev *dev);
void mlx4_cleanup_mcg_table(struct mlx4_dev *dev);
+int mlx4_WRITE_MTT_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vhcr,
+ struct mlx4_cmd_mailbox *inbox,
+ struct mlx4_cmd_mailbox *outbox);
+
void mlx4_start_catas_poll(struct mlx4_dev *dev);
void mlx4_stop_catas_poll(struct mlx4_dev *dev);
void mlx4_catas_init(void);
diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c
index ca7ab8e..11a3d26 100644
--- a/drivers/net/mlx4/mr.c
+++ b/drivers/net/mlx4/mr.c
@@ -262,6 +262,35 @@ static int mlx4_HW2SW_MPT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox
!mailbox, MLX4_CMD_HW2SW_MPT, MLX4_CMD_TIME_CLASS_B);
}
+int mlx4_WRITE_MTT_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vhcr,
+ struct mlx4_cmd_mailbox *inbox,
+ struct mlx4_cmd_mailbox *outbox)
+{
+ struct mlx4_mtt mtt;
+ u64 *page_list = inbox->buf;
+ int i;
+
+ /* Call the SW implementation of write_mtt:
+ * - Prepare a dummy mtt struct
+ * - Translate inbox contents to simple addresses in host endianess */
+ mtt.first_seg = 0;
+ mtt.order = 0;
+ mtt.page_shift = 0;
+ for (i = 0; i < vhcr->in_modifier; ++i)
+ page_list[i + 2] = be64_to_cpu(page_list[i + 2]) & ~1ULL;
+ vhcr->errno = mlx4_write_mtt(dev, &mtt, be64_to_cpu(page_list[0]),
+ vhcr->in_modifier,
+ page_list + 2);
+ return 0;
+}
+
+static int mlx4_WRITE_MTT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
+ int num_entries)
+{
+ return mlx4_cmd(dev, mailbox->dma, num_entries, 0, MLX4_CMD_WRITE_MTT,
+ MLX4_CMD_TIME_CLASS_A);
+}
+
int mlx4_mr_alloc(struct mlx4_dev *dev, u32 pd, u64 iova, u64 size, u32 access,
int npages, int page_shift, struct mlx4_mr *mr)
{
@@ -413,24 +442,45 @@ static int mlx4_write_mtt_chunk(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
int start_index, int npages, u64 *page_list)
{
+ struct mlx4_cmd_mailbox *mailbox = NULL;
int chunk;
- int err;
+ int err = 0;
+ __be64 *inbox = NULL;
+ int i;
if (mtt->order < 0)
return -EINVAL;
+ if (mlx4_is_slave(dev)) {
+ mailbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ inbox = mailbox->buf;
+ }
+
while (npages > 0) {
- chunk = min_t(int, PAGE_SIZE / sizeof(u64), npages);
- err = mlx4_write_mtt_chunk(dev, mtt, start_index, chunk, page_list);
+ if (mlx4_is_slave(dev)) {
+ chunk = min_t(int, MLX4_MAILBOX_SIZE / sizeof(u64) - MLX4_MTT_ENTRY_PER_SEG, npages);
+ inbox[0] = cpu_to_be64(mtt->first_seg * MLX4_MTT_ENTRY_PER_SEG + start_index);
+ inbox[1] = 0;
+ for (i = 0; i < chunk; ++i)
+ inbox[i + 2] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT);
+ err = mlx4_WRITE_MTT(dev, mailbox, chunk);
+ } else {
+ chunk = min_t(int, PAGE_SIZE / sizeof(u64), npages);
+ err = mlx4_write_mtt_chunk(dev, mtt, start_index, chunk, page_list);
+ }
if (err)
- return err;
+ goto out;
npages -= chunk;
start_index += chunk;
page_list += chunk;
}
-
- return 0;
+out:
+ if (mlx4_is_slave(dev))
+ mlx4_free_cmd_mailbox(dev, mailbox);
+ return err;
}
EXPORT_SYMBOL_GPL(mlx4_write_mtt);
--
1.6.1.3
^ permalink raw reply related
* [PATCH 05/25] mlx4_core: add slave resource allocation
From: Yevgeny Petrilin @ 2009-11-04 15:30 UTC (permalink / raw)
To: rdreier; +Cc: linux-rdma, netdev, liranl, tziporet, yevgenyp
All QPs/CQs/SRQs/MPTs/MTTs are allocated from shared pools, which are owned by
the master. In addition, all backing ICM memory for these objects is managed by
the master.
To allow slaves to allocate resources, ICM allocation is separated from the rest
of the object state, which is held at the slave.
Slaves can then reserve resource ranges and allocate ICM over the comm channel.
Signed-off-by: Liran Liss <liranl@mellanox.co.il>
---
drivers/net/mlx4/cmd.c | 96 +++++++++++++++++++++++++++++
drivers/net/mlx4/cq.c | 91 +++++++++++++++++++++-------
drivers/net/mlx4/mlx4.h | 27 ++++++++
drivers/net/mlx4/mr.c | 125 ++++++++++++++++++++++++++++++++++----
drivers/net/mlx4/qp.c | 151 +++++++++++++++++++++++++++++++++-------------
drivers/net/mlx4/srq.c | 88 ++++++++++++++++++++-------
include/linux/mlx4/cmd.h | 2 +
7 files changed, 482 insertions(+), 98 deletions(-)
diff --git a/drivers/net/mlx4/cmd.c b/drivers/net/mlx4/cmd.c
index 96462f7..b1701d2 100644
--- a/drivers/net/mlx4/cmd.c
+++ b/drivers/net/mlx4/cmd.c
@@ -418,6 +418,100 @@ int mlx4_ACCESS_MEM(struct mlx4_dev *dev, u64 master_addr, int slave, u64 slave_
MLX4_CMD_TIME_CLASS_A);
}
+static int mlx4_RESOURCE_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vhcr,
+ struct mlx4_cmd_mailbox *inbox,
+ struct mlx4_cmd_mailbox *outbox)
+{
+ u32 param1 = *((u32 *) &vhcr->in_param);
+ u32 param2 = *(((u32 *) &vhcr->in_param) + 1);
+ int ret;
+
+#if 0
+ char *res[] = {"QP", "CQ", "SRQ", "MPT", "MTT"};
+ mlx4_warn(dev, "resource wrapper - %s (mode: %s) type:%s param1:%d param2:%d\n",
+ vhcr->op == MLX4_CMD_ALLOC_RES ? "allocate" : "free",
+ vhcr->op_modifier == ICM_RESERVE ? "reserve" :
+ (vhcr->op_modifier == ICM_ALLOC ? "alloc" : "reserve+alloc"),
+ res[vhcr->in_modifier], param1, param2);
+#endif
+
+ vhcr->errno = 0;
+ switch (vhcr->in_modifier) {
+ case RES_QP:
+ switch (vhcr->op_modifier) {
+ case ICM_RESERVE:
+ if (vhcr->op == MLX4_CMD_ALLOC_RES) {
+ vhcr->errno = mlx4_qp_reserve_range(dev, param1, param2, &ret);
+ if (!vhcr->errno)
+ vhcr->out_param = ret;
+ } else {
+ mlx4_qp_release_range(dev, param1, param2);
+ }
+ break;
+ case ICM_ALLOC:
+ if (vhcr->op == MLX4_CMD_ALLOC_RES)
+ vhcr->errno = mlx4_qp_alloc_icm(dev, param1);
+ else
+ mlx4_qp_free_icm(dev, param1);
+ break;
+ default:
+ vhcr->errno = -EINVAL;
+ }
+ break;
+ case RES_CQ:
+ if (vhcr->op == MLX4_CMD_ALLOC_RES) {
+ vhcr->errno = mlx4_cq_alloc_icm(dev, &ret);
+ if (!vhcr->errno)
+ vhcr->out_param = ret;
+ } else
+ mlx4_cq_free_icm(dev, param1);
+ break;
+ case RES_SRQ:
+ if (vhcr->op == MLX4_CMD_ALLOC_RES) {
+ vhcr->errno = mlx4_srq_alloc_icm(dev, &ret);
+ if (!vhcr->errno)
+ vhcr->out_param = ret;
+ } else
+ mlx4_srq_free_icm(dev, param1);
+ break;
+ case RES_MPT:
+ switch (vhcr->op_modifier) {
+ case ICM_RESERVE:
+ if (vhcr->op == MLX4_CMD_ALLOC_RES) {
+ ret = mlx4_mr_reserve(dev);
+ if (ret == -1)
+ vhcr->errno = -ENOMEM;
+ else
+ vhcr->out_param = ret;
+ } else
+ mlx4_mr_release(dev, param1);
+ break;
+ case ICM_ALLOC:
+ if (vhcr->op == MLX4_CMD_ALLOC_RES)
+ vhcr->errno = mlx4_mr_alloc_icm(dev, param1);
+ else
+ mlx4_mr_free_icm(dev, param1);
+ break;
+ default:
+ vhcr->errno = -EINVAL;
+ }
+ break;
+ case RES_MTT:
+ if (vhcr->op == MLX4_CMD_ALLOC_RES) {
+ ret = mlx4_alloc_mtt_range(dev, param1 /* order */);
+ if (ret == -1)
+ vhcr->errno = -ENOMEM;
+ else
+ vhcr->out_param = ret;
+ } else
+ mlx4_free_mtt_range(dev, param1 /* first */, param2 /* order */);
+ break;
+ default:
+ vhcr->errno = -EINVAL;
+ }
+ return 0;
+}
+
static struct mlx4_cmd_info {
u8 opcode;
u8 has_inbox;
@@ -434,6 +528,8 @@ static struct mlx4_cmd_info {
{MLX4_CMD_SW2HW_EQ, 1, 0, 0, NULL, NULL}, /* need verifier */
{MLX4_CMD_NOP, 0, 0, 0, NULL, NULL},
+ {MLX4_CMD_ALLOC_RES, 0, 0, 1, NULL, mlx4_RESOURCE_wrapper},
+ {MLX4_CMD_FREE_RES, 0, 0, 0, NULL, mlx4_RESOURCE_wrapper},
{MLX4_CMD_SW2HW_MPT, 1, 0, 0, NULL, NULL}, /* need verifier */
{MLX4_CMD_QUERY_MPT, 0, 1, 0, NULL, NULL}, /* need verifier */
diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c
index ccfe276..3fb9f7f 100644
--- a/drivers/net/mlx4/cq.c
+++ b/drivers/net/mlx4/cq.c
@@ -186,6 +186,70 @@ int mlx4_cq_resize(struct mlx4_dev *dev, struct mlx4_cq *cq,
}
EXPORT_SYMBOL_GPL(mlx4_cq_resize);
+int mlx4_cq_alloc_icm(struct mlx4_dev *dev, int *cqn)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_cq_table *cq_table = &priv->cq_table;
+ u64 out_param;
+ int err;
+
+ if (mlx4_is_slave(dev)) {
+ err = mlx4_cmd_imm(dev, 0, &out_param, RES_CQ,
+ ICM_RESERVE_AND_ALLOC,
+ MLX4_CMD_ALLOC_RES,
+ MLX4_CMD_TIME_CLASS_A);
+ if (err) {
+ *cqn = -1;
+ return err;
+ } else {
+ *cqn = out_param;
+ return 0;
+ }
+ }
+
+ *cqn = mlx4_bitmap_alloc(&cq_table->bitmap);
+ if (*cqn == -1)
+ return -ENOMEM;
+
+ err = mlx4_table_get(dev, &cq_table->table, *cqn);
+ if (err)
+ goto err_out;
+
+ err = mlx4_table_get(dev, &cq_table->cmpt_table, *cqn);
+ if (err)
+ goto err_put;
+ return 0;
+
+err_put:
+ mlx4_table_put(dev, &cq_table->table, *cqn);
+
+err_out:
+ mlx4_bitmap_free(&cq_table->bitmap, *cqn);
+ return err;
+}
+
+void mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_cq_table *cq_table = &priv->cq_table;
+ u64 in_param;
+ int err;
+
+ if (mlx4_is_slave(dev)) {
+ *((u32 *) &in_param) = cqn;
+ *(((u32 *) &in_param) + 1) = 0;
+ err = mlx4_cmd(dev, in_param, RES_CQ, ICM_RESERVE_AND_ALLOC,
+ MLX4_CMD_FREE_RES,
+ MLX4_CMD_TIME_CLASS_A);
+ if (err)
+ mlx4_warn(dev, "Failed freeing cq:%d\n", cqn);
+ } else {
+ mlx4_table_put(dev, &cq_table->cmpt_table, cqn);
+ mlx4_table_put(dev, &cq_table->table, cqn);
+ mlx4_bitmap_free(&cq_table->bitmap, cqn);
+ }
+}
+
int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt,
struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq,
unsigned vector, int collapsed)
@@ -202,23 +266,15 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt,
cq->vector = vector;
- cq->cqn = mlx4_bitmap_alloc(&cq_table->bitmap);
- if (cq->cqn == -1)
- return -ENOMEM;
-
- err = mlx4_table_get(dev, &cq_table->table, cq->cqn);
+ err = mlx4_cq_alloc_icm(dev, &cq->cqn);
if (err)
- goto err_out;
-
- err = mlx4_table_get(dev, &cq_table->cmpt_table, cq->cqn);
- if (err)
- goto err_put;
+ return err;
spin_lock_irq(&cq_table->lock);
err = radix_tree_insert(&cq_table->tree, cq->cqn, cq);
spin_unlock_irq(&cq_table->lock);
if (err)
- goto err_cmpt_put;
+ goto err_icm;
mailbox = mlx4_alloc_cmd_mailbox(dev);
if (IS_ERR(mailbox)) {
@@ -257,14 +313,8 @@ err_radix:
radix_tree_delete(&cq_table->tree, cq->cqn);
spin_unlock_irq(&cq_table->lock);
-err_cmpt_put:
- mlx4_table_put(dev, &cq_table->cmpt_table, cq->cqn);
-
-err_put:
- mlx4_table_put(dev, &cq_table->table, cq->cqn);
-
-err_out:
- mlx4_bitmap_free(&cq_table->bitmap, cq->cqn);
+err_icm:
+ mlx4_cq_free_icm(dev, cq->cqn);
return err;
}
@@ -290,8 +340,7 @@ void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq)
complete(&cq->free);
wait_for_completion(&cq->free);
- mlx4_table_put(dev, &cq_table->table, cq->cqn);
- mlx4_bitmap_free(&cq_table->bitmap, cq->cqn);
+ mlx4_cq_free_icm(dev, cq->cqn);
}
EXPORT_SYMBOL_GPL(mlx4_cq_free);
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
index 4796982..91f1215 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/mlx4/mlx4.h
@@ -94,6 +94,21 @@ enum {
MLX4_COMM_CMD_VHCR_POST
};
+enum mlx4_resource {
+ RES_QP,
+ RES_CQ,
+ RES_SRQ,
+ RES_MPT,
+ RES_MTT
+};
+
+enum mlx4_alloc_mode {
+ ICM_RESERVE_AND_ALLOC,
+ ICM_RESERVE,
+ ICM_ALLOC,
+ ICM_MAC_VLAN,
+};
+
enum {
MLX4_MFUNC_MAX_EQES = 8,
MLX4_MFUNC_EQE_MASK = (MLX4_MFUNC_MAX_EQES - 1)
@@ -422,6 +437,18 @@ void mlx4_cleanup_qp_table(struct mlx4_dev *dev);
void mlx4_cleanup_srq_table(struct mlx4_dev *dev);
void mlx4_cleanup_mcg_table(struct mlx4_dev *dev);
+int mlx4_qp_alloc_icm(struct mlx4_dev *dev, int qpn);
+void mlx4_qp_free_icm(struct mlx4_dev *dev, int qpn);
+int mlx4_cq_alloc_icm(struct mlx4_dev *dev, int *cqn);
+void mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn);
+int mlx4_srq_alloc_icm(struct mlx4_dev *dev, int *srqn);
+void mlx4_srq_free_icm(struct mlx4_dev *dev, int srqn);
+int mlx4_mr_reserve(struct mlx4_dev *dev);
+void mlx4_mr_release(struct mlx4_dev *dev, u32 index);
+int mlx4_mr_alloc_icm(struct mlx4_dev *dev, u32 index);
+void mlx4_mr_free_icm(struct mlx4_dev *dev, u32 index);
+u32 mlx4_alloc_mtt_range(struct mlx4_dev *dev, int order);
+void mlx4_free_mtt_range(struct mlx4_dev *dev, u32 first_seg, int order);
int mlx4_WRITE_MTT_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vhcr,
struct mlx4_cmd_mailbox *inbox,
struct mlx4_cmd_mailbox *outbox);
diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c
index 11a3d26..aa1eba6 100644
--- a/drivers/net/mlx4/mr.c
+++ b/drivers/net/mlx4/mr.c
@@ -178,10 +178,26 @@ static void mlx4_buddy_cleanup(struct mlx4_buddy *buddy)
kfree(buddy->num_free);
}
-static u32 mlx4_alloc_mtt_range(struct mlx4_dev *dev, int order)
+u32 mlx4_alloc_mtt_range(struct mlx4_dev *dev, int order)
{
struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table;
+ u64 in_param;
+ u64 out_param;
u32 seg;
+ int err;
+
+ if (mlx4_is_slave(dev)) {
+ *((u32 *) &in_param) = order;
+ *(((u32 *) &in_param) + 1) = 0;
+ err = mlx4_cmd_imm(dev, in_param, &out_param, RES_MTT,
+ ICM_RESERVE_AND_ALLOC,
+ MLX4_CMD_ALLOC_RES,
+ MLX4_CMD_TIME_CLASS_A);
+ if (err)
+ return -1;
+ else
+ return out_param;
+ }
seg = mlx4_buddy_alloc(&mr_table->mtt_buddy, order);
if (seg == -1)
@@ -219,16 +235,33 @@ int mlx4_mtt_init(struct mlx4_dev *dev, int npages, int page_shift,
}
EXPORT_SYMBOL_GPL(mlx4_mtt_init);
-void mlx4_mtt_cleanup(struct mlx4_dev *dev, struct mlx4_mtt *mtt)
+void mlx4_free_mtt_range(struct mlx4_dev *dev, u32 first_seg, int order)
{
struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table;
+ u64 in_param;
+ int err;
+
+ if (mlx4_is_slave(dev)) {
+ *((u32 *) &in_param) = first_seg;
+ *(((u32 *) &in_param) + 1) = order;
+ err = mlx4_cmd(dev, in_param, RES_MTT, ICM_RESERVE_AND_ALLOC,
+ MLX4_CMD_FREE_RES,
+ MLX4_CMD_TIME_CLASS_A);
+ if (err)
+ mlx4_warn(dev, "Failed to free mtt range at:%d order:%d\n", first_seg, order);
+ } else {
+ mlx4_buddy_free(&mr_table->mtt_buddy, first_seg, order);
+ mlx4_table_put_range(dev, &mr_table->mtt_table, first_seg,
+ first_seg + (1 << order) - 1);
+ }
+}
+void mlx4_mtt_cleanup(struct mlx4_dev *dev, struct mlx4_mtt *mtt)
+{
if (mtt->order < 0)
return;
- mlx4_buddy_free(&mr_table->mtt_buddy, mtt->first_seg, mtt->order);
- mlx4_table_put_range(dev, &mr_table->mtt_table, mtt->first_seg,
- mtt->first_seg + (1 << mtt->order) - 1);
+ mlx4_free_mtt_range(dev, mtt->first_seg, mtt->order);
}
EXPORT_SYMBOL_GPL(mlx4_mtt_cleanup);
@@ -291,14 +324,81 @@ static int mlx4_WRITE_MTT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox
MLX4_CMD_TIME_CLASS_A);
}
+int mlx4_mr_reserve(struct mlx4_dev *dev)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ u64 out_param;
+ int err;
+
+ if (mlx4_is_slave(dev)) {
+ err = mlx4_cmd_imm(dev, 0, &out_param, RES_MPT, ICM_RESERVE,
+ MLX4_CMD_ALLOC_RES,
+ MLX4_CMD_TIME_CLASS_A);
+ if (err)
+ return -1;
+ return out_param;
+ }
+ return mlx4_bitmap_alloc(&priv->mr_table.mpt_bitmap);
+}
+
+void mlx4_mr_release(struct mlx4_dev *dev, u32 index)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ u64 in_param;
+ int err;
+
+ if (mlx4_is_slave(dev)) {
+ *((u32 *) &in_param) = index;
+ *(((u32 *) &in_param) + 1) = 0;
+ err = mlx4_cmd(dev, in_param, RES_MPT, ICM_RESERVE,
+ MLX4_CMD_FREE_RES,
+ MLX4_CMD_TIME_CLASS_A);
+ if (err)
+ mlx4_warn(dev, "Failed to release mr index:%d\n", index);
+ } else
+ mlx4_bitmap_free(&priv->mr_table.mpt_bitmap, index);
+}
+
+int mlx4_mr_alloc_icm(struct mlx4_dev *dev, u32 index)
+{
+ struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table;
+ u64 param;
+
+ if (mlx4_is_slave(dev)) {
+ *((u32 *) ¶m) = index;
+ *(((u32 *) ¶m) + 1) = 0;
+ return mlx4_cmd_imm(dev, param, ¶m, RES_MPT, ICM_ALLOC,
+ MLX4_CMD_ALLOC_RES,
+ MLX4_CMD_TIME_CLASS_A);
+ } else
+ return mlx4_table_get(dev, &mr_table->dmpt_table, index);
+}
+
+void mlx4_mr_free_icm(struct mlx4_dev *dev, u32 index)
+{
+ struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table;
+ u64 in_param;
+ int err;
+
+ if (mlx4_is_slave(dev)) {
+ *((u32 *) &in_param) = index;
+ *(((u32 *) &in_param) + 1) = 0;
+ err = mlx4_cmd(dev, in_param, RES_MPT, ICM_ALLOC,
+ MLX4_CMD_FREE_RES,
+ MLX4_CMD_TIME_CLASS_A);
+ if (err)
+ mlx4_warn(dev, "Failed to free icm of mr index:%d\n", index);
+ } else
+ mlx4_table_put(dev, &mr_table->dmpt_table, index);
+}
+
int mlx4_mr_alloc(struct mlx4_dev *dev, u32 pd, u64 iova, u64 size, u32 access,
int npages, int page_shift, struct mlx4_mr *mr)
{
- struct mlx4_priv *priv = mlx4_priv(dev);
u32 index;
int err;
- index = mlx4_bitmap_alloc(&priv->mr_table.mpt_bitmap);
+ index = mlx4_mr_reserve(dev);
if (index == -1)
return -ENOMEM;
@@ -311,7 +411,7 @@ int mlx4_mr_alloc(struct mlx4_dev *dev, u32 pd, u64 iova, u64 size, u32 access,
err = mlx4_mtt_init(dev, npages, page_shift, &mr->mtt);
if (err)
- mlx4_bitmap_free(&priv->mr_table.mpt_bitmap, index);
+ mlx4_mr_release(dev, index);
return err;
}
@@ -319,7 +419,6 @@ EXPORT_SYMBOL_GPL(mlx4_mr_alloc);
void mlx4_mr_free(struct mlx4_dev *dev, struct mlx4_mr *mr)
{
- struct mlx4_priv *priv = mlx4_priv(dev);
int err;
if (mr->enabled) {
@@ -331,18 +430,18 @@ void mlx4_mr_free(struct mlx4_dev *dev, struct mlx4_mr *mr)
}
mlx4_mtt_cleanup(dev, &mr->mtt);
- mlx4_bitmap_free(&priv->mr_table.mpt_bitmap, key_to_hw_index(mr->key));
+ mlx4_mr_release(dev, key_to_hw_index(mr->key));
+ mlx4_mr_free_icm(dev, key_to_hw_index(mr->key));
}
EXPORT_SYMBOL_GPL(mlx4_mr_free);
int mlx4_mr_enable(struct mlx4_dev *dev, struct mlx4_mr *mr)
{
- struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table;
struct mlx4_cmd_mailbox *mailbox;
struct mlx4_mpt_entry *mpt_entry;
int err;
- err = mlx4_table_get(dev, &mr_table->dmpt_table, key_to_hw_index(mr->key));
+ err = mlx4_mr_alloc_icm(dev, key_to_hw_index(mr->key));
if (err)
return err;
@@ -400,7 +499,7 @@ err_cmd:
mlx4_free_cmd_mailbox(dev, mailbox);
err_table:
- mlx4_table_put(dev, &mr_table->dmpt_table, key_to_hw_index(mr->key));
+ mlx4_mr_free_icm(dev, key_to_hw_index(mr->key));
return err;
}
EXPORT_SYMBOL_GPL(mlx4_mr_enable);
diff --git a/drivers/net/mlx4/qp.c b/drivers/net/mlx4/qp.c
index 42ab9fc..065c7fc 100644
--- a/drivers/net/mlx4/qp.c
+++ b/drivers/net/mlx4/qp.c
@@ -149,13 +149,24 @@ int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, int *base)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_qp_table *qp_table = &priv->qp_table;
- int qpn;
-
- qpn = mlx4_bitmap_alloc_range(&qp_table->bitmap, cnt, align);
- if (qpn == -1)
- return -ENOMEM;
+ u64 in_param;
+ u64 out_param;
+ int err;
- *base = qpn;
+ if (mlx4_is_slave(dev)) {
+ *((u32 *) &in_param) = cnt;
+ *(((u32 *) &in_param) + 1) = align;
+ err = mlx4_cmd_imm(dev, in_param, &out_param, RES_QP, ICM_RESERVE,
+ MLX4_CMD_ALLOC_RES,
+ MLX4_CMD_TIME_CLASS_A);
+ if (err)
+ return err;
+ *base = out_param;
+ } else {
+ *base = mlx4_bitmap_alloc_range(&qp_table->bitmap, cnt, align);
+ if (*base == -1)
+ return -ENOMEM;
+ }
return 0;
}
EXPORT_SYMBOL_GPL(mlx4_qp_reserve_range);
@@ -164,73 +175,133 @@ void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_qp_table *qp_table = &priv->qp_table;
- if (base_qpn < dev->caps.sqp_start + 8)
- return;
+ u64 in_param;
+ int err;
- mlx4_bitmap_free_range(&qp_table->bitmap, base_qpn, cnt);
+ if (mlx4_is_slave(dev)) {
+ *((u32 *) &in_param) = base_qpn;
+ *(((u32 *) &in_param) + 1) = cnt;
+ err = mlx4_cmd(dev, in_param, RES_QP, ICM_RESERVE,
+ MLX4_CMD_FREE_RES,
+ MLX4_CMD_TIME_CLASS_A);
+ if (err) {
+ mlx4_warn(dev, "Failed to release qp range base:%d cnt:%d\n",
+ base_qpn, cnt);
+ }
+ } else {
+ if (base_qpn < dev->caps.sqp_start + 8)
+ return;
+ mlx4_bitmap_free_range(&qp_table->bitmap, base_qpn, cnt);
+ }
}
EXPORT_SYMBOL_GPL(mlx4_qp_release_range);
-int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp)
+int mlx4_qp_alloc_icm(struct mlx4_dev *dev, int qpn)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_qp_table *qp_table = &priv->qp_table;
+ u64 param;
int err;
- if (!qpn)
- return -EINVAL;
-
- qp->qpn = qpn;
-
- err = mlx4_table_get(dev, &qp_table->qp_table, qp->qpn);
+ if (mlx4_is_slave(dev)) {
+ *((u32 *) ¶m) = qpn;
+ *(((u32 *) ¶m) + 1) = 0;
+ return mlx4_cmd_imm(dev, param, ¶m, RES_QP, ICM_ALLOC,
+ MLX4_CMD_ALLOC_RES,
+ MLX4_CMD_TIME_CLASS_A);
+ }
+ err = mlx4_table_get(dev, &qp_table->qp_table, qpn);
if (err)
goto err_out;
- err = mlx4_table_get(dev, &qp_table->auxc_table, qp->qpn);
+ err = mlx4_table_get(dev, &qp_table->auxc_table, qpn);
if (err)
goto err_put_qp;
- err = mlx4_table_get(dev, &qp_table->altc_table, qp->qpn);
+ err = mlx4_table_get(dev, &qp_table->altc_table, qpn);
if (err)
goto err_put_auxc;
- err = mlx4_table_get(dev, &qp_table->rdmarc_table, qp->qpn);
+ err = mlx4_table_get(dev, &qp_table->rdmarc_table, qpn);
if (err)
goto err_put_altc;
- err = mlx4_table_get(dev, &qp_table->cmpt_table, qp->qpn);
+ err = mlx4_table_get(dev, &qp_table->cmpt_table, qpn);
if (err)
goto err_put_rdmarc;
- spin_lock_irq(&qp_table->lock);
- err = radix_tree_insert(&dev->qp_table_tree, qp->qpn & (dev->caps.num_qps - 1), qp);
- spin_unlock_irq(&qp_table->lock);
- if (err)
- goto err_put_cmpt;
-
- atomic_set(&qp->refcount, 1);
- init_completion(&qp->free);
-
return 0;
-err_put_cmpt:
- mlx4_table_put(dev, &qp_table->cmpt_table, qp->qpn);
-
err_put_rdmarc:
- mlx4_table_put(dev, &qp_table->rdmarc_table, qp->qpn);
+ mlx4_table_put(dev, &qp_table->rdmarc_table, qpn);
err_put_altc:
- mlx4_table_put(dev, &qp_table->altc_table, qp->qpn);
+ mlx4_table_put(dev, &qp_table->altc_table, qpn);
err_put_auxc:
- mlx4_table_put(dev, &qp_table->auxc_table, qp->qpn);
+ mlx4_table_put(dev, &qp_table->auxc_table, qpn);
err_put_qp:
- mlx4_table_put(dev, &qp_table->qp_table, qp->qpn);
+ mlx4_table_put(dev, &qp_table->qp_table, qpn);
err_out:
return err;
}
+
+void mlx4_qp_free_icm(struct mlx4_dev *dev, int qpn)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_qp_table *qp_table = &priv->qp_table;
+ u64 in_param;
+ int err;
+
+ if (mlx4_is_slave(dev)) {
+ *((u32 *) &in_param) = qpn;
+ *(((u32 *) &in_param) + 1) = 0;
+ err = mlx4_cmd(dev, in_param, RES_QP, ICM_ALLOC,
+ MLX4_CMD_FREE_RES,
+ MLX4_CMD_TIME_CLASS_A);
+ if (err)
+ mlx4_warn(dev, "Failed to free icm of qp:%d\n", qpn);
+ } else {
+ mlx4_table_put(dev, &qp_table->cmpt_table, qpn);
+ mlx4_table_put(dev, &qp_table->rdmarc_table, qpn);
+ mlx4_table_put(dev, &qp_table->altc_table, qpn);
+ mlx4_table_put(dev, &qp_table->auxc_table, qpn);
+ mlx4_table_put(dev, &qp_table->qp_table, qpn);
+ }
+}
+
+int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_qp_table *qp_table = &priv->qp_table;
+ int err;
+
+ if (!qpn)
+ return -EINVAL;
+
+ qp->qpn = qpn;
+
+ err = mlx4_qp_alloc_icm(dev, qpn);
+ if (err)
+ return err;
+
+ spin_lock_irq(&qp_table->lock);
+ err = radix_tree_insert(&dev->qp_table_tree, qp->qpn & (dev->caps.num_qps - 1), qp);
+ spin_unlock_irq(&qp_table->lock);
+ if (err)
+ goto err_icm;
+
+ atomic_set(&qp->refcount, 1);
+ init_completion(&qp->free);
+
+ return 0;
+
+err_icm:
+ mlx4_qp_free_icm(dev, qpn);
+ return err;
+}
EXPORT_SYMBOL_GPL(mlx4_qp_alloc);
void mlx4_qp_remove(struct mlx4_dev *dev, struct mlx4_qp *qp)
@@ -246,17 +317,11 @@ EXPORT_SYMBOL_GPL(mlx4_qp_remove);
void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp)
{
- struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table;
-
if (atomic_dec_and_test(&qp->refcount))
complete(&qp->free);
wait_for_completion(&qp->free);
- mlx4_table_put(dev, &qp_table->cmpt_table, qp->qpn);
- mlx4_table_put(dev, &qp_table->rdmarc_table, qp->qpn);
- mlx4_table_put(dev, &qp_table->altc_table, qp->qpn);
- mlx4_table_put(dev, &qp_table->auxc_table, qp->qpn);
- mlx4_table_put(dev, &qp_table->qp_table, qp->qpn);
+ mlx4_qp_free_icm(dev, qp->qpn);
}
EXPORT_SYMBOL_GPL(mlx4_qp_free);
diff --git a/drivers/net/mlx4/srq.c b/drivers/net/mlx4/srq.c
index 1377d0d..ed11f18 100644
--- a/drivers/net/mlx4/srq.c
+++ b/drivers/net/mlx4/srq.c
@@ -108,32 +108,86 @@ static int mlx4_QUERY_SRQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox
MLX4_CMD_TIME_CLASS_A);
}
-int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, struct mlx4_mtt *mtt,
- u64 db_rec, struct mlx4_srq *srq)
+int mlx4_srq_alloc_icm(struct mlx4_dev *dev, int *srqn)
{
struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
- struct mlx4_cmd_mailbox *mailbox;
- struct mlx4_srq_context *srq_context;
- u64 mtt_addr;
+ u64 out_param;
int err;
- srq->srqn = mlx4_bitmap_alloc(&srq_table->bitmap);
- if (srq->srqn == -1)
+ if (mlx4_is_slave(dev)) {
+ err = mlx4_cmd_imm(dev, 0, &out_param, RES_SRQ,
+ ICM_RESERVE_AND_ALLOC,
+ MLX4_CMD_ALLOC_RES,
+ MLX4_CMD_TIME_CLASS_A);
+ if (err) {
+ *srqn = -1;
+ return err;
+ } else {
+ *srqn = out_param;
+ return 0;
+ }
+ }
+
+ *srqn = mlx4_bitmap_alloc(&srq_table->bitmap);
+ if (*srqn == -1)
return -ENOMEM;
- err = mlx4_table_get(dev, &srq_table->table, srq->srqn);
+ err = mlx4_table_get(dev, &srq_table->table, *srqn);
if (err)
goto err_out;
- err = mlx4_table_get(dev, &srq_table->cmpt_table, srq->srqn);
+ err = mlx4_table_get(dev, &srq_table->cmpt_table, *srqn);
if (err)
goto err_put;
+ return 0;
+
+err_put:
+ mlx4_table_put(dev, &srq_table->table, *srqn);
+
+err_out:
+ mlx4_bitmap_free(&srq_table->bitmap, *srqn);
+ return err;
+}
+
+void mlx4_srq_free_icm(struct mlx4_dev *dev, int srqn)
+{
+ struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
+ u64 in_param;
+ int err;
+
+ if (mlx4_is_slave(dev)) {
+ *((u32 *) &in_param) = srqn;
+ *(((u32 *) &in_param) + 1) = 0;
+ err = mlx4_cmd(dev, in_param, RES_SRQ, ICM_RESERVE_AND_ALLOC,
+ MLX4_CMD_FREE_RES,
+ MLX4_CMD_TIME_CLASS_A);
+ if (err)
+ mlx4_warn(dev, "Failed freeing cq:%d\n", srqn);
+ } else {
+ mlx4_table_put(dev, &srq_table->cmpt_table, srqn);
+ mlx4_table_put(dev, &srq_table->table, srqn);
+ mlx4_bitmap_free(&srq_table->bitmap, srqn);
+ }
+}
+
+int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, struct mlx4_mtt *mtt,
+ u64 db_rec, struct mlx4_srq *srq)
+{
+ struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
+ struct mlx4_cmd_mailbox *mailbox;
+ struct mlx4_srq_context *srq_context;
+ u64 mtt_addr;
+ int err;
+
+ err = mlx4_srq_alloc_icm(dev, &srq->srqn);
+ if (err)
+ return err;
spin_lock_irq(&srq_table->lock);
err = radix_tree_insert(&srq_table->tree, srq->srqn, srq);
spin_unlock_irq(&srq_table->lock);
if (err)
- goto err_cmpt_put;
+ goto err_icm;
mailbox = mlx4_alloc_cmd_mailbox(dev);
if (IS_ERR(mailbox)) {
@@ -170,15 +224,8 @@ err_radix:
radix_tree_delete(&srq_table->tree, srq->srqn);
spin_unlock_irq(&srq_table->lock);
-err_cmpt_put:
- mlx4_table_put(dev, &srq_table->cmpt_table, srq->srqn);
-
-err_put:
- mlx4_table_put(dev, &srq_table->table, srq->srqn);
-
-err_out:
- mlx4_bitmap_free(&srq_table->bitmap, srq->srqn);
-
+err_icm:
+ mlx4_srq_free_icm(dev, srq->srqn);
return err;
}
EXPORT_SYMBOL_GPL(mlx4_srq_alloc);
@@ -200,8 +247,7 @@ void mlx4_srq_free(struct mlx4_dev *dev, struct mlx4_srq *srq)
complete(&srq->free);
wait_for_completion(&srq->free);
- mlx4_table_put(dev, &srq_table->table, srq->srqn);
- mlx4_bitmap_free(&srq_table->bitmap, srq->srqn);
+ mlx4_srq_free_icm(dev, srq->srqn);
}
EXPORT_SYMBOL_GPL(mlx4_srq_free);
diff --git a/include/linux/mlx4/cmd.h b/include/linux/mlx4/cmd.h
index dda1762..dceb93f 100644
--- a/include/linux/mlx4/cmd.h
+++ b/include/linux/mlx4/cmd.h
@@ -120,6 +120,8 @@ enum {
MLX4_CMD_ACCESS_MEM = 0x2e,
/* virtual commands */
+ MLX4_CMD_ALLOC_RES = 0x50,
+ MLX4_CMD_FREE_RES = 0x51,
MLX4_CMD_GET_EVENT = 0x52,
/* debug commands */
--
1.6.1.3
^ permalink raw reply related
* [PATCH 09/25] mlx4_core: dispatch slave asynch events
From: Yevgeny Petrilin @ 2009-11-04 15:30 UTC (permalink / raw)
To: rdreier; +Cc: linux-rdma, netdev, liranl, tziporet, yevgenyp
Affiliated and unaffiliated asynch events are handled by a single EQ owned by
the master. A per-slave SW event queue is added to log and dispatch both slave-specific
events and events that apply to all slaves.
Signed-off-by: Liran Liss <liranl@mellanox.co.il>
---
drivers/net/mlx4/cmd.c | 5 ++-
drivers/net/mlx4/eq.c | 92 +++++++++++++++++++++++++++++++++++++++++++---
drivers/net/mlx4/mlx4.h | 8 ++++
3 files changed, 98 insertions(+), 7 deletions(-)
diff --git a/drivers/net/mlx4/cmd.c b/drivers/net/mlx4/cmd.c
index d2646d1..0a7c9c0 100644
--- a/drivers/net/mlx4/cmd.c
+++ b/drivers/net/mlx4/cmd.c
@@ -535,6 +535,7 @@ static struct mlx4_cmd_info {
{MLX4_CMD_NOP, 0, 0, 0, NULL, NULL},
{MLX4_CMD_ALLOC_RES, 0, 0, 1, NULL, mlx4_RESOURCE_wrapper},
{MLX4_CMD_FREE_RES, 0, 0, 0, NULL, mlx4_RESOURCE_wrapper},
+ {MLX4_CMD_GET_EVENT, 0, 0, 1, NULL, mlx4_GET_EVENT_wrapper},
{MLX4_CMD_SW2HW_MPT, 1, 0, 0, NULL, NULL}, /* need verifier */
{MLX4_CMD_QUERY_MPT, 0, 1, 0, NULL, NULL}, /* need verifier */
@@ -829,8 +830,10 @@ int mlx4_multi_func_init(struct mlx4_dev *dev)
if (!priv->mfunc.master.slave_state)
goto err_comm;
- for (i = 0; i < dev->num_slaves; ++i)
+ for (i = 0; i < dev->num_slaves; ++i) {
priv->mfunc.master.slave_state[i].last_cmd = MLX4_COMM_CMD_RESET;
+ spin_lock_init(&priv->mfunc.master.slave_state[i].lock);
+ }
INIT_DELAYED_WORK(&priv->mfunc.comm_work, mlx4_master_poll_comm);
priv->mfunc.comm_wq = create_singlethread_workqueue("mlx4_comm");
diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c
index 70c16d4..1e8b62d 100644
--- a/drivers/net/mlx4/eq.c
+++ b/drivers/net/mlx4/eq.c
@@ -160,6 +160,61 @@ static struct mlx4_eqe *next_eqe_sw(struct mlx4_eq *eq)
return !!(eqe->owner & 0x80) ^ !!(eq->cons_index & eq->nent) ? NULL : eqe;
}
+void mlx4_slave_event(struct mlx4_dev *dev, int slave, u8 type, u8 port, u32 param)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_slave_state *ctx = &priv->mfunc.master.slave_state[slave];
+ unsigned long flags;
+
+ if (ctx->last_cmd != MLX4_COMM_CMD_VHCR_POST) {
+ mlx4_warn(dev, "received event for inactive slave:%d\n", slave);
+ return;
+ }
+
+ /* Unconditionally add the new event - during overflows, we drop the
+ * oldest events */
+ spin_lock_irqsave(&ctx->lock, flags);
+ ctx->eq[ctx->eq_pi & MLX4_MFUNC_EQE_MASK].type = type;
+ ctx->eq[ctx->eq_pi & MLX4_MFUNC_EQE_MASK].port = port;
+ ctx->eq[ctx->eq_pi & MLX4_MFUNC_EQE_MASK].param = param;
+ ++ctx->eq_pi;
+ spin_unlock_irqrestore(&ctx->lock, flags);
+}
+
+static void mlx4_slave_event_all(struct mlx4_dev *dev, u8 type, u8 port, u32 param)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ int i;
+
+ for (i = 0; i < dev->num_slaves; ++i)
+ if (priv->mfunc.master.slave_state[i].last_cmd == MLX4_COMM_CMD_VHCR_POST)
+ mlx4_slave_event(dev, i, type, port, param);
+}
+
+int mlx4_GET_EVENT_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vhcr,
+ struct mlx4_cmd_mailbox *inbox,
+ struct mlx4_cmd_mailbox *outbox)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_slave_state *ctx = &priv->mfunc.master.slave_state[slave];
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctx->lock, flags);
+ if (ctx->eq_ci == ctx->eq_pi) {
+ vhcr->out_param = MLX4_EVENT_TYPE_NONE;
+ } else if ((u16) (ctx->eq_pi - ctx->eq_ci) > MLX4_MFUNC_MAX_EQES) {
+ ctx->eq_ci = ctx->eq_pi - MLX4_MFUNC_MAX_EQES;
+ vhcr->out_param = MLX4_EVENT_TYPE_EQ_OVERFLOW;
+ } else {
+ vhcr->out_param = ctx->eq[ctx->eq_ci & MLX4_MFUNC_EQE_MASK].type |
+ ((u64) ctx->eq[ctx->eq_ci & MLX4_MFUNC_EQE_MASK].port << 8) |
+ ((u64) ctx->eq[ctx->eq_ci & MLX4_MFUNC_EQE_MASK].param << 32);
+ ++ctx->eq_ci;
+ }
+ spin_unlock_irqrestore(&ctx->lock, flags);
+ return 0;
+}
+
static int mlx4_GET_EVENT(struct mlx4_dev *dev, struct mlx4_slave_eqe *eqe)
{
int ret;
@@ -205,14 +260,26 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
case MLX4_EVENT_TYPE_PATH_MIG_FAILED:
case MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
case MLX4_EVENT_TYPE_WQ_ACCESS_ERROR:
- mlx4_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 0xffffff,
- eqe->type);
+ if (mlx4_is_master(dev)) {
+ /* TODO: forward only to slave owning the QP */
+ mlx4_slave_event(dev, 0, eqe->type, 0,
+ be32_to_cpu(eqe->event.qp.qpn) &
+ 0xffffff);
+ } else
+ mlx4_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) &
+ 0xffffff, eqe->type);
break;
case MLX4_EVENT_TYPE_SRQ_LIMIT:
case MLX4_EVENT_TYPE_SRQ_CATAS_ERROR:
- mlx4_srq_event(dev, be32_to_cpu(eqe->event.srq.srqn) & 0xffffff,
- eqe->type);
+ if (mlx4_is_master(dev)) {
+ /* TODO: forward only to slave owning the SRQ */
+ mlx4_slave_event(dev, 0, eqe->type, 0,
+ be32_to_cpu(eqe->event.srq.srqn) &
+ 0xffffff);
+ } else
+ mlx4_srq_event(dev, be32_to_cpu(eqe->event.srq.srqn) &
+ 0xffffff, eqe->type);
break;
case MLX4_EVENT_TYPE_CMD:
@@ -227,10 +294,18 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
if (eqe->subtype == MLX4_PORT_CHANGE_SUBTYPE_DOWN) {
mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_DOWN,
port);
+ if (mlx4_is_master(dev)) {
+ mlx4_slave_event_all(dev, MLX4_EVENT_TYPE_PORT_CHANGE,
+ port, MLX4_DEV_EVENT_PORT_DOWN);
+ }
mlx4_priv(dev)->sense.do_sense_port[port] = 1;
} else {
mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_UP,
port);
+ if (mlx4_is_master(dev)) {
+ mlx4_slave_event_all(dev, MLX4_EVENT_TYPE_PORT_CHANGE,
+ port, MLX4_DEV_EVENT_PORT_UP);
+ }
mlx4_priv(dev)->sense.do_sense_port[port] = 0;
}
break;
@@ -240,8 +315,13 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
eqe->event.cq_err.syndrome == 1 ?
"overrun" : "access violation",
be32_to_cpu(eqe->event.cq_err.cqn) & 0xffffff);
- mlx4_cq_event(dev, be32_to_cpu(eqe->event.cq_err.cqn),
- eqe->type);
+ if (mlx4_is_master(dev)) {
+ /* TODO: forward only to slave owning the CQ */
+ mlx4_slave_event(dev, 0, eqe->type, 0,
+ be32_to_cpu(eqe->event.cq_err.cqn));
+ } else
+ mlx4_cq_event(dev, be32_to_cpu(eqe->event.cq_err.cqn),
+ eqe->type);
break;
case MLX4_EVENT_TYPE_EQ_OVERFLOW:
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
index 8a7a041..fb1c6f0 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/mlx4/mlx4.h
@@ -216,6 +216,10 @@ struct mlx4_slave_state {
u8 init_port_mask;
dma_addr_t vhcr_dma;
__be32 ib_cap_mask[MLX4_MAX_PORTS + 1];
+ struct mlx4_slave_eqe eq[MLX4_MFUNC_MAX_EQES];
+ u16 eq_pi;
+ u16 eq_ci;
+ spinlock_t lock;
};
struct mlx4_mfunc_master_ctx {
@@ -422,6 +426,10 @@ int mlx4_reset(struct mlx4_dev *dev);
int mlx4_alloc_eq_table(struct mlx4_dev *dev);
void mlx4_free_eq_table(struct mlx4_dev *dev);
+void mlx4_slave_event(struct mlx4_dev *dev, int slave, u8 type, u8 port, u32 param);
+int mlx4_GET_EVENT_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vhcr,
+ struct mlx4_cmd_mailbox *inbox,
+ struct mlx4_cmd_mailbox *outbox);
int mlx4_init_pd_table(struct mlx4_dev *dev);
int mlx4_init_uar_table(struct mlx4_dev *dev);
--
1.6.1.3
^ permalink raw reply related
* [PATCH 14/25] mlx4_core: multi-function resource setup
From: Yevgeny Petrilin @ 2009-11-04 15:31 UTC (permalink / raw)
To: rdreier; +Cc: linux-rdma, netdev, liranl, tziporet, yevgenyp
Only master function needs to configure eq asynch events, and initialize resource
allocators.
Signed-off-by: Liran Liss <liranl@mellanox.co.il>
---
drivers/net/mlx4/cq.c | 4 +++
drivers/net/mlx4/eq.c | 61 ++++++++++++++++++++++++------------------
drivers/net/mlx4/main.c | 45 +++++++++++++++++--------------
drivers/net/mlx4/mcg.c | 6 ++++
drivers/net/mlx4/mr.c | 6 ++++
drivers/net/mlx4/pd.c | 12 ++++++--
drivers/net/mlx4/qp.c | 33 ++++++++++++++++++++++-
drivers/net/mlx4/srq.c | 4 +++
include/linux/mlx4/device.h | 1 +
9 files changed, 121 insertions(+), 51 deletions(-)
diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c
index 9f9f246..b605041 100644
--- a/drivers/net/mlx4/cq.c
+++ b/drivers/net/mlx4/cq.c
@@ -353,6 +353,8 @@ int mlx4_init_cq_table(struct mlx4_dev *dev)
spin_lock_init(&cq_table->lock);
INIT_RADIX_TREE(&cq_table->tree, GFP_ATOMIC);
+ if (mlx4_is_slave(dev))
+ return 0;
err = mlx4_bitmap_init(&cq_table->bitmap, dev->caps.num_cqs,
dev->caps.num_cqs - 1, dev->caps.reserved_cqs, 0);
@@ -364,6 +366,8 @@ int mlx4_init_cq_table(struct mlx4_dev *dev)
void mlx4_cleanup_cq_table(struct mlx4_dev *dev)
{
+ if (mlx4_is_slave(dev))
+ return;
/* Nothing to do to clean up radix_tree */
mlx4_bitmap_cleanup(&mlx4_priv(dev)->cq_table.bitmap);
}
diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c
index 46064cc..b0c8022 100644
--- a/drivers/net/mlx4/eq.c
+++ b/drivers/net/mlx4/eq.c
@@ -732,39 +732,42 @@ int mlx4_init_eq_table(struct mlx4_dev *dev)
goto err_out_free;
}
- err = mlx4_bitmap_init(&priv->eq_table.bitmap, dev->caps.num_eqs,
- dev->caps.num_eqs - 1, dev->caps.reserved_eqs, 0);
+ err = mlx4_bitmap_init_no_mask(&priv->eq_table.bitmap, dev->caps.num_eqs,
+ dev->caps.reserved_eqs, 0);
if (err)
goto err_out_free;
for (i = 0; i < mlx4_num_eq_uar(dev); ++i)
priv->eq_table.uar_map[i] = NULL;
- err = mlx4_map_clr_int(dev);
- if (err)
- goto err_out_bitmap;
+ if (!mlx4_is_slave(dev)) {
+ err = mlx4_map_clr_int(dev);
+ if (err)
+ goto err_out_bitmap;
- priv->eq_table.clr_mask =
- swab32(1 << (priv->eq_table.inta_pin & 31));
- priv->eq_table.clr_int = priv->clr_base +
- (priv->eq_table.inta_pin < 32 ? 4 : 0);
+ priv->eq_table.clr_mask =
+ swab32(1 << (priv->eq_table.inta_pin & 31));
+ priv->eq_table.clr_int = priv->clr_base +
+ (priv->eq_table.inta_pin < 32 ? 4 : 0);
+ }
priv->eq_table.irq_names =
kmalloc(MLX4_IRQNAME_SIZE * (dev->caps.num_comp_vectors + 1),
GFP_KERNEL);
if (!priv->eq_table.irq_names) {
err = -ENOMEM;
- goto err_out_bitmap;
+ i = 0;
+ goto err_out_unmap;
}
for (i = 0; i < dev->caps.num_comp_vectors; ++i) {
- err = mlx4_create_eq(dev, dev->caps.num_cqs + MLX4_NUM_SPARE_EQE,
+ err = mlx4_create_eq(dev, dev->caps.num_cqs -
+ dev->caps.reserved_cqs +
+ MLX4_NUM_SPARE_EQE,
(dev->flags & MLX4_FLAG_MSI_X) ? i : 0,
&priv->eq_table.eq[i]);
- if (err) {
- --i;
+ if (err)
goto err_out_unmap;
- }
}
err = mlx4_create_eq(dev, MLX4_NUM_ASYNC_EQE + MLX4_NUM_SPARE_EQE,
@@ -814,11 +817,13 @@ int mlx4_init_eq_table(struct mlx4_dev *dev)
priv->eq_table.have_irq = 1;
}
- err = mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 0,
- priv->eq_table.eq[dev->caps.num_comp_vectors].eqn);
- if (err)
- mlx4_warn(dev, "MAP_EQ for async EQ %d failed (%d)\n",
- priv->eq_table.eq[dev->caps.num_comp_vectors].eqn, err);
+ if (!mlx4_is_slave(dev)) { /* hw async events cannot be shared */
+ err = mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 0,
+ priv->eq_table.eq[dev->caps.num_comp_vectors].eqn);
+ if (err)
+ mlx4_warn(dev, "MAP_EQ for async EQ %d failed (%d)\n",
+ priv->eq_table.eq[dev->caps.num_comp_vectors].eqn, err);
+ }
for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i)
eq_set_ci(&priv->eq_table.eq[i], 1);
@@ -829,14 +834,15 @@ err_out_async:
mlx4_free_eq(dev, &priv->eq_table.eq[dev->caps.num_comp_vectors]);
err_out_comp:
- i = dev->caps.num_comp_vectors - 1;
+ i = dev->caps.num_comp_vectors;
err_out_unmap:
- while (i >= 0) {
- mlx4_free_eq(dev, &priv->eq_table.eq[i]);
+ while (i > 0) {
--i;
+ mlx4_free_eq(dev, &priv->eq_table.eq[i]);
}
- mlx4_unmap_clr_int(dev);
+ if (!mlx4_is_slave(dev))
+ mlx4_unmap_clr_int(dev);
mlx4_free_irqs(dev);
err_out_bitmap:
@@ -853,15 +859,18 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev)
struct mlx4_priv *priv = mlx4_priv(dev);
int i;
- mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 1,
- priv->eq_table.eq[dev->caps.num_comp_vectors].eqn);
+ if (!mlx4_is_slave(dev)) {
+ mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 1,
+ priv->eq_table.eq[dev->caps.num_comp_vectors].eqn);
+ }
mlx4_free_irqs(dev);
for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i)
mlx4_free_eq(dev, &priv->eq_table.eq[i]);
- mlx4_unmap_clr_int(dev);
+ if (!mlx4_is_slave(dev))
+ mlx4_unmap_clr_int(dev);
for (i = 0; i < mlx4_num_eq_uar(dev); ++i)
if (priv->eq_table.uar_map[i])
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index d8143c6..2852445 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -904,11 +904,14 @@ static int mlx4_setup_hca(struct mlx4_dev *dev)
goto err_mr_table_free;
}
- err = mlx4_cmd_use_events(dev);
- if (err) {
- mlx4_err(dev, "Failed to switch to event-driven "
- "firmware commands, aborting.\n");
- goto err_eq_table_free;
+ /* CX1: no comm channel events */
+ if (!mlx4_is_master(dev) && !mlx4_is_slave(dev)) {
+ err = mlx4_cmd_use_events(dev);
+ if (err) {
+ mlx4_err(dev, "Failed to switch to event-driven "
+ "firmware commands, aborting.\n");
+ goto err_eq_table_free;
+ }
}
err = mlx4_NOP(dev);
@@ -958,22 +961,23 @@ static int mlx4_setup_hca(struct mlx4_dev *dev)
goto err_qp_table_free;
}
- for (port = 1; port <= dev->caps.num_ports; port++) {
- ib_port_default_caps = 0;
- err = mlx4_get_port_ib_caps(dev, port, &ib_port_default_caps);
- if (err)
- mlx4_warn(dev, "failed to get port %d default "
- "ib capabilities (%d). Continuing with "
- "caps = 0\n", port, err);
- dev->caps.ib_port_def_cap[port] = ib_port_default_caps;
- err = mlx4_SET_PORT(dev, port);
- if (err) {
- mlx4_err(dev, "Failed to set port %d, aborting\n",
- port);
- goto err_mcg_table_free;
+ if (!mlx4_is_slave(dev)) {
+ for (port = 1; port <= dev->caps.num_ports; port++) {
+ ib_port_default_caps = 0;
+ err = mlx4_get_port_ib_caps(dev, port, &ib_port_default_caps);
+ if (err)
+ mlx4_warn(dev, "failed to get port %d default "
+ "ib capabilities (%d). Continuing with "
+ "caps = 0\n", port, err);
+ dev->caps.ib_port_def_cap[port] = ib_port_default_caps;
+ err = mlx4_SET_PORT(dev, port);
+ if (err) {
+ mlx4_err(dev, "Failed to set port %d, aborting\n",
+ port);
+ goto err_mcg_table_free;
+ }
}
}
-
return 0;
err_mcg_table_free:
@@ -989,7 +993,8 @@ err_cq_table_free:
mlx4_cleanup_cq_table(dev);
err_cmd_poll:
- mlx4_cmd_use_polling(dev);
+ if (!mlx4_is_master(dev) && !mlx4_is_slave(dev))
+ mlx4_cmd_use_polling(dev);
err_eq_table_free:
mlx4_cleanup_eq_table(dev);
diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c
index 96f09ed..daa08f1 100644
--- a/drivers/net/mlx4/mcg.c
+++ b/drivers/net/mlx4/mcg.c
@@ -393,6 +393,10 @@ int mlx4_init_mcg_table(struct mlx4_dev *dev)
struct mlx4_priv *priv = mlx4_priv(dev);
int err;
+ /* Nothing to do for slaves - mcg handling is para-virtualized */
+ if (mlx4_is_slave(dev))
+ return 0;
+
err = mlx4_bitmap_init(&priv->mcg_table.bitmap, dev->caps.num_amgms,
dev->caps.num_amgms - 1, 0, 0);
if (err)
@@ -405,5 +409,7 @@ int mlx4_init_mcg_table(struct mlx4_dev *dev)
void mlx4_cleanup_mcg_table(struct mlx4_dev *dev)
{
+ if (mlx4_is_slave(dev))
+ return;
mlx4_bitmap_cleanup(&mlx4_priv(dev)->mcg_table.bitmap);
}
diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c
index aa1eba6..522d29a 100644
--- a/drivers/net/mlx4/mr.c
+++ b/drivers/net/mlx4/mr.c
@@ -612,6 +612,10 @@ int mlx4_init_mr_table(struct mlx4_dev *dev)
struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table;
int err;
+ /* Nothing to do for slaves - all MR handling is forwarded to the master */
+ if (mlx4_is_slave(dev))
+ return 0;
+
err = mlx4_bitmap_init(&mr_table->mpt_bitmap, dev->caps.num_mpts,
~0, dev->caps.reserved_mrws, 0);
if (err)
@@ -646,6 +650,8 @@ void mlx4_cleanup_mr_table(struct mlx4_dev *dev)
{
struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table;
+ if (mlx4_is_slave(dev))
+ return;
mlx4_buddy_cleanup(&mr_table->mtt_buddy);
mlx4_bitmap_cleanup(&mr_table->mpt_bitmap);
}
diff --git a/drivers/net/mlx4/pd.c b/drivers/net/mlx4/pd.c
index 08eaf08..db7e2f4 100644
--- a/drivers/net/mlx4/pd.c
+++ b/drivers/net/mlx4/pd.c
@@ -96,6 +96,10 @@ EXPORT_SYMBOL_GPL(mlx4_uar_free);
int mlx4_init_uar_table(struct mlx4_dev *dev)
{
+ /* CX1: master doesn't have UARs */
+ if (mlx4_is_master(dev))
+ return 0;
+
if (dev->caps.num_uars <= 128) {
mlx4_err(dev, "Only %d UAR pages (need more than 128)\n",
dev->caps.num_uars);
@@ -103,12 +107,14 @@ int mlx4_init_uar_table(struct mlx4_dev *dev)
return -ENODEV;
}
- return mlx4_bitmap_init(&mlx4_priv(dev)->uar_table.bitmap,
- dev->caps.num_uars, dev->caps.num_uars - 1,
- max(128, dev->caps.reserved_uars), 0);
+ return mlx4_bitmap_init_no_mask(&mlx4_priv(dev)->uar_table.bitmap,
+ dev->caps.num_uars,
+ dev->caps.reserved_uars, 0);
}
void mlx4_cleanup_uar_table(struct mlx4_dev *dev)
{
+ if (mlx4_is_master(dev))
+ return;
mlx4_bitmap_cleanup(&mlx4_priv(dev)->uar_table.bitmap);
}
diff --git a/drivers/net/mlx4/qp.c b/drivers/net/mlx4/qp.c
index 99b9ded..60c1d7f 100644
--- a/drivers/net/mlx4/qp.c
+++ b/drivers/net/mlx4/qp.c
@@ -406,6 +406,23 @@ int mlx4_init_qp_table(struct mlx4_dev *dev)
spin_lock_init(&qp_table->lock);
INIT_RADIX_TREE(&dev->qp_table_tree, GFP_ATOMIC);
+ if (mlx4_is_slave(dev)) {
+ /* For each slave, just allocate a normal 8-byte alligned special-QP
+ * range intead of mlx4_init_qp_table() reservation */
+ err = mlx4_qp_reserve_range(dev, 8, 8, &dev->caps.sqp_start);
+ if (err) {
+ mlx4_err(dev, "Failed to allocate special QP range\n");
+ return err;
+ }
+
+ err = mlx4_CONF_SPECIAL_QP(dev, dev->caps.sqp_start);
+ if (err) {
+ mlx4_err(dev, "Failed to configure special QP range\n");
+ mlx4_qp_release_range(dev, dev->caps.sqp_start, 8);
+ return err;
+ }
+ return 0;
+ }
/*
* We reserve 2 extra QPs per port for the special QPs. The
@@ -415,6 +432,10 @@ int mlx4_init_qp_table(struct mlx4_dev *dev)
dev->caps.sqp_start =
ALIGN(dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], 8);
+ /* If multi-function is enabled, we reserve an additional QP for qp0/1 tunneling.
+ * CX1: slave0 manages tunnel QP */
+ dev->caps.tunnel_qpn = mlx4_is_master(dev) ? dev->caps.sqp_start + 8 : 0;
+
{
int sort[MLX4_NUM_QP_REGION];
int i, j, tmp;
@@ -444,17 +465,25 @@ int mlx4_init_qp_table(struct mlx4_dev *dev)
}
err = mlx4_bitmap_init(&qp_table->bitmap, dev->caps.num_qps,
- (1 << 23) - 1, dev->caps.sqp_start + 8,
- reserved_from_top);
+ (1 << 23) - 1, dev->caps.sqp_start + 8 +
+ 2 * !!dev->caps.tunnel_qpn, reserved_from_top);
if (err)
return err;
+ /* CX1: master has no QPs */
+ if (mlx4_is_master(dev))
+ return 0;
+
return mlx4_CONF_SPECIAL_QP(dev, dev->caps.sqp_start);
}
void mlx4_cleanup_qp_table(struct mlx4_dev *dev)
{
mlx4_CONF_SPECIAL_QP(dev, 0);
+ if (mlx4_is_slave(dev)) {
+ mlx4_qp_release_range(dev, dev->caps.sqp_start, 8);
+ return;
+ }
mlx4_bitmap_cleanup(&mlx4_priv(dev)->qp_table.bitmap);
}
diff --git a/drivers/net/mlx4/srq.c b/drivers/net/mlx4/srq.c
index ed11f18..3050318 100644
--- a/drivers/net/mlx4/srq.c
+++ b/drivers/net/mlx4/srq.c
@@ -287,6 +287,8 @@ int mlx4_init_srq_table(struct mlx4_dev *dev)
spin_lock_init(&srq_table->lock);
INIT_RADIX_TREE(&srq_table->tree, GFP_ATOMIC);
+ if (mlx4_is_slave(dev))
+ return 0;
err = mlx4_bitmap_init(&srq_table->bitmap, dev->caps.num_srqs,
dev->caps.num_srqs - 1, dev->caps.reserved_srqs, 0);
@@ -298,5 +300,7 @@ int mlx4_init_srq_table(struct mlx4_dev *dev)
void mlx4_cleanup_srq_table(struct mlx4_dev *dev)
{
+ if (mlx4_is_slave(dev))
+ return;
mlx4_bitmap_cleanup(&mlx4_priv(dev)->srq_table.bitmap);
}
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index 4b9091a..bbd398b 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -204,6 +204,7 @@ struct mlx4_caps {
int max_qp_init_rdma;
int max_qp_dest_rdma;
int sqp_start;
+ int tunnel_qpn;
int num_srqs;
int max_srq_wqes;
int max_srq_sge;
--
1.6.1.3
^ permalink raw reply related
* [PATCH 20/25] mlx4: Managing SET_PORT for En port for multi-func
From: Yevgeny Petrilin @ 2009-11-04 15:31 UTC (permalink / raw)
To: rdreier; +Cc: linux-rdma, netdev, liranl, tziporet, yevgenyp
MTU is set as max among all active functions.
The base QP number is the base QP number of the port.
Signed-off-by: Yevgeny Petrilin <yevgenyp@mellanox.co.il>
---
drivers/net/mlx4/mlx4.h | 2 +
drivers/net/mlx4/port.c | 56 ++++++++++++++++++++++++++++++++++++++++++---
include/linux/mlx4/cmd.h | 1 +
3 files changed, 55 insertions(+), 4 deletions(-)
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
index 3e434e4..1213de6 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/mlx4/mlx4.h
@@ -221,6 +221,7 @@ struct mlx4_slave_state {
u8 last_cmd;
u8 init_port_mask;
dma_addr_t vhcr_dma;
+ u16 mtu[MLX4_MAX_PORTS + 1];
__be32 ib_cap_mask[MLX4_MAX_PORTS + 1];
struct mlx4_slave_eqe eq[MLX4_MFUNC_MAX_EQES];
u16 eq_pi;
@@ -232,6 +233,7 @@ struct mlx4_slave_state {
struct mlx4_mfunc_master_ctx {
struct mlx4_slave_state *slave_state;
int init_port_ref[MLX4_MAX_PORTS + 1];
+ u16 max_mtu[MLX4_MAX_PORTS + 1];
};
struct mlx4_vhcr {
diff --git a/drivers/net/mlx4/port.c b/drivers/net/mlx4/port.c
index 6e729dd..02b56ba 100644
--- a/drivers/net/mlx4/port.c
+++ b/drivers/net/mlx4/port.c
@@ -36,6 +36,7 @@
#include <linux/mlx4/cmd.h>
#include "mlx4.h"
+#include "en_port.h"
#define MLX4_MAC_VALID (1ull << 63)
#define MLX4_MAC_MASK 0xffffffffffffULL
@@ -351,9 +352,17 @@ int mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vhc
struct mlx4_cmd_mailbox *outbox)
{
struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_port_info *port_info;
+ struct mlx4_mfunc_master_ctx *master = &priv->mfunc.master;
+ struct mlx4_slave_state *slave_st = &master->slave_state[slave];
+ struct mlx4_set_port_rqp_calc_context *qpn_context;
+ struct mlx4_set_port_general_context *gen_context;
int reset_qkey_viols;
int port;
int is_eth;
+ u32 in_modifier;
+ u32 promisc;
+ u16 mtu, prev_mtu;
int err;
int i;
__be32 agg_cap_mask;
@@ -361,13 +370,52 @@ int mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vhc
__be32 new_cap_mask;
port = vhcr->in_modifier & 0xff;
+ in_modifier = vhcr->in_modifier >> 8;
is_eth = vhcr->op_modifier;
+ port_info = &priv->port[port];
- /* For Ethernet, we currently support only slave0.
- * TODO: add multi-vf support */
+ /* All slaves can perform SET_PORT operations, just need to verify
+ * we keep the mutual resources unchanged */
if (is_eth) {
- if (slave)
- return -EINVAL;
+ switch (in_modifier) {
+ case MLX4_SET_PORT_RQP_CALC:
+ qpn_context = inbox->buf;
+ qpn_context->base_qpn = cpu_to_be32(port_info->base_qpn);
+ qpn_context->n_mac = 0x7;
+ promisc = be32_to_cpu(qpn_context->promisc) >>
+ SET_PORT_PROMISC_SHIFT;
+ qpn_context->promisc = cpu_to_be32(
+ promisc << SET_PORT_PROMISC_SHIFT |
+ port_info->base_qpn);
+ promisc = be32_to_cpu(qpn_context->mcast) >>
+ SET_PORT_PROMISC_SHIFT;
+ qpn_context->mcast = cpu_to_be32(
+ promisc << SET_PORT_PROMISC_SHIFT |
+ port_info->base_qpn);
+ break;
+ case MLX4_SET_PORT_GENERAL:
+ gen_context = inbox->buf;
+ /* Mtu is configured as the max MTU among all the
+ * the functions on the port. */
+ mtu = be16_to_cpu(gen_context->mtu);
+ mtu = max_t(int, mtu, dev->caps.eth_mtu_cap[port]);
+ prev_mtu = slave_st->mtu[port];
+ slave_st->mtu[port] = mtu;
+ if (mtu > master->max_mtu[port])
+ master->max_mtu[port] = mtu;
+ if (mtu < prev_mtu && prev_mtu == master->max_mtu[port]) {
+ slave_st->mtu[port] = mtu;
+ master->max_mtu[port] = mtu;
+ for (i = 0; i < dev->num_slaves; i++) {
+ master->max_mtu[port] =
+ max(master->max_mtu[port],
+ master->slave_state[i].mtu[port]);
+ }
+ }
+
+ gen_context->mtu = cpu_to_be16(master->max_mtu[port]);
+ break;
+ }
return mlx4_cmd(dev, inbox->dma, vhcr->in_modifier,
vhcr->op_modifier,
MLX4_CMD_SET_PORT,
diff --git a/include/linux/mlx4/cmd.h b/include/linux/mlx4/cmd.h
index f729c82..c0f2897 100644
--- a/include/linux/mlx4/cmd.h
+++ b/include/linux/mlx4/cmd.h
@@ -151,6 +151,7 @@ enum {
MLX4_SET_PORT_MAC_TABLE = 0x2,
MLX4_SET_PORT_VLAN_TABLE = 0x3,
MLX4_SET_PORT_PRIO_MAP = 0x4,
+ MLX4_SET_PORT_MODIFIERS
};
struct mlx4_dev;
--
1.6.1.3
^ permalink raw reply related
* [PATCH 22/25] mlx4_en: Attaching Multicast addresses
From: Yevgeny Petrilin @ 2009-11-04 15:32 UTC (permalink / raw)
To: rdreier; +Cc: linux-rdma, netdev, liranl, tziporet, yevgenyp
The device attaches all the multicast addresses to it indirection QP
The multicast steering is now done through the multicast table.
If there is no match, the packet will arrive to the indirection QP
of the first function.
Signed-off-by: Yevgeny Petrilin <yevgenyp@mellanox.co.il>
---
drivers/net/mlx4/en_netdev.c | 33 +++++++++++++++++++++++++++++++--
drivers/net/mlx4/en_port.c | 6 ++++--
drivers/net/mlx4/en_port.h | 11 +++++++++--
drivers/net/mlx4/port.c | 4 ++--
4 files changed, 46 insertions(+), 8 deletions(-)
diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c
index 488f967..8406fbb 100644
--- a/drivers/net/mlx4/en_netdev.c
+++ b/drivers/net/mlx4/en_netdev.c
@@ -177,6 +177,7 @@ static void mlx4_en_cache_mclist(struct net_device *dev)
struct dev_mc_list *tmp;
struct dev_mc_list *plist = NULL;
+ mlx4_en_clear_list(dev);
for (mclist = dev->mc_list; mclist; mclist = mclist->next) {
tmp = kmalloc(sizeof(struct dev_mc_list), GFP_ATOMIC);
if (!tmp) {
@@ -213,6 +214,7 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
struct net_device *dev = priv->dev;
struct dev_mc_list *mclist;
u64 mcast_addr = 0;
+ u8 mc_list[16] = {0};
int err;
mutex_lock(&mdev->state_lock);
@@ -292,6 +294,12 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
if (err)
en_err(priv, "Failed disabling multicast filter\n");
+ /* Detach our qp from all the multicast addresses */
+ for (mclist = priv->mc_list; mclist; mclist = mclist->next) {
+ memcpy(&mc_list[10], mclist->dmi_addr, ETH_ALEN);
+ mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp,
+ mc_list, MLX4_PROT_ETH);
+ }
/* Flush mcast filter and init it with broadcast address */
mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, ETH_BCAST,
1, MLX4_MCAST_CONFIG);
@@ -302,6 +310,9 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
mlx4_en_cache_mclist(dev);
netif_tx_unlock_bh(dev);
for (mclist = priv->mc_list; mclist; mclist = mclist->next) {
+ memcpy(&mc_list[10], mclist->dmi_addr, ETH_ALEN);
+ mlx4_multicast_attach(mdev->dev, &priv->rss_map.indir_qp,
+ mc_list, 0, MLX4_PROT_ETH);
mcast_addr = mlx4_en_mac_to_u64(mclist->dmi_addr);
mlx4_SET_MCAST_FLTR(mdev->dev, priv->port,
mcast_addr, 0, MLX4_MCAST_CONFIG);
@@ -310,8 +321,6 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
0, MLX4_MCAST_ENABLE);
if (err)
en_err(priv, "Failed enabling multicast filter\n");
-
- mlx4_en_clear_list(dev);
}
out:
mutex_unlock(&mdev->state_lock);
@@ -557,6 +566,7 @@ int mlx4_en_start_port(struct net_device *dev)
int err = 0;
int i;
int j;
+ u8 mc_list[16] = {0};
if (priv->port_up) {
en_dbg(DRV, priv, "start port called while port already up\n");
@@ -669,6 +679,12 @@ int mlx4_en_start_port(struct net_device *dev)
goto tx_err;
}
+ /* Attach rx QP to bradcast address */
+ memset(&mc_list[10], 0xff, ETH_ALEN);
+ if (mlx4_multicast_attach(mdev->dev, &priv->rss_map.indir_qp, mc_list,
+ 0, MLX4_PROT_ETH))
+ mlx4_warn(mdev, "Failed Attaching Broadcast\n");
+
/* Schedule multicast task to populate multicast list */
queue_work(mdev->workqueue, &priv->mcast_task);
@@ -699,7 +715,9 @@ void mlx4_en_stop_port(struct net_device *dev)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
struct mlx4_en_dev *mdev = priv->mdev;
+ struct dev_mc_list *mclist;
int i;
+ u8 mc_list[16] = {0};
if (!priv->port_up) {
en_dbg(DRV, priv, "stop port called while port already down\n");
@@ -715,6 +733,17 @@ void mlx4_en_stop_port(struct net_device *dev)
priv->port_up = false;
mlx4_CLOSE_PORT(mdev->dev, priv->port);
+ /* Detach All multicasts */
+ memset(&mc_list[10], 0xff, ETH_ALEN);
+ mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp, mc_list,
+ MLX4_PROT_ETH);
+ for (mclist = priv->mc_list; mclist; mclist = mclist->next) {
+ memcpy(&mc_list[10], mclist->dmi_addr, ETH_ALEN);
+ mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp,
+ mc_list, MLX4_PROT_ETH);
+ }
+ mlx4_en_clear_list(dev);
+
/* Unregister Mac address for the port */
mlx4_unregister_mac(mdev->dev, priv->port, priv->base_qpn);
diff --git a/drivers/net/mlx4/en_port.c b/drivers/net/mlx4/en_port.c
index c099cb4..c7aa86e 100644
--- a/drivers/net/mlx4/en_port.c
+++ b/drivers/net/mlx4/en_port.c
@@ -128,8 +128,10 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
context->base_qpn = cpu_to_be32(base_qpn);
context->n_mac = 0x7;
- context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT | base_qpn);
- context->mcast = cpu_to_be32(1 << SET_PORT_PROMISC_SHIFT | base_qpn);
+ context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT |
+ base_qpn);
+ context->mcast = cpu_to_be32(MCAST_DIRECT << SET_PORT_MC_PROMISC_SHIFT |
+ base_qpn);
context->intra_no_vlan = 0;
context->no_vlan = MLX4_NO_VLAN_IDX;
context->intra_vlan_miss = 0;
diff --git a/drivers/net/mlx4/en_port.h b/drivers/net/mlx4/en_port.h
index 674a804..c62abd7 100644
--- a/drivers/net/mlx4/en_port.h
+++ b/drivers/net/mlx4/en_port.h
@@ -35,8 +35,15 @@
#define _MLX4_EN_PORT_H_
-#define SET_PORT_GEN_ALL_VALID 0x7
-#define SET_PORT_PROMISC_SHIFT 31
+#define SET_PORT_GEN_ALL_VALID 0x7
+#define SET_PORT_PROMISC_SHIFT 31
+#define SET_PORT_MC_PROMISC_SHIFT 30
+
+enum {
+ MCAST_DIRECT_ONLY = 0,
+ MCAST_DIRECT = 1,
+ MCAST_DEFAULT = 2
+};
enum {
MLX4_CMD_SET_VLAN_FLTR = 0x47,
diff --git a/drivers/net/mlx4/port.c b/drivers/net/mlx4/port.c
index 02b56ba..7317d0f 100644
--- a/drivers/net/mlx4/port.c
+++ b/drivers/net/mlx4/port.c
@@ -388,9 +388,9 @@ int mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vhc
promisc << SET_PORT_PROMISC_SHIFT |
port_info->base_qpn);
promisc = be32_to_cpu(qpn_context->mcast) >>
- SET_PORT_PROMISC_SHIFT;
+ SET_PORT_MC_PROMISC_SHIFT;
qpn_context->mcast = cpu_to_be32(
- promisc << SET_PORT_PROMISC_SHIFT |
+ promisc << SET_PORT_MC_PROMISC_SHIFT |
port_info->base_qpn);
break;
case MLX4_SET_PORT_GENERAL:
--
1.6.1.3
^ 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