2010-04-21 15:30:06 -07:00
/*
* Copyright ( c ) 2009 - 2010 Chelsio , Inc . All rights reserved .
*
* This software is available to you under a choice of one of two
* licenses . You may choose to be licensed under the terms of the GNU
* General Public License ( GPL ) Version 2 , available from the file
* COPYING in the main directory of this source tree , or the
* OpenIB . org BSD license below :
*
* Redistribution and use in source and binary forms , with or
* without modification , are permitted provided that the following
* conditions are met :
*
* - Redistributions of source code must retain the above
* copyright notice , this list of conditions and the following
* disclaimer .
*
* - Redistributions in binary form must reproduce the above
* copyright notice , this list of conditions and the following
* disclaimer in the documentation and / or other materials
* provided with the distribution .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND ,
* EXPRESS OR IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY , FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER IN AN
* ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE .
*/
2013-03-14 05:09:01 +00:00
# include <linux/module.h>
# include <linux/moduleparam.h>
2010-04-21 15:30:06 -07:00
# include <rdma/ib_umem.h>
2011-07-26 16:09:06 -07:00
# include <linux/atomic.h>
2016-02-29 18:05:29 +02:00
# include <rdma/ib_user_verbs.h>
2010-04-21 15:30:06 -07:00
# include "iw_cxgb4.h"
2017-02-23 12:31:43 +05:30
int use_dsgl = 1 ;
2013-03-14 05:09:01 +00:00
module_param ( use_dsgl , int , 0644 ) ;
2017-02-23 12:31:43 +05:30
MODULE_PARM_DESC ( use_dsgl , " Use DSGL for PBL/FastReg (default=1) (DEPRECATED) " ) ;
2013-03-14 05:09:01 +00:00
2010-04-21 15:30:06 -07:00
# define T4_ULPTX_MIN_IO 32
# define C4IW_MAX_INLINE_SIZE 96
2013-03-14 05:09:01 +00:00
# define T4_ULPTX_MAX_DMA 1024
# define C4IW_INLINE_THRESHOLD 128
2010-04-21 15:30:06 -07:00
2013-03-14 05:09:01 +00:00
static int inline_threshold = C4IW_INLINE_THRESHOLD ;
module_param ( inline_threshold , int , 0644 ) ;
MODULE_PARM_DESC ( inline_threshold , " inline vs dsgl threshold (default=128) " ) ;
2014-11-21 09:36:36 -06:00
static int mr_exceeds_hw_limits ( struct c4iw_dev * dev , u64 length )
{
return ( is_t4 ( dev - > rdev . lldi . adapter_type ) | |
is_t5 ( dev - > rdev . lldi . adapter_type ) ) & &
length > = 8 * 1024 * 1024 * 1024ULL ;
}
2013-03-14 05:09:01 +00:00
static int _c4iw_write_mem_dma_aligned ( struct c4iw_rdev * rdev , u32 addr ,
2016-06-10 01:05:16 +05:30
u32 len , dma_addr_t data ,
2017-09-26 13:07:26 -07:00
struct sk_buff * skb ,
struct c4iw_wr_wait * wr_waitp )
2013-03-14 05:09:01 +00:00
{
struct ulp_mem_io * req ;
struct ulptx_sgl * sgl ;
u8 wr_len ;
int ret = 0 ;
addr & = 0x7FFFFFF ;
2017-09-26 13:07:26 -07:00
if ( wr_waitp )
c4iw_init_wr_wait ( wr_waitp ) ;
2013-03-14 05:09:01 +00:00
wr_len = roundup ( sizeof ( * req ) + sizeof ( * sgl ) , 16 ) ;
2016-06-10 01:05:16 +05:30
if ( ! skb ) {
skb = alloc_skb ( wr_len , GFP_KERNEL | __GFP_NOFAIL ) ;
if ( ! skb )
return - ENOMEM ;
}
2013-03-14 05:09:01 +00:00
set_wr_txq ( skb , CPL_PRIORITY_CONTROL , 0 ) ;
net: introduce __skb_put_[zero, data, u8]
follow Johannes Berg, semantic patch file as below,
@@
identifier p, p2;
expression len;
expression skb;
type t, t2;
@@
(
-p = __skb_put(skb, len);
+p = __skb_put_zero(skb, len);
|
-p = (t)__skb_put(skb, len);
+p = __skb_put_zero(skb, len);
)
... when != p
(
p2 = (t2)p;
-memset(p2, 0, len);
|
-memset(p, 0, len);
)
@@
identifier p;
expression len;
expression skb;
type t;
@@
(
-t p = __skb_put(skb, len);
+t p = __skb_put_zero(skb, len);
)
... when != p
(
-memset(p, 0, len);
)
@@
type t, t2;
identifier p, p2;
expression skb;
@@
t *p;
...
(
-p = __skb_put(skb, sizeof(t));
+p = __skb_put_zero(skb, sizeof(t));
|
-p = (t *)__skb_put(skb, sizeof(t));
+p = __skb_put_zero(skb, sizeof(t));
)
... when != p
(
p2 = (t2)p;
-memset(p2, 0, sizeof(*p));
|
-memset(p, 0, sizeof(*p));
)
@@
expression skb, len;
@@
-memset(__skb_put(skb, len), 0, len);
+__skb_put_zero(skb, len);
@@
expression skb, len, data;
@@
-memcpy(__skb_put(skb, len), data, len);
+__skb_put_data(skb, data, len);
@@
expression SKB, C, S;
typedef u8;
identifier fn = {__skb_put};
fresh identifier fn2 = fn ## "_u8";
@@
- *(u8 *)fn(SKB, S) = C;
+ fn2(SKB, C);
Signed-off-by: yuan linyu <Linyu.Yuan@alcatel-sbell.com.cn>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-18 22:48:17 +08:00
req = __skb_put_zero ( skb , wr_len ) ;
2013-03-14 05:09:01 +00:00
INIT_ULPTX_WR ( req , wr_len , 0 , 0 ) ;
2014-11-07 09:35:25 +05:30
req - > wr . wr_hi = cpu_to_be32 ( FW_WR_OP_V ( FW_ULPTX_WR ) |
2017-09-26 13:07:26 -07:00
( wr_waitp ? FW_WR_COMPL_F : 0 ) ) ;
req - > wr . wr_lo = wr_waitp ? ( __force __be64 ) ( unsigned long ) wr_waitp : 0L ;
2014-11-07 09:35:25 +05:30
req - > wr . wr_mid = cpu_to_be32 ( FW_WR_LEN16_V ( DIV_ROUND_UP ( wr_len , 16 ) ) ) ;
2016-05-06 22:17:56 +05:30
req - > cmd = cpu_to_be32 ( ULPTX_CMD_V ( ULP_TX_MEM_WRITE ) |
T5_ULP_MEMIO_ORDER_V ( 1 ) |
T5_ULP_MEMIO_FID_V ( rdev - > lldi . rxq_ids [ 0 ] ) ) ;
2014-11-12 17:15:57 -08:00
req - > dlen = cpu_to_be32 ( ULP_MEMIO_DATA_LEN_V ( len > > 5 ) ) ;
2013-03-14 05:09:01 +00:00
req - > len16 = cpu_to_be32 ( DIV_ROUND_UP ( wr_len - sizeof ( req - > wr ) , 16 ) ) ;
2014-11-12 17:15:57 -08:00
req - > lock_addr = cpu_to_be32 ( ULP_MEMIO_ADDR_V ( addr ) ) ;
2013-03-14 05:09:01 +00:00
sgl = ( struct ulptx_sgl * ) ( req + 1 ) ;
2014-11-12 17:15:57 -08:00
sgl - > cmd_nsge = cpu_to_be32 ( ULPTX_CMD_V ( ULP_TX_SC_DSGL ) |
2015-01-08 21:38:16 -08:00
ULPTX_NSGE_V ( 1 ) ) ;
2013-03-14 05:09:01 +00:00
sgl - > len0 = cpu_to_be32 ( len ) ;
2013-03-14 05:09:02 +00:00
sgl - > addr0 = cpu_to_be64 ( data ) ;
2013-03-14 05:09:01 +00:00
2017-09-26 13:07:26 -07:00
if ( wr_waitp )
iw_cxgb4: add referencing to wait objects
For messages sent from the host to fw that solicit a reply from fw,
the c4iw_wr_wait struct pointer is passed in the host->fw message, and
included in the fw->host fw6_msg reply. This allows the sender to wait
until the reply is received, and the code processing the ingress reply
to wake up the sender.
If c4iw_wait_for_reply() times out, however, we need to keep the
c4iw_wr_wait object around in case the reply eventually does arrive.
Otherwise we have touch-after-free bugs in the wake_up paths.
This was hit due to a bad kernel driver that blocked ingress processing
of cxgb4 for a long time, causing iw_cxgb4 timeouts, but eventually
resuming ingress processing and thus hitting the touch-after-free bug.
So I want to fix iw_cxgb4 such that we'll at least keep the wait object
around until the reply comes. If it never comes we leak a small amount of
memory, but if it does come late, we won't potentially crash the system.
So add a kref struct in the c4iw_wr_wait struct, and take a reference
before sending a message to FW that will generate a FW6 reply. And remove
the reference (and potentially free the wait object) when the reply
is processed.
The ep code also uses the wr_wait for non FW6 CPL messages and doesn't
embed the c4iw_wr_wait object in the message sent to firmware. So for
those cases we add c4iw_wake_up_noref().
The mr/mw, cq, and qp object create/destroy paths do need this reference
logic. For these paths, c4iw_ref_send_wait() is introduced to take the
wr_wait reference, send the msg to fw, and then wait for the reply.
So going forward, iw_cxgb4 either uses c4iw_ofld_send(),
c4iw_wait_for_reply() and c4iw_wake_up_noref() like is done in the some
of the endpoint logic, or c4iw_ref_send_wait() and c4iw_wake_up_deref()
(formerly c4iw_wake_up()) when sending messages with the c4iw_wr_wait
object pointer embedded in the message and resulting FW6 reply.
Signed-off-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
2017-09-26 13:13:17 -07:00
ret = c4iw_ref_send_wait ( rdev , skb , wr_waitp , 0 , 0 , __func__ ) ;
else
ret = c4iw_ofld_send ( rdev , skb ) ;
2013-03-14 05:09:01 +00:00
return ret ;
}
static int _c4iw_write_mem_inline ( struct c4iw_rdev * rdev , u32 addr , u32 len ,
2017-09-26 13:07:26 -07:00
void * data , struct sk_buff * skb ,
struct c4iw_wr_wait * wr_waitp )
2010-04-21 15:30:06 -07:00
{
struct ulp_mem_io * req ;
struct ulptx_idata * sc ;
u8 wr_len , * to_dp , * from_dp ;
int copy_len , num_wqe , i , ret = 0 ;
2014-11-12 17:15:57 -08:00
__be32 cmd = cpu_to_be32 ( ULPTX_CMD_V ( ULP_TX_MEM_WRITE ) ) ;
2013-03-14 05:09:01 +00:00
if ( is_t4 ( rdev - > lldi . adapter_type ) )
2014-11-12 17:15:57 -08:00
cmd | = cpu_to_be32 ( ULP_MEMIO_ORDER_F ) ;
2013-03-14 05:09:01 +00:00
else
2014-11-12 17:15:57 -08:00
cmd | = cpu_to_be32 ( T5_ULP_MEMIO_IMM_F ) ;
2010-04-21 15:30:06 -07:00
addr & = 0x7FFFFFF ;
2017-09-27 13:05:49 +05:30
pr_debug ( " addr 0x%x len %u \n " , addr , len ) ;
2010-04-21 15:30:06 -07:00
num_wqe = DIV_ROUND_UP ( len , C4IW_MAX_INLINE_SIZE ) ;
2017-09-26 13:07:26 -07:00
c4iw_init_wr_wait ( wr_waitp ) ;
2010-04-21 15:30:06 -07:00
for ( i = 0 ; i < num_wqe ; i + + ) {
copy_len = len > C4IW_MAX_INLINE_SIZE ? C4IW_MAX_INLINE_SIZE :
len ;
wr_len = roundup ( sizeof * req + sizeof * sc +
roundup ( copy_len , T4_ULPTX_MIN_IO ) , 16 ) ;
2016-06-10 01:05:16 +05:30
if ( ! skb ) {
skb = alloc_skb ( wr_len , GFP_KERNEL | __GFP_NOFAIL ) ;
if ( ! skb )
return - ENOMEM ;
}
2010-04-21 15:30:06 -07:00
set_wr_txq ( skb , CPL_PRIORITY_CONTROL , 0 ) ;
net: introduce __skb_put_[zero, data, u8]
follow Johannes Berg, semantic patch file as below,
@@
identifier p, p2;
expression len;
expression skb;
type t, t2;
@@
(
-p = __skb_put(skb, len);
+p = __skb_put_zero(skb, len);
|
-p = (t)__skb_put(skb, len);
+p = __skb_put_zero(skb, len);
)
... when != p
(
p2 = (t2)p;
-memset(p2, 0, len);
|
-memset(p, 0, len);
)
@@
identifier p;
expression len;
expression skb;
type t;
@@
(
-t p = __skb_put(skb, len);
+t p = __skb_put_zero(skb, len);
)
... when != p
(
-memset(p, 0, len);
)
@@
type t, t2;
identifier p, p2;
expression skb;
@@
t *p;
...
(
-p = __skb_put(skb, sizeof(t));
+p = __skb_put_zero(skb, sizeof(t));
|
-p = (t *)__skb_put(skb, sizeof(t));
+p = __skb_put_zero(skb, sizeof(t));
)
... when != p
(
p2 = (t2)p;
-memset(p2, 0, sizeof(*p));
|
-memset(p, 0, sizeof(*p));
)
@@
expression skb, len;
@@
-memset(__skb_put(skb, len), 0, len);
+__skb_put_zero(skb, len);
@@
expression skb, len, data;
@@
-memcpy(__skb_put(skb, len), data, len);
+__skb_put_data(skb, data, len);
@@
expression SKB, C, S;
typedef u8;
identifier fn = {__skb_put};
fresh identifier fn2 = fn ## "_u8";
@@
- *(u8 *)fn(SKB, S) = C;
+ fn2(SKB, C);
Signed-off-by: yuan linyu <Linyu.Yuan@alcatel-sbell.com.cn>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-18 22:48:17 +08:00
req = __skb_put_zero ( skb , wr_len ) ;
2010-04-21 15:30:06 -07:00
INIT_ULPTX_WR ( req , wr_len , 0 , 0 ) ;
if ( i = = ( num_wqe - 1 ) ) {
2014-11-07 09:35:25 +05:30
req - > wr . wr_hi = cpu_to_be32 ( FW_WR_OP_V ( FW_ULPTX_WR ) |
FW_WR_COMPL_F ) ;
2017-09-26 13:07:26 -07:00
req - > wr . wr_lo = ( __force __be64 ) ( unsigned long ) wr_waitp ;
2010-04-21 15:30:06 -07:00
} else
2014-11-07 09:35:25 +05:30
req - > wr . wr_hi = cpu_to_be32 ( FW_WR_OP_V ( FW_ULPTX_WR ) ) ;
2010-04-21 15:30:06 -07:00
req - > wr . wr_mid = cpu_to_be32 (
2014-11-07 09:35:25 +05:30
FW_WR_LEN16_V ( DIV_ROUND_UP ( wr_len , 16 ) ) ) ;
2010-04-21 15:30:06 -07:00
2013-03-14 05:09:01 +00:00
req - > cmd = cmd ;
2014-11-12 17:15:57 -08:00
req - > dlen = cpu_to_be32 ( ULP_MEMIO_DATA_LEN_V (
2010-04-21 15:30:06 -07:00
DIV_ROUND_UP ( copy_len , T4_ULPTX_MIN_IO ) ) ) ;
req - > len16 = cpu_to_be32 ( DIV_ROUND_UP ( wr_len - sizeof ( req - > wr ) ,
16 ) ) ;
2014-11-12 17:15:57 -08:00
req - > lock_addr = cpu_to_be32 ( ULP_MEMIO_ADDR_V ( addr + i * 3 ) ) ;
2010-04-21 15:30:06 -07:00
sc = ( struct ulptx_idata * ) ( req + 1 ) ;
2014-11-12 17:15:57 -08:00
sc - > cmd_more = cpu_to_be32 ( ULPTX_CMD_V ( ULP_TX_SC_IMM ) ) ;
2010-04-21 15:30:06 -07:00
sc - > len = cpu_to_be32 ( roundup ( copy_len , T4_ULPTX_MIN_IO ) ) ;
to_dp = ( u8 * ) ( sc + 1 ) ;
from_dp = ( u8 * ) data + i * C4IW_MAX_INLINE_SIZE ;
if ( data )
memcpy ( to_dp , from_dp , copy_len ) ;
else
memset ( to_dp , 0 , copy_len ) ;
if ( copy_len % T4_ULPTX_MIN_IO )
memset ( to_dp + copy_len , 0 , T4_ULPTX_MIN_IO -
( copy_len % T4_ULPTX_MIN_IO ) ) ;
iw_cxgb4: add referencing to wait objects
For messages sent from the host to fw that solicit a reply from fw,
the c4iw_wr_wait struct pointer is passed in the host->fw message, and
included in the fw->host fw6_msg reply. This allows the sender to wait
until the reply is received, and the code processing the ingress reply
to wake up the sender.
If c4iw_wait_for_reply() times out, however, we need to keep the
c4iw_wr_wait object around in case the reply eventually does arrive.
Otherwise we have touch-after-free bugs in the wake_up paths.
This was hit due to a bad kernel driver that blocked ingress processing
of cxgb4 for a long time, causing iw_cxgb4 timeouts, but eventually
resuming ingress processing and thus hitting the touch-after-free bug.
So I want to fix iw_cxgb4 such that we'll at least keep the wait object
around until the reply comes. If it never comes we leak a small amount of
memory, but if it does come late, we won't potentially crash the system.
So add a kref struct in the c4iw_wr_wait struct, and take a reference
before sending a message to FW that will generate a FW6 reply. And remove
the reference (and potentially free the wait object) when the reply
is processed.
The ep code also uses the wr_wait for non FW6 CPL messages and doesn't
embed the c4iw_wr_wait object in the message sent to firmware. So for
those cases we add c4iw_wake_up_noref().
The mr/mw, cq, and qp object create/destroy paths do need this reference
logic. For these paths, c4iw_ref_send_wait() is introduced to take the
wr_wait reference, send the msg to fw, and then wait for the reply.
So going forward, iw_cxgb4 either uses c4iw_ofld_send(),
c4iw_wait_for_reply() and c4iw_wake_up_noref() like is done in the some
of the endpoint logic, or c4iw_ref_send_wait() and c4iw_wake_up_deref()
(formerly c4iw_wake_up()) when sending messages with the c4iw_wr_wait
object pointer embedded in the message and resulting FW6 reply.
Signed-off-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
2017-09-26 13:13:17 -07:00
if ( i = = ( num_wqe - 1 ) )
ret = c4iw_ref_send_wait ( rdev , skb , wr_waitp , 0 , 0 ,
__func__ ) ;
else
ret = c4iw_ofld_send ( rdev , skb ) ;
2010-04-21 15:30:06 -07:00
if ( ret )
iw_cxgb4: add referencing to wait objects
For messages sent from the host to fw that solicit a reply from fw,
the c4iw_wr_wait struct pointer is passed in the host->fw message, and
included in the fw->host fw6_msg reply. This allows the sender to wait
until the reply is received, and the code processing the ingress reply
to wake up the sender.
If c4iw_wait_for_reply() times out, however, we need to keep the
c4iw_wr_wait object around in case the reply eventually does arrive.
Otherwise we have touch-after-free bugs in the wake_up paths.
This was hit due to a bad kernel driver that blocked ingress processing
of cxgb4 for a long time, causing iw_cxgb4 timeouts, but eventually
resuming ingress processing and thus hitting the touch-after-free bug.
So I want to fix iw_cxgb4 such that we'll at least keep the wait object
around until the reply comes. If it never comes we leak a small amount of
memory, but if it does come late, we won't potentially crash the system.
So add a kref struct in the c4iw_wr_wait struct, and take a reference
before sending a message to FW that will generate a FW6 reply. And remove
the reference (and potentially free the wait object) when the reply
is processed.
The ep code also uses the wr_wait for non FW6 CPL messages and doesn't
embed the c4iw_wr_wait object in the message sent to firmware. So for
those cases we add c4iw_wake_up_noref().
The mr/mw, cq, and qp object create/destroy paths do need this reference
logic. For these paths, c4iw_ref_send_wait() is introduced to take the
wr_wait reference, send the msg to fw, and then wait for the reply.
So going forward, iw_cxgb4 either uses c4iw_ofld_send(),
c4iw_wait_for_reply() and c4iw_wake_up_noref() like is done in the some
of the endpoint logic, or c4iw_ref_send_wait() and c4iw_wake_up_deref()
(formerly c4iw_wake_up()) when sending messages with the c4iw_wr_wait
object pointer embedded in the message and resulting FW6 reply.
Signed-off-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
2017-09-26 13:13:17 -07:00
break ;
skb = NULL ;
2010-04-21 15:30:06 -07:00
len - = C4IW_MAX_INLINE_SIZE ;
}
return ret ;
}
2016-06-10 01:05:16 +05:30
static int _c4iw_write_mem_dma ( struct c4iw_rdev * rdev , u32 addr , u32 len ,
2017-09-26 13:07:26 -07:00
void * data , struct sk_buff * skb ,
struct c4iw_wr_wait * wr_waitp )
2013-03-14 05:09:01 +00:00
{
u32 remain = len ;
u32 dmalen ;
int ret = 0 ;
2013-03-14 05:09:02 +00:00
dma_addr_t daddr ;
dma_addr_t save ;
daddr = dma_map_single ( & rdev - > lldi . pdev - > dev , data , len , DMA_TO_DEVICE ) ;
if ( dma_mapping_error ( & rdev - > lldi . pdev - > dev , daddr ) )
return - 1 ;
save = daddr ;
2013-03-14 05:09:01 +00:00
while ( remain > inline_threshold ) {
if ( remain < T4_ULPTX_MAX_DMA ) {
if ( remain & ~ T4_ULPTX_MIN_IO )
dmalen = remain & ~ ( T4_ULPTX_MIN_IO - 1 ) ;
else
dmalen = remain ;
} else
dmalen = T4_ULPTX_MAX_DMA ;
remain - = dmalen ;
2013-03-14 05:09:02 +00:00
ret = _c4iw_write_mem_dma_aligned ( rdev , addr , dmalen , daddr ,
2017-09-26 13:07:26 -07:00
skb , remain ? NULL : wr_waitp ) ;
2013-03-14 05:09:01 +00:00
if ( ret )
goto out ;
addr + = dmalen > > 5 ;
data + = dmalen ;
2013-03-14 05:09:02 +00:00
daddr + = dmalen ;
2013-03-14 05:09:01 +00:00
}
if ( remain )
2017-09-26 13:07:26 -07:00
ret = _c4iw_write_mem_inline ( rdev , addr , remain , data , skb ,
wr_waitp ) ;
2013-03-14 05:09:01 +00:00
out :
2013-03-14 05:09:02 +00:00
dma_unmap_single ( & rdev - > lldi . pdev - > dev , save , len , DMA_TO_DEVICE ) ;
2013-03-14 05:09:01 +00:00
return ret ;
}
/*
* write len bytes of data into addr ( 32 B aligned address )
* If data is NULL , clear len byte of memory to zero .
*/
static int write_adapter_mem ( struct c4iw_rdev * rdev , u32 addr , u32 len ,
2017-09-26 13:07:26 -07:00
void * data , struct sk_buff * skb ,
struct c4iw_wr_wait * wr_waitp )
2013-03-14 05:09:01 +00:00
{
2017-09-26 13:07:26 -07:00
int ret ;
if ( ! rdev - > lldi . ulptx_memwrite_dsgl | | ! use_dsgl ) {
ret = _c4iw_write_mem_inline ( rdev , addr , len , data , skb ,
wr_waitp ) ;
goto out ;
}
if ( len < = inline_threshold ) {
ret = _c4iw_write_mem_inline ( rdev , addr , len , data , skb ,
wr_waitp ) ;
goto out ;
}
ret = _c4iw_write_mem_dma ( rdev , addr , len , data , skb , wr_waitp ) ;
if ( ret ) {
pr_warn_ratelimited ( " %s: dma map failure (non fatal) \n " ,
pci_name ( rdev - > lldi . pdev ) ) ;
ret = _c4iw_write_mem_inline ( rdev , addr , len , data , skb ,
wr_waitp ) ;
}
out :
return ret ;
2013-03-14 05:09:01 +00:00
}
2010-04-21 15:30:06 -07:00
/*
* Build and write a TPT entry .
* IN : stag key , pdid , perm , bind_enabled , zbva , to , len , page_size ,
* pbl_size and pbl_addr
* OUT : stag index
*/
static int write_tpt_entry ( struct c4iw_rdev * rdev , u32 reset_tpt_entry ,
u32 * stag , u8 stag_state , u32 pdid ,
enum fw_ri_stag_type type , enum fw_ri_mem_perms perm ,
int bind_enabled , u32 zbva , u64 to ,
2016-06-10 01:05:16 +05:30
u64 len , u8 page_size , u32 pbl_size , u32 pbl_addr ,
2017-09-26 13:07:26 -07:00
struct sk_buff * skb , struct c4iw_wr_wait * wr_waitp )
2010-04-21 15:30:06 -07:00
{
int err ;
struct fw_ri_tpte tpt ;
u32 stag_idx ;
static atomic_t key ;
if ( c4iw_fatal_error ( rdev ) )
return - EIO ;
stag_state = stag_state > 0 ;
stag_idx = ( * stag ) > > 8 ;
if ( ( ! reset_tpt_entry ) & & ( * stag = = T4_STAG_UNSET ) ) {
2012-05-18 15:29:32 +05:30
stag_idx = c4iw_get_resource ( & rdev - > resource . tpt_table ) ;
2014-04-09 09:38:28 -05:00
if ( ! stag_idx ) {
mutex_lock ( & rdev - > stats . lock ) ;
rdev - > stats . stag . fail + + ;
mutex_unlock ( & rdev - > stats . lock ) ;
2010-04-21 15:30:06 -07:00
return - ENOMEM ;
2014-04-09 09:38:28 -05:00
}
2012-05-18 15:29:27 +05:30
mutex_lock ( & rdev - > stats . lock ) ;
rdev - > stats . stag . cur + = 32 ;
if ( rdev - > stats . stag . cur > rdev - > stats . stag . max )
rdev - > stats . stag . max = rdev - > stats . stag . cur ;
mutex_unlock ( & rdev - > stats . lock ) ;
2010-04-21 15:30:06 -07:00
* stag = ( stag_idx < < 8 ) | ( atomic_inc_return ( & key ) & 0xff ) ;
}
2017-09-27 13:05:49 +05:30
pr_debug ( " stag_state 0x%0x type 0x%0x pdid 0x%0x, stag_idx 0x%x \n " ,
stag_state , type , pdid , stag_idx ) ;
2010-04-21 15:30:06 -07:00
/* write TPT entry */
if ( reset_tpt_entry )
memset ( & tpt , 0 , sizeof ( tpt ) ) ;
else {
2015-01-16 09:24:48 +05:30
tpt . valid_to_pdid = cpu_to_be32 ( FW_RI_TPTE_VALID_F |
FW_RI_TPTE_STAGKEY_V ( ( * stag & FW_RI_TPTE_STAGKEY_M ) ) |
FW_RI_TPTE_STAGSTATE_V ( stag_state ) |
FW_RI_TPTE_STAGTYPE_V ( type ) | FW_RI_TPTE_PDID_V ( pdid ) ) ;
tpt . locread_to_qpid = cpu_to_be32 ( FW_RI_TPTE_PERM_V ( perm ) |
( bind_enabled ? FW_RI_TPTE_MWBINDEN_F : 0 ) |
FW_RI_TPTE_ADDRTYPE_V ( ( zbva ? FW_RI_ZERO_BASED_TO :
2010-04-21 15:30:06 -07:00
FW_RI_VA_BASED_TO ) ) |
2015-01-16 09:24:48 +05:30
FW_RI_TPTE_PS_V ( page_size ) ) ;
2010-04-21 15:30:06 -07:00
tpt . nosnoop_pbladdr = ! pbl_size ? 0 : cpu_to_be32 (
2015-01-16 09:24:48 +05:30
FW_RI_TPTE_PBLADDR_V ( PBL_OFF ( rdev , pbl_addr ) > > 3 ) ) ;
2010-04-21 15:30:06 -07:00
tpt . len_lo = cpu_to_be32 ( ( u32 ) ( len & 0xffffffffUL ) ) ;
tpt . va_hi = cpu_to_be32 ( ( u32 ) ( to > > 32 ) ) ;
tpt . va_lo_fbo = cpu_to_be32 ( ( u32 ) ( to & 0xffffffffUL ) ) ;
tpt . dca_mwbcnt_pstag = cpu_to_be32 ( 0 ) ;
tpt . len_hi = cpu_to_be32 ( ( u32 ) ( len > > 32 ) ) ;
}
err = write_adapter_mem ( rdev , stag_idx +
( rdev - > lldi . vr - > stag . start > > 5 ) ,
2017-09-26 13:07:26 -07:00
sizeof ( tpt ) , & tpt , skb , wr_waitp ) ;
2010-04-21 15:30:06 -07:00
2012-05-18 15:29:27 +05:30
if ( reset_tpt_entry ) {
2012-05-18 15:29:32 +05:30
c4iw_put_resource ( & rdev - > resource . tpt_table , stag_idx ) ;
2012-05-18 15:29:27 +05:30
mutex_lock ( & rdev - > stats . lock ) ;
rdev - > stats . stag . cur - = 32 ;
mutex_unlock ( & rdev - > stats . lock ) ;
}
2010-04-21 15:30:06 -07:00
return err ;
}
static int write_pbl ( struct c4iw_rdev * rdev , __be64 * pbl ,
2017-09-26 13:07:26 -07:00
u32 pbl_addr , u32 pbl_size , struct c4iw_wr_wait * wr_waitp )
2010-04-21 15:30:06 -07:00
{
int err ;
2017-09-27 13:05:49 +05:30
pr_debug ( " *pdb_addr 0x%x, pbl_base 0x%x, pbl_size %d \n " ,
pbl_addr , rdev - > lldi . vr - > pbl . start ,
2017-02-09 14:23:51 -08:00
pbl_size ) ;
2010-04-21 15:30:06 -07:00
2017-09-26 13:07:26 -07:00
err = write_adapter_mem ( rdev , pbl_addr > > 5 , pbl_size < < 3 , pbl , NULL ,
wr_waitp ) ;
2010-04-21 15:30:06 -07:00
return err ;
}
static int dereg_mem ( struct c4iw_rdev * rdev , u32 stag , u32 pbl_size ,
2017-09-26 13:07:26 -07:00
u32 pbl_addr , struct sk_buff * skb ,
struct c4iw_wr_wait * wr_waitp )
2010-04-21 15:30:06 -07:00
{
return write_tpt_entry ( rdev , 1 , & stag , 0 , 0 , 0 , 0 , 0 , 0 , 0UL , 0 , 0 ,
2017-09-26 13:07:26 -07:00
pbl_size , pbl_addr , skb , wr_waitp ) ;
2010-04-21 15:30:06 -07:00
}
2017-09-26 13:07:26 -07:00
static int allocate_window ( struct c4iw_rdev * rdev , u32 * stag , u32 pdid ,
struct c4iw_wr_wait * wr_waitp )
2010-04-21 15:30:06 -07:00
{
* stag = T4_STAG_UNSET ;
return write_tpt_entry ( rdev , 0 , stag , 0 , pdid , FW_RI_STAG_MW , 0 , 0 , 0 ,
2017-09-26 13:07:26 -07:00
0UL , 0 , 0 , 0 , 0 , NULL , wr_waitp ) ;
2010-04-21 15:30:06 -07:00
}
2016-06-10 01:05:16 +05:30
static int deallocate_window ( struct c4iw_rdev * rdev , u32 stag ,
2017-09-26 13:07:26 -07:00
struct sk_buff * skb ,
struct c4iw_wr_wait * wr_waitp )
2010-04-21 15:30:06 -07:00
{
return write_tpt_entry ( rdev , 1 , & stag , 0 , 0 , 0 , 0 , 0 , 0 , 0UL , 0 , 0 , 0 ,
2017-09-26 13:07:26 -07:00
0 , skb , wr_waitp ) ;
2010-04-21 15:30:06 -07:00
}
static int allocate_stag ( struct c4iw_rdev * rdev , u32 * stag , u32 pdid ,
2017-09-26 13:07:26 -07:00
u32 pbl_size , u32 pbl_addr ,
struct c4iw_wr_wait * wr_waitp )
2010-04-21 15:30:06 -07:00
{
* stag = T4_STAG_UNSET ;
return write_tpt_entry ( rdev , 0 , stag , 0 , pdid , FW_RI_STAG_NSMR , 0 , 0 , 0 ,
2017-09-26 13:07:26 -07:00
0UL , 0 , 0 , pbl_size , pbl_addr , NULL , wr_waitp ) ;
2010-04-21 15:30:06 -07:00
}
static int finish_mem_reg ( struct c4iw_mr * mhp , u32 stag )
{
u32 mmid ;
mhp - > attr . state = 1 ;
mhp - > attr . stag = stag ;
mmid = stag > > 8 ;
mhp - > ibmr . rkey = mhp - > ibmr . lkey = stag ;
2018-03-01 13:57:58 -08:00
mhp - > ibmr . length = mhp - > attr . len ;
mhp - > ibmr . iova = mhp - > attr . va_fbo ;
mhp - > ibmr . page_size = 1U < < ( mhp - > attr . page_size + 12 ) ;
2017-09-27 13:05:49 +05:30
pr_debug ( " mmid 0x%x mhp %p \n " , mmid , mhp ) ;
2010-04-21 15:30:06 -07:00
return insert_handle ( mhp - > rhp , & mhp - > rhp - > mmidr , mhp , mmid ) ;
}
static int register_mem ( struct c4iw_dev * rhp , struct c4iw_pd * php ,
struct c4iw_mr * mhp , int shift )
{
u32 stag = T4_STAG_UNSET ;
int ret ;
ret = write_tpt_entry ( & rhp - > rdev , 0 , & stag , 1 , mhp - > attr . pdid ,
2014-11-21 09:36:35 -06:00
FW_RI_STAG_NSMR , mhp - > attr . len ?
mhp - > attr . perms : 0 ,
2010-04-21 15:30:06 -07:00
mhp - > attr . mw_bind_enable , mhp - > attr . zbva ,
2014-11-21 09:36:35 -06:00
mhp - > attr . va_fbo , mhp - > attr . len ?
mhp - > attr . len : - 1 , shift - 12 ,
2017-09-26 13:07:26 -07:00
mhp - > attr . pbl_size , mhp - > attr . pbl_addr , NULL ,
mhp - > wr_waitp ) ;
2010-04-21 15:30:06 -07:00
if ( ret )
return ret ;
ret = finish_mem_reg ( mhp , stag ) ;
2016-06-10 01:05:16 +05:30
if ( ret ) {
2010-04-21 15:30:06 -07:00
dereg_mem ( & rhp - > rdev , mhp - > attr . stag , mhp - > attr . pbl_size ,
2017-09-26 13:07:26 -07:00
mhp - > attr . pbl_addr , mhp - > dereg_skb , mhp - > wr_waitp ) ;
2016-06-10 01:05:16 +05:30
mhp - > dereg_skb = NULL ;
}
2010-04-21 15:30:06 -07:00
return ret ;
}
static int alloc_pbl ( struct c4iw_mr * mhp , int npages )
{
mhp - > attr . pbl_addr = c4iw_pblpool_alloc ( & mhp - > rhp - > rdev ,
npages < < 3 ) ;
if ( ! mhp - > attr . pbl_addr )
return - ENOMEM ;
mhp - > attr . pbl_size = npages ;
return 0 ;
}
struct ib_mr * c4iw_get_dma_mr ( struct ib_pd * pd , int acc )
{
struct c4iw_dev * rhp ;
struct c4iw_pd * php ;
struct c4iw_mr * mhp ;
int ret ;
u32 stag = T4_STAG_UNSET ;
2017-09-27 13:05:49 +05:30
pr_debug ( " ib_pd %p \n " , pd ) ;
2010-04-21 15:30:06 -07:00
php = to_c4iw_pd ( pd ) ;
rhp = php - > rhp ;
mhp = kzalloc ( sizeof ( * mhp ) , GFP_KERNEL ) ;
if ( ! mhp )
return ERR_PTR ( - ENOMEM ) ;
iw_cxgb4: add referencing to wait objects
For messages sent from the host to fw that solicit a reply from fw,
the c4iw_wr_wait struct pointer is passed in the host->fw message, and
included in the fw->host fw6_msg reply. This allows the sender to wait
until the reply is received, and the code processing the ingress reply
to wake up the sender.
If c4iw_wait_for_reply() times out, however, we need to keep the
c4iw_wr_wait object around in case the reply eventually does arrive.
Otherwise we have touch-after-free bugs in the wake_up paths.
This was hit due to a bad kernel driver that blocked ingress processing
of cxgb4 for a long time, causing iw_cxgb4 timeouts, but eventually
resuming ingress processing and thus hitting the touch-after-free bug.
So I want to fix iw_cxgb4 such that we'll at least keep the wait object
around until the reply comes. If it never comes we leak a small amount of
memory, but if it does come late, we won't potentially crash the system.
So add a kref struct in the c4iw_wr_wait struct, and take a reference
before sending a message to FW that will generate a FW6 reply. And remove
the reference (and potentially free the wait object) when the reply
is processed.
The ep code also uses the wr_wait for non FW6 CPL messages and doesn't
embed the c4iw_wr_wait object in the message sent to firmware. So for
those cases we add c4iw_wake_up_noref().
The mr/mw, cq, and qp object create/destroy paths do need this reference
logic. For these paths, c4iw_ref_send_wait() is introduced to take the
wr_wait reference, send the msg to fw, and then wait for the reply.
So going forward, iw_cxgb4 either uses c4iw_ofld_send(),
c4iw_wait_for_reply() and c4iw_wake_up_noref() like is done in the some
of the endpoint logic, or c4iw_ref_send_wait() and c4iw_wake_up_deref()
(formerly c4iw_wake_up()) when sending messages with the c4iw_wr_wait
object pointer embedded in the message and resulting FW6 reply.
Signed-off-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
2017-09-26 13:13:17 -07:00
mhp - > wr_waitp = c4iw_alloc_wr_wait ( GFP_KERNEL ) ;
2017-09-26 13:07:26 -07:00
if ( ! mhp - > wr_waitp ) {
ret = - ENOMEM ;
goto err_free_mhp ;
}
c4iw_init_wr_wait ( mhp - > wr_waitp ) ;
2010-04-21 15:30:06 -07:00
2016-06-10 01:05:16 +05:30
mhp - > dereg_skb = alloc_skb ( SGE_MAX_WR_LEN , GFP_KERNEL ) ;
if ( ! mhp - > dereg_skb ) {
ret = - ENOMEM ;
2017-09-26 13:07:26 -07:00
goto err_free_wr_wait ;
2016-06-10 01:05:16 +05:30
}
2010-04-21 15:30:06 -07:00
mhp - > rhp = rhp ;
mhp - > attr . pdid = php - > pdid ;
mhp - > attr . perms = c4iw_ib_to_tpt_access ( acc ) ;
mhp - > attr . mw_bind_enable = ( acc & IB_ACCESS_MW_BIND ) = = IB_ACCESS_MW_BIND ;
mhp - > attr . zbva = 0 ;
mhp - > attr . va_fbo = 0 ;
mhp - > attr . page_size = 0 ;
2015-04-22 01:44:59 +05:30
mhp - > attr . len = ~ 0ULL ;
2010-04-21 15:30:06 -07:00
mhp - > attr . pbl_size = 0 ;
ret = write_tpt_entry ( & rhp - > rdev , 0 , & stag , 1 , php - > pdid ,
FW_RI_STAG_NSMR , mhp - > attr . perms ,
2016-06-10 01:05:16 +05:30
mhp - > attr . mw_bind_enable , 0 , 0 , ~ 0ULL , 0 , 0 , 0 ,
2017-09-26 13:07:26 -07:00
NULL , mhp - > wr_waitp ) ;
2010-04-21 15:30:06 -07:00
if ( ret )
2017-09-26 13:07:26 -07:00
goto err_free_skb ;
2010-04-21 15:30:06 -07:00
ret = finish_mem_reg ( mhp , stag ) ;
if ( ret )
2017-09-26 13:07:26 -07:00
goto err_dereg_mem ;
2010-04-21 15:30:06 -07:00
return & mhp - > ibmr ;
2017-09-26 13:07:26 -07:00
err_dereg_mem :
2010-04-21 15:30:06 -07:00
dereg_mem ( & rhp - > rdev , mhp - > attr . stag , mhp - > attr . pbl_size ,
2017-09-26 13:07:26 -07:00
mhp - > attr . pbl_addr , mhp - > dereg_skb , mhp - > wr_waitp ) ;
err_free_skb :
2016-06-10 01:05:16 +05:30
kfree_skb ( mhp - > dereg_skb ) ;
2018-05-08 07:44:27 +02:00
err_free_wr_wait :
c4iw_put_wr_wait ( mhp - > wr_waitp ) ;
2017-09-26 13:07:26 -07:00
err_free_mhp :
2010-04-21 15:30:06 -07:00
kfree ( mhp ) ;
return ERR_PTR ( ret ) ;
}
struct ib_mr * c4iw_reg_user_mr ( struct ib_pd * pd , u64 start , u64 length ,
u64 virt , int acc , struct ib_udata * udata )
{
__be64 * pages ;
int shift , n , len ;
2014-01-28 13:40:15 +02:00
int i , k , entry ;
2017-09-26 13:07:26 -07:00
int err = - ENOMEM ;
2014-01-28 13:40:15 +02:00
struct scatterlist * sg ;
2010-04-21 15:30:06 -07:00
struct c4iw_dev * rhp ;
struct c4iw_pd * php ;
struct c4iw_mr * mhp ;
2017-09-27 13:05:49 +05:30
pr_debug ( " ib_pd %p \n " , pd ) ;
2010-04-21 15:30:06 -07:00
if ( length = = ~ 0ULL )
return ERR_PTR ( - EINVAL ) ;
if ( ( length + start ) < start )
return ERR_PTR ( - EINVAL ) ;
php = to_c4iw_pd ( pd ) ;
rhp = php - > rhp ;
2014-11-21 09:36:36 -06:00
if ( mr_exceeds_hw_limits ( rhp , length ) )
return ERR_PTR ( - EINVAL ) ;
2010-04-21 15:30:06 -07:00
mhp = kzalloc ( sizeof ( * mhp ) , GFP_KERNEL ) ;
if ( ! mhp )
return ERR_PTR ( - ENOMEM ) ;
iw_cxgb4: add referencing to wait objects
For messages sent from the host to fw that solicit a reply from fw,
the c4iw_wr_wait struct pointer is passed in the host->fw message, and
included in the fw->host fw6_msg reply. This allows the sender to wait
until the reply is received, and the code processing the ingress reply
to wake up the sender.
If c4iw_wait_for_reply() times out, however, we need to keep the
c4iw_wr_wait object around in case the reply eventually does arrive.
Otherwise we have touch-after-free bugs in the wake_up paths.
This was hit due to a bad kernel driver that blocked ingress processing
of cxgb4 for a long time, causing iw_cxgb4 timeouts, but eventually
resuming ingress processing and thus hitting the touch-after-free bug.
So I want to fix iw_cxgb4 such that we'll at least keep the wait object
around until the reply comes. If it never comes we leak a small amount of
memory, but if it does come late, we won't potentially crash the system.
So add a kref struct in the c4iw_wr_wait struct, and take a reference
before sending a message to FW that will generate a FW6 reply. And remove
the reference (and potentially free the wait object) when the reply
is processed.
The ep code also uses the wr_wait for non FW6 CPL messages and doesn't
embed the c4iw_wr_wait object in the message sent to firmware. So for
those cases we add c4iw_wake_up_noref().
The mr/mw, cq, and qp object create/destroy paths do need this reference
logic. For these paths, c4iw_ref_send_wait() is introduced to take the
wr_wait reference, send the msg to fw, and then wait for the reply.
So going forward, iw_cxgb4 either uses c4iw_ofld_send(),
c4iw_wait_for_reply() and c4iw_wake_up_noref() like is done in the some
of the endpoint logic, or c4iw_ref_send_wait() and c4iw_wake_up_deref()
(formerly c4iw_wake_up()) when sending messages with the c4iw_wr_wait
object pointer embedded in the message and resulting FW6 reply.
Signed-off-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
2017-09-26 13:13:17 -07:00
mhp - > wr_waitp = c4iw_alloc_wr_wait ( GFP_KERNEL ) ;
2017-09-26 13:07:26 -07:00
if ( ! mhp - > wr_waitp )
goto err_free_mhp ;
2010-04-21 15:30:06 -07:00
2016-06-10 01:05:16 +05:30
mhp - > dereg_skb = alloc_skb ( SGE_MAX_WR_LEN , GFP_KERNEL ) ;
2017-09-26 13:07:26 -07:00
if ( ! mhp - > dereg_skb )
goto err_free_wr_wait ;
2016-06-10 01:05:16 +05:30
2010-04-21 15:30:06 -07:00
mhp - > rhp = rhp ;
mhp - > umem = ib_umem_get ( pd - > uobject - > context , start , length , acc , 0 ) ;
2017-09-26 13:07:26 -07:00
if ( IS_ERR ( mhp - > umem ) )
goto err_free_skb ;
2010-04-21 15:30:06 -07:00
2017-04-05 09:23:50 +03:00
shift = mhp - > umem - > page_shift ;
2010-04-21 15:30:06 -07:00
2014-01-28 13:40:15 +02:00
n = mhp - > umem - > nmap ;
2010-04-21 15:30:06 -07:00
err = alloc_pbl ( mhp , n ) ;
if ( err )
2017-09-26 13:07:26 -07:00
goto err_umem_release ;
2010-04-21 15:30:06 -07:00
pages = ( __be64 * ) __get_free_page ( GFP_KERNEL ) ;
if ( ! pages ) {
err = - ENOMEM ;
2017-09-26 13:07:26 -07:00
goto err_pbl_free ;
2010-04-21 15:30:06 -07:00
}
i = n = 0 ;
2014-01-28 13:40:15 +02:00
for_each_sg ( mhp - > umem - > sg_head . sgl , sg , mhp - > umem - > nmap , entry ) {
len = sg_dma_len ( sg ) > > shift ;
for ( k = 0 ; k < len ; + + k ) {
pages [ i + + ] = cpu_to_be64 ( sg_dma_address ( sg ) +
2017-04-05 09:23:50 +03:00
( k < < shift ) ) ;
2014-01-28 13:40:15 +02:00
if ( i = = PAGE_SIZE / sizeof * pages ) {
err = write_pbl ( & mhp - > rhp - > rdev ,
pages ,
2017-09-26 13:07:26 -07:00
mhp - > attr . pbl_addr + ( n < < 3 ) , i ,
mhp - > wr_waitp ) ;
2014-01-28 13:40:15 +02:00
if ( err )
goto pbl_done ;
n + = i ;
i = 0 ;
2010-04-21 15:30:06 -07:00
}
}
2014-01-28 13:40:15 +02:00
}
2010-04-21 15:30:06 -07:00
if ( i )
err = write_pbl ( & mhp - > rhp - > rdev , pages ,
2017-09-26 13:07:26 -07:00
mhp - > attr . pbl_addr + ( n < < 3 ) , i ,
mhp - > wr_waitp ) ;
2010-04-21 15:30:06 -07:00
pbl_done :
free_page ( ( unsigned long ) pages ) ;
if ( err )
2017-09-26 13:07:26 -07:00
goto err_pbl_free ;
2010-04-21 15:30:06 -07:00
mhp - > attr . pdid = php - > pdid ;
mhp - > attr . zbva = 0 ;
mhp - > attr . perms = c4iw_ib_to_tpt_access ( acc ) ;
mhp - > attr . va_fbo = virt ;
mhp - > attr . page_size = shift - 12 ;
2011-06-14 20:59:21 +00:00
mhp - > attr . len = length ;
2010-04-21 15:30:06 -07:00
err = register_mem ( rhp , php , mhp , shift ) ;
if ( err )
2017-09-26 13:07:26 -07:00
goto err_pbl_free ;
2010-04-21 15:30:06 -07:00
return & mhp - > ibmr ;
2017-09-26 13:07:26 -07:00
err_pbl_free :
2010-04-21 15:30:06 -07:00
c4iw_pblpool_free ( & mhp - > rhp - > rdev , mhp - > attr . pbl_addr ,
mhp - > attr . pbl_size < < 3 ) ;
2017-09-26 13:07:26 -07:00
err_umem_release :
2010-04-21 15:30:06 -07:00
ib_umem_release ( mhp - > umem ) ;
2017-09-26 13:07:26 -07:00
err_free_skb :
2016-06-10 01:05:16 +05:30
kfree_skb ( mhp - > dereg_skb ) ;
2017-09-26 13:07:26 -07:00
err_free_wr_wait :
iw_cxgb4: add referencing to wait objects
For messages sent from the host to fw that solicit a reply from fw,
the c4iw_wr_wait struct pointer is passed in the host->fw message, and
included in the fw->host fw6_msg reply. This allows the sender to wait
until the reply is received, and the code processing the ingress reply
to wake up the sender.
If c4iw_wait_for_reply() times out, however, we need to keep the
c4iw_wr_wait object around in case the reply eventually does arrive.
Otherwise we have touch-after-free bugs in the wake_up paths.
This was hit due to a bad kernel driver that blocked ingress processing
of cxgb4 for a long time, causing iw_cxgb4 timeouts, but eventually
resuming ingress processing and thus hitting the touch-after-free bug.
So I want to fix iw_cxgb4 such that we'll at least keep the wait object
around until the reply comes. If it never comes we leak a small amount of
memory, but if it does come late, we won't potentially crash the system.
So add a kref struct in the c4iw_wr_wait struct, and take a reference
before sending a message to FW that will generate a FW6 reply. And remove
the reference (and potentially free the wait object) when the reply
is processed.
The ep code also uses the wr_wait for non FW6 CPL messages and doesn't
embed the c4iw_wr_wait object in the message sent to firmware. So for
those cases we add c4iw_wake_up_noref().
The mr/mw, cq, and qp object create/destroy paths do need this reference
logic. For these paths, c4iw_ref_send_wait() is introduced to take the
wr_wait reference, send the msg to fw, and then wait for the reply.
So going forward, iw_cxgb4 either uses c4iw_ofld_send(),
c4iw_wait_for_reply() and c4iw_wake_up_noref() like is done in the some
of the endpoint logic, or c4iw_ref_send_wait() and c4iw_wake_up_deref()
(formerly c4iw_wake_up()) when sending messages with the c4iw_wr_wait
object pointer embedded in the message and resulting FW6 reply.
Signed-off-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
2017-09-26 13:13:17 -07:00
c4iw_put_wr_wait ( mhp - > wr_waitp ) ;
2017-09-26 13:07:26 -07:00
err_free_mhp :
2010-04-21 15:30:06 -07:00
kfree ( mhp ) ;
return ERR_PTR ( err ) ;
}
2016-02-29 18:05:29 +02:00
struct ib_mw * c4iw_alloc_mw ( struct ib_pd * pd , enum ib_mw_type type ,
struct ib_udata * udata )
2010-04-21 15:30:06 -07:00
{
struct c4iw_dev * rhp ;
struct c4iw_pd * php ;
struct c4iw_mw * mhp ;
u32 mmid ;
u32 stag = 0 ;
int ret ;
2013-02-06 16:19:12 +00:00
if ( type ! = IB_MW_TYPE_1 )
return ERR_PTR ( - EINVAL ) ;
2010-04-21 15:30:06 -07:00
php = to_c4iw_pd ( pd ) ;
rhp = php - > rhp ;
mhp = kzalloc ( sizeof ( * mhp ) , GFP_KERNEL ) ;
if ( ! mhp )
return ERR_PTR ( - ENOMEM ) ;
2016-06-10 01:05:16 +05:30
iw_cxgb4: add referencing to wait objects
For messages sent from the host to fw that solicit a reply from fw,
the c4iw_wr_wait struct pointer is passed in the host->fw message, and
included in the fw->host fw6_msg reply. This allows the sender to wait
until the reply is received, and the code processing the ingress reply
to wake up the sender.
If c4iw_wait_for_reply() times out, however, we need to keep the
c4iw_wr_wait object around in case the reply eventually does arrive.
Otherwise we have touch-after-free bugs in the wake_up paths.
This was hit due to a bad kernel driver that blocked ingress processing
of cxgb4 for a long time, causing iw_cxgb4 timeouts, but eventually
resuming ingress processing and thus hitting the touch-after-free bug.
So I want to fix iw_cxgb4 such that we'll at least keep the wait object
around until the reply comes. If it never comes we leak a small amount of
memory, but if it does come late, we won't potentially crash the system.
So add a kref struct in the c4iw_wr_wait struct, and take a reference
before sending a message to FW that will generate a FW6 reply. And remove
the reference (and potentially free the wait object) when the reply
is processed.
The ep code also uses the wr_wait for non FW6 CPL messages and doesn't
embed the c4iw_wr_wait object in the message sent to firmware. So for
those cases we add c4iw_wake_up_noref().
The mr/mw, cq, and qp object create/destroy paths do need this reference
logic. For these paths, c4iw_ref_send_wait() is introduced to take the
wr_wait reference, send the msg to fw, and then wait for the reply.
So going forward, iw_cxgb4 either uses c4iw_ofld_send(),
c4iw_wait_for_reply() and c4iw_wake_up_noref() like is done in the some
of the endpoint logic, or c4iw_ref_send_wait() and c4iw_wake_up_deref()
(formerly c4iw_wake_up()) when sending messages with the c4iw_wr_wait
object pointer embedded in the message and resulting FW6 reply.
Signed-off-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
2017-09-26 13:13:17 -07:00
mhp - > wr_waitp = c4iw_alloc_wr_wait ( GFP_KERNEL ) ;
2017-09-26 13:07:26 -07:00
if ( ! mhp - > wr_waitp ) {
ret = - ENOMEM ;
goto free_mhp ;
}
2016-06-10 01:05:16 +05:30
mhp - > dereg_skb = alloc_skb ( SGE_MAX_WR_LEN , GFP_KERNEL ) ;
if ( ! mhp - > dereg_skb ) {
2016-06-30 11:44:33 +05:30
ret = - ENOMEM ;
2017-09-26 13:07:26 -07:00
goto free_wr_wait ;
2016-06-10 01:05:16 +05:30
}
2017-09-26 13:07:26 -07:00
ret = allocate_window ( & rhp - > rdev , & stag , php - > pdid , mhp - > wr_waitp ) ;
2016-06-30 11:44:33 +05:30
if ( ret )
goto free_skb ;
2010-04-21 15:30:06 -07:00
mhp - > rhp = rhp ;
mhp - > attr . pdid = php - > pdid ;
mhp - > attr . type = FW_RI_STAG_MW ;
mhp - > attr . stag = stag ;
mmid = ( stag ) > > 8 ;
mhp - > ibmw . rkey = stag ;
if ( insert_handle ( rhp , & rhp - > mmidr , mhp , mmid ) ) {
2016-06-30 11:44:33 +05:30
ret = - ENOMEM ;
goto dealloc_win ;
2010-04-21 15:30:06 -07:00
}
2017-09-27 13:05:49 +05:30
pr_debug ( " mmid 0x%x mhp %p stag 0x%x \n " , mmid , mhp , stag ) ;
2010-04-21 15:30:06 -07:00
return & ( mhp - > ibmw ) ;
2016-06-30 11:44:33 +05:30
dealloc_win :
2017-09-26 13:07:26 -07:00
deallocate_window ( & rhp - > rdev , mhp - > attr . stag , mhp - > dereg_skb ,
mhp - > wr_waitp ) ;
2016-06-30 11:44:33 +05:30
free_skb :
kfree_skb ( mhp - > dereg_skb ) ;
2017-09-26 13:07:26 -07:00
free_wr_wait :
iw_cxgb4: add referencing to wait objects
For messages sent from the host to fw that solicit a reply from fw,
the c4iw_wr_wait struct pointer is passed in the host->fw message, and
included in the fw->host fw6_msg reply. This allows the sender to wait
until the reply is received, and the code processing the ingress reply
to wake up the sender.
If c4iw_wait_for_reply() times out, however, we need to keep the
c4iw_wr_wait object around in case the reply eventually does arrive.
Otherwise we have touch-after-free bugs in the wake_up paths.
This was hit due to a bad kernel driver that blocked ingress processing
of cxgb4 for a long time, causing iw_cxgb4 timeouts, but eventually
resuming ingress processing and thus hitting the touch-after-free bug.
So I want to fix iw_cxgb4 such that we'll at least keep the wait object
around until the reply comes. If it never comes we leak a small amount of
memory, but if it does come late, we won't potentially crash the system.
So add a kref struct in the c4iw_wr_wait struct, and take a reference
before sending a message to FW that will generate a FW6 reply. And remove
the reference (and potentially free the wait object) when the reply
is processed.
The ep code also uses the wr_wait for non FW6 CPL messages and doesn't
embed the c4iw_wr_wait object in the message sent to firmware. So for
those cases we add c4iw_wake_up_noref().
The mr/mw, cq, and qp object create/destroy paths do need this reference
logic. For these paths, c4iw_ref_send_wait() is introduced to take the
wr_wait reference, send the msg to fw, and then wait for the reply.
So going forward, iw_cxgb4 either uses c4iw_ofld_send(),
c4iw_wait_for_reply() and c4iw_wake_up_noref() like is done in the some
of the endpoint logic, or c4iw_ref_send_wait() and c4iw_wake_up_deref()
(formerly c4iw_wake_up()) when sending messages with the c4iw_wr_wait
object pointer embedded in the message and resulting FW6 reply.
Signed-off-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
2017-09-26 13:13:17 -07:00
c4iw_put_wr_wait ( mhp - > wr_waitp ) ;
2016-06-30 11:44:33 +05:30
free_mhp :
kfree ( mhp ) ;
return ERR_PTR ( ret ) ;
2010-04-21 15:30:06 -07:00
}
int c4iw_dealloc_mw ( struct ib_mw * mw )
{
struct c4iw_dev * rhp ;
struct c4iw_mw * mhp ;
u32 mmid ;
mhp = to_c4iw_mw ( mw ) ;
rhp = mhp - > rhp ;
mmid = ( mw - > rkey ) > > 8 ;
remove_handle ( rhp , & rhp - > mmidr , mmid ) ;
2017-09-26 13:07:26 -07:00
deallocate_window ( & rhp - > rdev , mhp - > attr . stag , mhp - > dereg_skb ,
mhp - > wr_waitp ) ;
2016-06-30 11:44:33 +05:30
kfree_skb ( mhp - > dereg_skb ) ;
iw_cxgb4: add referencing to wait objects
For messages sent from the host to fw that solicit a reply from fw,
the c4iw_wr_wait struct pointer is passed in the host->fw message, and
included in the fw->host fw6_msg reply. This allows the sender to wait
until the reply is received, and the code processing the ingress reply
to wake up the sender.
If c4iw_wait_for_reply() times out, however, we need to keep the
c4iw_wr_wait object around in case the reply eventually does arrive.
Otherwise we have touch-after-free bugs in the wake_up paths.
This was hit due to a bad kernel driver that blocked ingress processing
of cxgb4 for a long time, causing iw_cxgb4 timeouts, but eventually
resuming ingress processing and thus hitting the touch-after-free bug.
So I want to fix iw_cxgb4 such that we'll at least keep the wait object
around until the reply comes. If it never comes we leak a small amount of
memory, but if it does come late, we won't potentially crash the system.
So add a kref struct in the c4iw_wr_wait struct, and take a reference
before sending a message to FW that will generate a FW6 reply. And remove
the reference (and potentially free the wait object) when the reply
is processed.
The ep code also uses the wr_wait for non FW6 CPL messages and doesn't
embed the c4iw_wr_wait object in the message sent to firmware. So for
those cases we add c4iw_wake_up_noref().
The mr/mw, cq, and qp object create/destroy paths do need this reference
logic. For these paths, c4iw_ref_send_wait() is introduced to take the
wr_wait reference, send the msg to fw, and then wait for the reply.
So going forward, iw_cxgb4 either uses c4iw_ofld_send(),
c4iw_wait_for_reply() and c4iw_wake_up_noref() like is done in the some
of the endpoint logic, or c4iw_ref_send_wait() and c4iw_wake_up_deref()
(formerly c4iw_wake_up()) when sending messages with the c4iw_wr_wait
object pointer embedded in the message and resulting FW6 reply.
Signed-off-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
2017-09-26 13:13:17 -07:00
c4iw_put_wr_wait ( mhp - > wr_waitp ) ;
2010-04-21 15:30:06 -07:00
kfree ( mhp ) ;
2017-09-27 13:05:49 +05:30
pr_debug ( " ib_mw %p mmid 0x%x ptr %p \n " , mw , mmid , mhp ) ;
2010-04-21 15:30:06 -07:00
return 0 ;
}
2015-07-30 10:32:44 +03:00
struct ib_mr * c4iw_alloc_mr ( struct ib_pd * pd ,
enum ib_mr_type mr_type ,
u32 max_num_sg )
2010-04-21 15:30:06 -07:00
{
struct c4iw_dev * rhp ;
struct c4iw_pd * php ;
struct c4iw_mr * mhp ;
u32 mmid ;
u32 stag = 0 ;
int ret = 0 ;
2015-10-13 19:11:30 +03:00
int length = roundup ( max_num_sg * sizeof ( u64 ) , 32 ) ;
2010-04-21 15:30:06 -07:00
2016-02-12 16:10:35 +05:30
php = to_c4iw_pd ( pd ) ;
rhp = php - > rhp ;
2015-07-30 10:32:44 +03:00
if ( mr_type ! = IB_MR_TYPE_MEM_REG | |
2017-07-25 06:51:15 -07:00
max_num_sg > t4_max_fr_depth ( rhp - > rdev . lldi . ulptx_memwrite_dsgl & &
2016-02-12 16:10:35 +05:30
use_dsgl ) )
2015-07-30 10:32:44 +03:00
return ERR_PTR ( - EINVAL ) ;
2010-04-21 15:30:06 -07:00
mhp = kzalloc ( sizeof ( * mhp ) , GFP_KERNEL ) ;
2010-05-20 16:57:54 -05:00
if ( ! mhp ) {
ret = - ENOMEM ;
2010-04-21 15:30:06 -07:00
goto err ;
2010-05-20 16:57:54 -05:00
}
2010-04-21 15:30:06 -07:00
iw_cxgb4: add referencing to wait objects
For messages sent from the host to fw that solicit a reply from fw,
the c4iw_wr_wait struct pointer is passed in the host->fw message, and
included in the fw->host fw6_msg reply. This allows the sender to wait
until the reply is received, and the code processing the ingress reply
to wake up the sender.
If c4iw_wait_for_reply() times out, however, we need to keep the
c4iw_wr_wait object around in case the reply eventually does arrive.
Otherwise we have touch-after-free bugs in the wake_up paths.
This was hit due to a bad kernel driver that blocked ingress processing
of cxgb4 for a long time, causing iw_cxgb4 timeouts, but eventually
resuming ingress processing and thus hitting the touch-after-free bug.
So I want to fix iw_cxgb4 such that we'll at least keep the wait object
around until the reply comes. If it never comes we leak a small amount of
memory, but if it does come late, we won't potentially crash the system.
So add a kref struct in the c4iw_wr_wait struct, and take a reference
before sending a message to FW that will generate a FW6 reply. And remove
the reference (and potentially free the wait object) when the reply
is processed.
The ep code also uses the wr_wait for non FW6 CPL messages and doesn't
embed the c4iw_wr_wait object in the message sent to firmware. So for
those cases we add c4iw_wake_up_noref().
The mr/mw, cq, and qp object create/destroy paths do need this reference
logic. For these paths, c4iw_ref_send_wait() is introduced to take the
wr_wait reference, send the msg to fw, and then wait for the reply.
So going forward, iw_cxgb4 either uses c4iw_ofld_send(),
c4iw_wait_for_reply() and c4iw_wake_up_noref() like is done in the some
of the endpoint logic, or c4iw_ref_send_wait() and c4iw_wake_up_deref()
(formerly c4iw_wake_up()) when sending messages with the c4iw_wr_wait
object pointer embedded in the message and resulting FW6 reply.
Signed-off-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
2017-09-26 13:13:17 -07:00
mhp - > wr_waitp = c4iw_alloc_wr_wait ( GFP_KERNEL ) ;
2017-09-26 13:07:26 -07:00
if ( ! mhp - > wr_waitp ) {
ret = - ENOMEM ;
goto err_free_mhp ;
}
c4iw_init_wr_wait ( mhp - > wr_waitp ) ;
2015-10-13 19:11:30 +03:00
mhp - > mpl = dma_alloc_coherent ( & rhp - > rdev . lldi . pdev - > dev ,
length , & mhp - > mpl_addr , GFP_KERNEL ) ;
if ( ! mhp - > mpl ) {
ret = - ENOMEM ;
2017-09-26 13:07:26 -07:00
goto err_free_wr_wait ;
2015-10-13 19:11:30 +03:00
}
mhp - > max_mpl_len = length ;
2010-04-21 15:30:06 -07:00
mhp - > rhp = rhp ;
2015-07-30 10:32:44 +03:00
ret = alloc_pbl ( mhp , max_num_sg ) ;
2010-04-21 15:30:06 -07:00
if ( ret )
2017-09-26 13:07:26 -07:00
goto err_free_dma ;
2015-07-30 10:32:44 +03:00
mhp - > attr . pbl_size = max_num_sg ;
2010-04-21 15:30:06 -07:00
ret = allocate_stag ( & rhp - > rdev , & stag , php - > pdid ,
2017-09-26 13:07:26 -07:00
mhp - > attr . pbl_size , mhp - > attr . pbl_addr ,
mhp - > wr_waitp ) ;
2010-04-21 15:30:06 -07:00
if ( ret )
2017-09-26 13:07:26 -07:00
goto err_free_pbl ;
2010-04-21 15:30:06 -07:00
mhp - > attr . pdid = php - > pdid ;
mhp - > attr . type = FW_RI_STAG_NSMR ;
mhp - > attr . stag = stag ;
2016-09-16 07:54:52 -07:00
mhp - > attr . state = 0 ;
2010-04-21 15:30:06 -07:00
mmid = ( stag ) > > 8 ;
mhp - > ibmr . rkey = mhp - > ibmr . lkey = stag ;
2010-05-20 16:57:54 -05:00
if ( insert_handle ( rhp , & rhp - > mmidr , mhp , mmid ) ) {
ret = - ENOMEM ;
2017-09-26 13:07:26 -07:00
goto err_dereg ;
2010-05-20 16:57:54 -05:00
}
2010-04-21 15:30:06 -07:00
2017-09-27 13:05:49 +05:30
pr_debug ( " mmid 0x%x mhp %p stag 0x%x \n " , mmid , mhp , stag ) ;
2010-04-21 15:30:06 -07:00
return & ( mhp - > ibmr ) ;
2017-09-26 13:07:26 -07:00
err_dereg :
2010-04-21 15:30:06 -07:00
dereg_mem ( & rhp - > rdev , stag , mhp - > attr . pbl_size ,
2017-09-26 13:07:26 -07:00
mhp - > attr . pbl_addr , mhp - > dereg_skb , mhp - > wr_waitp ) ;
err_free_pbl :
2010-04-21 15:30:06 -07:00
c4iw_pblpool_free ( & mhp - > rhp - > rdev , mhp - > attr . pbl_addr ,
mhp - > attr . pbl_size < < 3 ) ;
2017-09-26 13:07:26 -07:00
err_free_dma :
2015-10-13 19:11:30 +03:00
dma_free_coherent ( & mhp - > rhp - > rdev . lldi . pdev - > dev ,
mhp - > max_mpl_len , mhp - > mpl , mhp - > mpl_addr ) ;
2017-09-26 13:07:26 -07:00
err_free_wr_wait :
iw_cxgb4: add referencing to wait objects
For messages sent from the host to fw that solicit a reply from fw,
the c4iw_wr_wait struct pointer is passed in the host->fw message, and
included in the fw->host fw6_msg reply. This allows the sender to wait
until the reply is received, and the code processing the ingress reply
to wake up the sender.
If c4iw_wait_for_reply() times out, however, we need to keep the
c4iw_wr_wait object around in case the reply eventually does arrive.
Otherwise we have touch-after-free bugs in the wake_up paths.
This was hit due to a bad kernel driver that blocked ingress processing
of cxgb4 for a long time, causing iw_cxgb4 timeouts, but eventually
resuming ingress processing and thus hitting the touch-after-free bug.
So I want to fix iw_cxgb4 such that we'll at least keep the wait object
around until the reply comes. If it never comes we leak a small amount of
memory, but if it does come late, we won't potentially crash the system.
So add a kref struct in the c4iw_wr_wait struct, and take a reference
before sending a message to FW that will generate a FW6 reply. And remove
the reference (and potentially free the wait object) when the reply
is processed.
The ep code also uses the wr_wait for non FW6 CPL messages and doesn't
embed the c4iw_wr_wait object in the message sent to firmware. So for
those cases we add c4iw_wake_up_noref().
The mr/mw, cq, and qp object create/destroy paths do need this reference
logic. For these paths, c4iw_ref_send_wait() is introduced to take the
wr_wait reference, send the msg to fw, and then wait for the reply.
So going forward, iw_cxgb4 either uses c4iw_ofld_send(),
c4iw_wait_for_reply() and c4iw_wake_up_noref() like is done in the some
of the endpoint logic, or c4iw_ref_send_wait() and c4iw_wake_up_deref()
(formerly c4iw_wake_up()) when sending messages with the c4iw_wr_wait
object pointer embedded in the message and resulting FW6 reply.
Signed-off-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
2017-09-26 13:13:17 -07:00
c4iw_put_wr_wait ( mhp - > wr_waitp ) ;
2017-09-26 13:07:26 -07:00
err_free_mhp :
2010-04-21 15:30:06 -07:00
kfree ( mhp ) ;
err :
return ERR_PTR ( ret ) ;
}
2015-10-13 19:11:30 +03:00
static int c4iw_set_page ( struct ib_mr * ibmr , u64 addr )
{
struct c4iw_mr * mhp = to_c4iw_mr ( ibmr ) ;
2018-06-21 07:43:21 -07:00
if ( unlikely ( mhp - > mpl_len = = mhp - > attr . pbl_size ) )
2015-10-13 19:11:30 +03:00
return - ENOMEM ;
mhp - > mpl [ mhp - > mpl_len + + ] = addr ;
return 0 ;
}
2016-05-03 18:01:04 +02:00
int c4iw_map_mr_sg ( struct ib_mr * ibmr , struct scatterlist * sg , int sg_nents ,
2016-05-12 10:49:15 -07:00
unsigned int * sg_offset )
2015-10-13 19:11:30 +03:00
{
struct c4iw_mr * mhp = to_c4iw_mr ( ibmr ) ;
mhp - > mpl_len = 0 ;
2016-05-03 18:01:04 +02:00
return ib_sg_to_pages ( ibmr , sg , sg_nents , sg_offset , c4iw_set_page ) ;
2015-10-13 19:11:30 +03:00
}
2010-04-21 15:30:06 -07:00
int c4iw_dereg_mr ( struct ib_mr * ib_mr )
{
struct c4iw_dev * rhp ;
struct c4iw_mr * mhp ;
u32 mmid ;
2017-09-27 13:05:49 +05:30
pr_debug ( " ib_mr %p \n " , ib_mr ) ;
2010-04-21 15:30:06 -07:00
mhp = to_c4iw_mr ( ib_mr ) ;
rhp = mhp - > rhp ;
mmid = mhp - > attr . stag > > 8 ;
2012-05-18 15:29:32 +05:30
remove_handle ( rhp , & rhp - > mmidr , mmid ) ;
2015-10-13 19:11:30 +03:00
if ( mhp - > mpl )
dma_free_coherent ( & mhp - > rhp - > rdev . lldi . pdev - > dev ,
mhp - > max_mpl_len , mhp - > mpl , mhp - > mpl_addr ) ;
2010-04-21 15:30:06 -07:00
dereg_mem ( & rhp - > rdev , mhp - > attr . stag , mhp - > attr . pbl_size ,
2017-09-26 13:07:26 -07:00
mhp - > attr . pbl_addr , mhp - > dereg_skb , mhp - > wr_waitp ) ;
2010-04-21 15:30:06 -07:00
if ( mhp - > attr . pbl_size )
c4iw_pblpool_free ( & mhp - > rhp - > rdev , mhp - > attr . pbl_addr ,
mhp - > attr . pbl_size < < 3 ) ;
if ( mhp - > kva )
kfree ( ( void * ) ( unsigned long ) mhp - > kva ) ;
if ( mhp - > umem )
ib_umem_release ( mhp - > umem ) ;
2017-09-27 13:05:49 +05:30
pr_debug ( " mmid 0x%x ptr %p \n " , mmid , mhp ) ;
iw_cxgb4: add referencing to wait objects
For messages sent from the host to fw that solicit a reply from fw,
the c4iw_wr_wait struct pointer is passed in the host->fw message, and
included in the fw->host fw6_msg reply. This allows the sender to wait
until the reply is received, and the code processing the ingress reply
to wake up the sender.
If c4iw_wait_for_reply() times out, however, we need to keep the
c4iw_wr_wait object around in case the reply eventually does arrive.
Otherwise we have touch-after-free bugs in the wake_up paths.
This was hit due to a bad kernel driver that blocked ingress processing
of cxgb4 for a long time, causing iw_cxgb4 timeouts, but eventually
resuming ingress processing and thus hitting the touch-after-free bug.
So I want to fix iw_cxgb4 such that we'll at least keep the wait object
around until the reply comes. If it never comes we leak a small amount of
memory, but if it does come late, we won't potentially crash the system.
So add a kref struct in the c4iw_wr_wait struct, and take a reference
before sending a message to FW that will generate a FW6 reply. And remove
the reference (and potentially free the wait object) when the reply
is processed.
The ep code also uses the wr_wait for non FW6 CPL messages and doesn't
embed the c4iw_wr_wait object in the message sent to firmware. So for
those cases we add c4iw_wake_up_noref().
The mr/mw, cq, and qp object create/destroy paths do need this reference
logic. For these paths, c4iw_ref_send_wait() is introduced to take the
wr_wait reference, send the msg to fw, and then wait for the reply.
So going forward, iw_cxgb4 either uses c4iw_ofld_send(),
c4iw_wait_for_reply() and c4iw_wake_up_noref() like is done in the some
of the endpoint logic, or c4iw_ref_send_wait() and c4iw_wake_up_deref()
(formerly c4iw_wake_up()) when sending messages with the c4iw_wr_wait
object pointer embedded in the message and resulting FW6 reply.
Signed-off-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
2017-09-26 13:13:17 -07:00
c4iw_put_wr_wait ( mhp - > wr_waitp ) ;
2010-04-21 15:30:06 -07:00
kfree ( mhp ) ;
return 0 ;
}
2016-11-03 12:09:38 -07:00
void c4iw_invalidate_mr ( struct c4iw_dev * rhp , u32 rkey )
{
struct c4iw_mr * mhp ;
unsigned long flags ;
spin_lock_irqsave ( & rhp - > lock , flags ) ;
mhp = get_mhp ( rhp , rkey > > 8 ) ;
if ( mhp )
mhp - > attr . state = 0 ;
spin_unlock_irqrestore ( & rhp - > lock , flags ) ;
}