22 Nov, 2017

1 commit

  • This converts all remaining cases of the old setup_timer() API into using
    timer_setup(), where the callback argument is the structure already
    holding the struct timer_list. These should have no behavioral changes,
    since they just change which pointer is passed into the callback with
    the same available pointers after conversion. It handles the following
    examples, in addition to some other variations.

    Casting from unsigned long:

    void my_callback(unsigned long data)
    {
    struct something *ptr = (struct something *)data;
    ...
    }
    ...
    setup_timer(&ptr->my_timer, my_callback, ptr);

    and forced object casts:

    void my_callback(struct something *ptr)
    {
    ...
    }
    ...
    setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr);

    become:

    void my_callback(struct timer_list *t)
    {
    struct something *ptr = from_timer(ptr, t, my_timer);
    ...
    }
    ...
    timer_setup(&ptr->my_timer, my_callback, 0);

    Direct function assignments:

    void my_callback(unsigned long data)
    {
    struct something *ptr = (struct something *)data;
    ...
    }
    ...
    ptr->my_timer.function = my_callback;

    have a temporary cast added, along with converting the args:

    void my_callback(struct timer_list *t)
    {
    struct something *ptr = from_timer(ptr, t, my_timer);
    ...
    }
    ...
    ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback;

    And finally, callbacks without a data assignment:

    void my_callback(unsigned long data)
    {
    ...
    }
    ...
    setup_timer(&ptr->my_timer, my_callback, 0);

    have their argument renamed to verify they're unused during conversion:

    void my_callback(struct timer_list *unused)
    {
    ...
    }
    ...
    timer_setup(&ptr->my_timer, my_callback, 0);

    The conversion is done with the following Coccinelle script:

    spatch --very-quiet --all-includes --include-headers \
    -I ./arch/x86/include -I ./arch/x86/include/generated \
    -I ./include -I ./arch/x86/include/uapi \
    -I ./arch/x86/include/generated/uapi -I ./include/uapi \
    -I ./include/generated/uapi --include ./include/linux/kconfig.h \
    --dir . \
    --cocci-file ~/src/data/timer_setup.cocci

    @fix_address_of@
    expression e;
    @@

    setup_timer(
    -&(e)
    +&e
    , ...)

    // Update any raw setup_timer() usages that have a NULL callback, but
    // would otherwise match change_timer_function_usage, since the latter
    // will update all function assignments done in the face of a NULL
    // function initialization in setup_timer().
    @change_timer_function_usage_NULL@
    expression _E;
    identifier _timer;
    type _cast_data;
    @@

    (
    -setup_timer(&_E->_timer, NULL, _E);
    +timer_setup(&_E->_timer, NULL, 0);
    |
    -setup_timer(&_E->_timer, NULL, (_cast_data)_E);
    +timer_setup(&_E->_timer, NULL, 0);
    |
    -setup_timer(&_E._timer, NULL, &_E);
    +timer_setup(&_E._timer, NULL, 0);
    |
    -setup_timer(&_E._timer, NULL, (_cast_data)&_E);
    +timer_setup(&_E._timer, NULL, 0);
    )

    @change_timer_function_usage@
    expression _E;
    identifier _timer;
    struct timer_list _stl;
    identifier _callback;
    type _cast_func, _cast_data;
    @@

    (
    -setup_timer(&_E->_timer, _callback, _E);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, &_callback, _E);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, _callback, (_cast_data)_E);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, &_callback, (_cast_data)_E);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, (_cast_func)_callback, _E);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, (_cast_func)&_callback, _E);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E._timer, _callback, (_cast_data)_E);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, _callback, (_cast_data)&_E);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, &_callback, (_cast_data)_E);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, &_callback, (_cast_data)&_E);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E);
    +timer_setup(&_E._timer, _callback, 0);
    |
    _E->_timer@_stl.function = _callback;
    |
    _E->_timer@_stl.function = &_callback;
    |
    _E->_timer@_stl.function = (_cast_func)_callback;
    |
    _E->_timer@_stl.function = (_cast_func)&_callback;
    |
    _E._timer@_stl.function = _callback;
    |
    _E._timer@_stl.function = &_callback;
    |
    _E._timer@_stl.function = (_cast_func)_callback;
    |
    _E._timer@_stl.function = (_cast_func)&_callback;
    )

    // callback(unsigned long arg)
    @change_callback_handle_cast
    depends on change_timer_function_usage@
    identifier change_timer_function_usage._callback;
    identifier change_timer_function_usage._timer;
    type _origtype;
    identifier _origarg;
    type _handletype;
    identifier _handle;
    @@

    void _callback(
    -_origtype _origarg
    +struct timer_list *t
    )
    {
    (
    ... when != _origarg
    _handletype *_handle =
    -(_handletype *)_origarg;
    +from_timer(_handle, t, _timer);
    ... when != _origarg
    |
    ... when != _origarg
    _handletype *_handle =
    -(void *)_origarg;
    +from_timer(_handle, t, _timer);
    ... when != _origarg
    |
    ... when != _origarg
    _handletype *_handle;
    ... when != _handle
    _handle =
    -(_handletype *)_origarg;
    +from_timer(_handle, t, _timer);
    ... when != _origarg
    |
    ... when != _origarg
    _handletype *_handle;
    ... when != _handle
    _handle =
    -(void *)_origarg;
    +from_timer(_handle, t, _timer);
    ... when != _origarg
    )
    }

    // callback(unsigned long arg) without existing variable
    @change_callback_handle_cast_no_arg
    depends on change_timer_function_usage &&
    !change_callback_handle_cast@
    identifier change_timer_function_usage._callback;
    identifier change_timer_function_usage._timer;
    type _origtype;
    identifier _origarg;
    type _handletype;
    @@

    void _callback(
    -_origtype _origarg
    +struct timer_list *t
    )
    {
    + _handletype *_origarg = from_timer(_origarg, t, _timer);
    +
    ... when != _origarg
    - (_handletype *)_origarg
    + _origarg
    ... when != _origarg
    }

    // Avoid already converted callbacks.
    @match_callback_converted
    depends on change_timer_function_usage &&
    !change_callback_handle_cast &&
    !change_callback_handle_cast_no_arg@
    identifier change_timer_function_usage._callback;
    identifier t;
    @@

    void _callback(struct timer_list *t)
    { ... }

    // callback(struct something *handle)
    @change_callback_handle_arg
    depends on change_timer_function_usage &&
    !match_callback_converted &&
    !change_callback_handle_cast &&
    !change_callback_handle_cast_no_arg@
    identifier change_timer_function_usage._callback;
    identifier change_timer_function_usage._timer;
    type _handletype;
    identifier _handle;
    @@

    void _callback(
    -_handletype *_handle
    +struct timer_list *t
    )
    {
    + _handletype *_handle = from_timer(_handle, t, _timer);
    ...
    }

    // If change_callback_handle_arg ran on an empty function, remove
    // the added handler.
    @unchange_callback_handle_arg
    depends on change_timer_function_usage &&
    change_callback_handle_arg@
    identifier change_timer_function_usage._callback;
    identifier change_timer_function_usage._timer;
    type _handletype;
    identifier _handle;
    identifier t;
    @@

    void _callback(struct timer_list *t)
    {
    - _handletype *_handle = from_timer(_handle, t, _timer);
    }

    // We only want to refactor the setup_timer() data argument if we've found
    // the matching callback. This undoes changes in change_timer_function_usage.
    @unchange_timer_function_usage
    depends on change_timer_function_usage &&
    !change_callback_handle_cast &&
    !change_callback_handle_cast_no_arg &&
    !change_callback_handle_arg@
    expression change_timer_function_usage._E;
    identifier change_timer_function_usage._timer;
    identifier change_timer_function_usage._callback;
    type change_timer_function_usage._cast_data;
    @@

    (
    -timer_setup(&_E->_timer, _callback, 0);
    +setup_timer(&_E->_timer, _callback, (_cast_data)_E);
    |
    -timer_setup(&_E._timer, _callback, 0);
    +setup_timer(&_E._timer, _callback, (_cast_data)&_E);
    )

    // If we fixed a callback from a .function assignment, fix the
    // assignment cast now.
    @change_timer_function_assignment
    depends on change_timer_function_usage &&
    (change_callback_handle_cast ||
    change_callback_handle_cast_no_arg ||
    change_callback_handle_arg)@
    expression change_timer_function_usage._E;
    identifier change_timer_function_usage._timer;
    identifier change_timer_function_usage._callback;
    type _cast_func;
    typedef TIMER_FUNC_TYPE;
    @@

    (
    _E->_timer.function =
    -_callback
    +(TIMER_FUNC_TYPE)_callback
    ;
    |
    _E->_timer.function =
    -&_callback
    +(TIMER_FUNC_TYPE)_callback
    ;
    |
    _E->_timer.function =
    -(_cast_func)_callback;
    +(TIMER_FUNC_TYPE)_callback
    ;
    |
    _E->_timer.function =
    -(_cast_func)&_callback
    +(TIMER_FUNC_TYPE)_callback
    ;
    |
    _E._timer.function =
    -_callback
    +(TIMER_FUNC_TYPE)_callback
    ;
    |
    _E._timer.function =
    -&_callback;
    +(TIMER_FUNC_TYPE)_callback
    ;
    |
    _E._timer.function =
    -(_cast_func)_callback
    +(TIMER_FUNC_TYPE)_callback
    ;
    |
    _E._timer.function =
    -(_cast_func)&_callback
    +(TIMER_FUNC_TYPE)_callback
    ;
    )

    // Sometimes timer functions are called directly. Replace matched args.
    @change_timer_function_calls
    depends on change_timer_function_usage &&
    (change_callback_handle_cast ||
    change_callback_handle_cast_no_arg ||
    change_callback_handle_arg)@
    expression _E;
    identifier change_timer_function_usage._timer;
    identifier change_timer_function_usage._callback;
    type _cast_data;
    @@

    _callback(
    (
    -(_cast_data)_E
    +&_E->_timer
    |
    -(_cast_data)&_E
    +&_E._timer
    |
    -_E
    +&_E->_timer
    )
    )

    // If a timer has been configured without a data argument, it can be
    // converted without regard to the callback argument, since it is unused.
    @match_timer_function_unused_data@
    expression _E;
    identifier _timer;
    identifier _callback;
    @@

    (
    -setup_timer(&_E->_timer, _callback, 0);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, _callback, 0L);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, _callback, 0UL);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E._timer, _callback, 0);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, _callback, 0L);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, _callback, 0UL);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_timer, _callback, 0);
    +timer_setup(&_timer, _callback, 0);
    |
    -setup_timer(&_timer, _callback, 0L);
    +timer_setup(&_timer, _callback, 0);
    |
    -setup_timer(&_timer, _callback, 0UL);
    +timer_setup(&_timer, _callback, 0);
    |
    -setup_timer(_timer, _callback, 0);
    +timer_setup(_timer, _callback, 0);
    |
    -setup_timer(_timer, _callback, 0L);
    +timer_setup(_timer, _callback, 0);
    |
    -setup_timer(_timer, _callback, 0UL);
    +timer_setup(_timer, _callback, 0);
    )

    @change_callback_unused_data
    depends on match_timer_function_unused_data@
    identifier match_timer_function_unused_data._callback;
    type _origtype;
    identifier _origarg;
    @@

    void _callback(
    -_origtype _origarg
    +struct timer_list *unused
    )
    {
    ... when != _origarg
    }

    Signed-off-by: Kees Cook

    Kees Cook
     

19 Nov, 2017

11 commits

  • The workaround code is never used because Skylake NTB does not need it.

    Reported-by: Allen Hubbe
    Signed-off-by: Dave Jiang
    Signed-off-by: Jon Mason

    Dave Jiang
     
  • Make these const as they are only used during a copy operation.
    Done using Coccinelle.

    Signed-off-by: Bhumika Goyal
    Signed-off-by: Jon Mason

    Bhumika Goyal
     
  • The Switchtec hardware has two types of memory windows: LUTs and Direct.
    The first area in each BAR is for LUT windows and the remaining area is
    for the direct region. The total number of LUT entries is set by a
    configuration setting in hardware and they all must be the same
    size. (This is fixed by switchtec_ntb to be 64K.)

    switchtec_ntb enables the LUTs only for the first BAR and enables the
    highest power of two possible. Seeing the LUTs are at the beginning of
    the BAR, the direct memory window's alignment is affected. Therefore,
    the maximum direct memory window size can not be greater than the number
    of LUTs times 64K. The direct window in other BARs will not have this
    restriction as the LUTs will not be enabled there. LUTs will only be
    exposed through the NTB API if the use_lut_mw parameter is set.

    Seeing the Switchtec hardware, by default, configures BARs to be 4G a
    module parameter is given to limit the size of the advertised memory
    windows. Higher layers tend to allocate the maximum BAR size and this
    has a tendency to fail when they try to allocate 4GB of contiguous
    memory.

    Signed-off-by: Logan Gunthorpe
    Reviewed-by: Stephen Bates
    Reviewed-by: Kurt Schwemmer
    Acked-by: Allen Hubbe
    Signed-off-by: Jon Mason

    Logan Gunthorpe
     
  • Seeing there is no dedicated hardware for this, we simply add
    these as entries in the shared memory window. Thus, we could support
    any number of them but 128 seems like enough, for now.

    Signed-off-by: Logan Gunthorpe
    Reviewed-by: Stephen Bates
    Reviewed-by: Kurt Schwemmer
    Acked-by: Allen Hubbe
    Signed-off-by: Jon Mason

    Logan Gunthorpe
     
  • Pretty straightforward implementation of doorbell registers.
    The shift and mask were setup in an earlier patch and this just hooks
    up the appropriate portion of the IDB register as the local doorbells
    and the opposite portion of ODB as the peer doorbells. The DB mask is
    protected by a spinlock to avoid concurrent read-modify-write accesses.

    Signed-off-by: Logan Gunthorpe
    Reviewed-by: Stephen Bates
    Reviewed-by: Kurt Schwemmer
    Acked-by: Allen Hubbe
    Signed-off-by: Jon Mason

    Logan Gunthorpe
     
  • switchtec_ntb checks for a link by looking at the shared memory
    window. If the magic number is correct and the other side indicates
    their link is enabled then we take the link to be up.

    Whenever we change our local link status we send a msg to the
    other side to check whether it's up and change their status.

    The current status is maintained in a flag so ntb_is_link_up
    can return quickly.

    We utilize Switchtec's link status notifier to also check link changes
    when the switch notices a port changes state.

    Signed-off-by: Logan Gunthorpe
    Reviewed-by: Stephen Bates
    Reviewed-by: Kurt Schwemmer
    Acked-by: Allen Hubbe
    Signed-off-by: Jon Mason

    Logan Gunthorpe
     
  • Add a skeleton NTB driver which will be filled out in subsequent patches.

    Signed-off-by: Logan Gunthorpe
    Reviewed-by: Stephen Bates
    Reviewed-by: Kurt Schwemmer
    Acked-by: Allen Hubbe
    Signed-off-by: Jon Mason

    Logan Gunthorpe
     
  • Set up some hardware registers and creates interrupt service routines
    for the doorbells and messages.

    There are 64 doorbells in the switch that are shared between all
    partitions. The upper 4 doorbells are also shared with the messages
    and are therefore not used. Thus, this provides 28 doorbells for each
    partition.

    Signed-off-by: Logan Gunthorpe
    Reviewed-by: Stephen Bates
    Reviewed-by: Kurt Schwemmer
    Acked-by: Allen Hubbe
    Signed-off-by: Jon Mason

    Logan Gunthorpe
     
  • Add the code to initialize the memory windows in the hardware.
    This includes setting up the requester ID table, and figuring out
    which BAR corresponds to which memory window. (Seeing the switch
    can be configured with any number of BARs.)

    Also, seeing the device doesn't have hardware for scratchpads or
    determining the link status, we create a shared memory window that has
    these features. A magic number with a version component will be used
    to determine if the other side's driver is actually up.

    The shared memory window also informs the other side of the
    size and count of the local memory windows.

    Signed-off-by: Logan Gunthorpe
    Reviewed-by: Stephen Bates
    Reviewed-by: Kurt Schwemmer
    Acked-by: Allen Hubbe
    Signed-off-by: Jon Mason

    Logan Gunthorpe
     
  • Seeing the Switchtec NTB hardware shares the same endpoint as the
    management endpoint we utilize the class_interface API to register
    an NTB driver for every Switchtec device in the system that has the
    NTB class code.

    Signed-off-by: Logan Gunthorpe
    Reviewed-by: Stephen Bates
    Reviewed-by: Kurt Schwemmer
    Acked-by: Allen Hubbe
    Acked-by: Bjorn Helgaas
    Signed-off-by: Jon Mason

    Logan Gunthorpe
     
  • With Switchtec hardware it's impossible to get the alignment parameters
    for a peer's memory window until the peer's driver has configured its
    windows. Strictly speaking, the link doesn't have to be up for this,
    but the link being up is the only way the client can tell that
    the other side has been configured.

    This patch converts ntb_transport and ntb_perf to use this function after
    the link goes up. This simplifies these clients slightly because they
    no longer have to store the alignment parameters. It also tweaks
    ntb_tool so that peer_mw_trans will print zero if it is run before
    the link goes up.

    Signed-off-by: Logan Gunthorpe
    Acked-by: Allen Hubbe
    Signed-off-by: Jon Mason

    Logan Gunthorpe
     

02 Aug, 2017

1 commit

  • It seems that under certain scenarios the SPAD can have bogus values caused
    by an agent (i.e. BIOS or other software) that is not the kernel driver, and
    that causes memory window setup failure. This should not cause the link to
    be disabled because if we do that, the driver will never recover again. We
    have verified in testing that this issue happens and prevents proper link
    recovery.

    Signed-off-by: Dave Jiang
    Acked-by: Allen Hubbe
    Signed-off-by: Jon Mason
    Fixes: 84f766855f61 ("ntb: stop link work when we do not have memory")

    Dave Jiang
     

18 Jul, 2017

1 commit

  • After converting to the new API, both ntb_tool and ntb_transport are
    using ntb_mw_count to iterate through ntb_peer_get_addr when they
    should be using ntb_peer_mw_count.

    This probably isn't an issue with the Intel and AMD drivers but
    this will matter for any future driver with asymetric memory window
    counts.

    Signed-off-by: Logan Gunthorpe
    Acked-by: Allen Hubbe
    Signed-off-by: Jon Mason
    Fixes: 443b9a14ecbe ("NTB: Alter MW API to support multi-ports devices")

    Logan Gunthorpe
     

06 Jul, 2017

12 commits

  • If a failure occurs when creating Debug FS entries, unroll all of
    the work that's been done.

    Signed-off-by: Gary R Hook
    Acked-by: Dave Jiang
    Signed-off-by: Jon Mason

    Gary R Hook
     
  • The ntb_perf tool uses module parameters to control the
    characteristics of its test. Enable the changing of these
    options through debugfs, and eliminating the need to unload
    and reload the module to make changes and run additional tests.

    Add a new module parameter that forces the DMA channel
    selection onto the same node as the NTB device (default: true).

    - seg_order: Size of the NTB memory window; power of 2.
    - run_order: Size of the data buffer; power of 2.
    - use_dma: Use DMA or memcpy? Default: 0.
    - on_node: Only use DMA channel(s) on the NTB node. Default: true.

    Signed-off-by: Gary R Hook
    Acked-by: Dave Jiang
    Signed-off-by: Jon Mason

    Gary R Hook
     
  • The Debug FS entries manage themselves; we don't need to hang onto
    them in the context structure.

    Signed-off-by: Gary R Hook
    Acked-by: Dave Jiang
    Signed-off-by: Jon Mason

    Gary R Hook
     
  • The DMA channel(s)/memory used to transfer data to an NTB device
    may not be required to be on the same node as the device. Add a
    module parameter that allows any candidate channel (aside from
    node assocation) and allocated memory to be used.

    Signed-off-by: Gary R Hook
    Acked-by: Dave Jiang
    Signed-off-by: Jon Mason

    Gary R Hook
     
  • IDT 89HPESxNTx device series is PCIe-switches, which support
    Non-Transparent bridging between domains connected to the device ports.
    Since new NTB API exposes multi-port interface and messaging API, the
    IDT NT-functions can be now supported in the kernel. This driver adds
    the following functionality:
    1) Multi-port NTB API to have information of possible NT-functions
    activated in compliance with available device ports.
    2) Memory windows of direct and look up table based address translation
    with all possible combinations of BARs setup.
    3) Traditional doorbell NTB API.
    4) One-on-one messaging NTB API.

    There are some IDT PCIe-switch setups, which must be done before any of
    the NTB peers started. It can be performed either by system BIOS via
    IDT SMBus-slave interface or by pre-initialized IDT PCIe-switch EEPROM:
    1) NT-functions of corresponding ports must be activated using
    SWPARTxCTL and SWPORTxCTL registers.
    2) BAR0 must be configured to expose NT-function configuration
    registers map.
    3) The rest of the BARs must have at least one memory window
    configured, otherwise the driver will just return an error.
    Temperature sensor of IDT PCIe-switches can be also optionally
    activated by BIOS or EEPROM.
    (See IDT documentations for details of how the pre-initialization can
    be done)

    Signed-off-by: Serge Semin
    Acked-by: Allen Hubbe
    Signed-off-by: Jon Mason

    Serge Semin
     
  • As per a comments in [1] by Greg Kroah-Hartman, the ndev_* macros should
    be cleaned up. This makes it more clear what's actually going on when
    reading the code.

    [1] http://www.spinics.net/lists/linux-pci/msg56904.html

    Signed-off-by: Logan Gunthorpe
    Signed-off-by: Jon Mason

    Logan Gunthorpe
     
  • As per a comments in [1] by Greg Kroah-Hartman, the ndev_* macros should
    be cleaned up. This makes it more clear what's actually going on when
    reading the code.

    [1] http://www.spinics.net/lists/linux-pci/msg56904.html

    Signed-off-by: Logan Gunthorpe
    Signed-off-by: Jon Mason

    Logan Gunthorpe
     
  • Some IDT NTB-capable PCIe-switches have message registers to communicate with
    peer devices. This patch adds new NTB API callback methods, which can be used
    to utilize these registers functionality:
    ntb_msg_count(); - get number of message registers
    ntb_msg_inbits(); - get bitfield of inbound message registers status
    ntb_msg_outbits(); - get bitfield of outbound message registers status
    ntb_msg_read_sts(); - read the inbound and outbound message registers status
    ntb_msg_clear_sts(); - clear status bits of message registers
    ntb_msg_set_mask(); - mask interrupts raised by status bits of message
    registers.
    ntb_msg_clear_mask(); - clear interrupts mask bits of message registers
    ntb_msg_read(midx, *pidx); - read message register with specified index,
    additionally getting peer port index which data received from
    ntb_msg_write(midx, pidx); - write data to the specified message register
    sending it to the passed peer device connected over a pidx port
    ntb_msg_event(); - notify driver context of a new message event

    Of course there is hardware which doesn't support Message registers, so
    this API is made optional.

    Signed-off-by: Serge Semin
    Acked-by: Allen Hubbe
    Signed-off-by: Jon Mason

    Serge Semin
     
  • Even though there is no any real NTB hardware, which would have both more
    than two ports and Scratchpad registers, it is logically correct to have
    Scratchpad API accepting a peer port index as well. Intel/AMD drivers utilize
    Primary and Secondary topology to split Scratchpad between connected root
    devices. Since port-index API introduced, Intel/AMD NTB hardware drivers can
    use device port to determine which Scratchpad registers actually belong to
    local and peer devices. The same approach can be used if some potential
    hardware in future will be multi-port and have some set of Scratchpads.
    Here are the brief of changes in the API:
    ntb_spad_count() - return number of Scratchpads per each port
    ntb_peer_spad_addr(pidx, sidx) - address of Scratchpad register of the
    peer device with pidx-index
    ntb_peer_spad_read(pidx, sidx) - read specified Scratchpad register of the
    peer with pidx-index
    ntb_peer_spad_write(pidx, sidx) - write data to Scratchpad register of the
    peer with pidx-index

    Since there is hardware which doesn't support Scratchpad registers, the
    corresponding API methods are now made optional.

    Signed-off-by: Serge Semin
    Acked-by: Allen Hubbe
    Signed-off-by: Jon Mason

    Serge Semin
     
  • Multi-port NTB devices permit to share a memory between all accessible peers.
    Memory Windows API is altered to correspondingly initialize and map memory
    windows for such devices:
    ntb_mw_count(pidx); - number of inbound memory windows, which can be allocated
    for shared buffer with specified peer device.
    ntb_mw_get_align(pidx, widx); - get alignment and size restriction parameters
    to properly allocate inbound memory region.
    ntb_peer_mw_count(); - get number of outbound memory windows.
    ntb_peer_mw_get_addr(widx); - get mapping address of an outbound memory window

    If hardware supports inbound translation configured on the local ntb port:
    ntb_mw_set_trans(pidx, widx); - set translation address of allocated inbound
    memory window so a peer device could access it.
    ntb_mw_clear_trans(pidx, widx); - clear the translation address of an inbound
    memory window.

    If hardware supports outbound translation configured on the peer ntb port:
    ntb_peer_mw_set_trans(pidx, widx); - set translation address of a memory
    window retrieved from a peer device
    ntb_peer_mw_clear_trans(pidx, widx); - clear the translation address of an
    outbound memory window

    Signed-off-by: Serge Semin
    Acked-by: Allen Hubbe
    Signed-off-by: Jon Mason

    Serge Semin
     
  • Multi-port devices permit the NTB connections between multiple domains,
    so a local device can have NTB link being up with one peer and being
    down with another. NTB link-state API is appropriately altered to return
    a bitfield of the link-states between the local device and possible peers.

    Signed-off-by: Serge Semin
    Acked-by: Allen Hubbe
    Signed-off-by: Jon Mason

    Serge Semin
     
  • There is some NTB hardware, which can combine more than just two domains
    over NTB. For instance, some IDT PCIe-switches can have NTB-functions
    activated on more than two-ports. The different domains are distinguished
    by ports they are connected to. So the new port-related methods are added to
    the NTB API:
    ntb_port_number() - return local port
    ntb_peer_port_count() - return number of peers local port can connect to
    ntb_peer_port_number(pdix) - return port number by it index
    ntb_peer_port_idx(port) - return port index by it number

    Current test-drivers aren't changed much. They still support two-ports devices
    for the time being while multi-ports hardware drivers aren't added.

    By default port-related API is declared for two-ports hardware.
    So corresponding hardware drivers won't need to implement it.

    Signed-off-by: Serge Semin
    Signed-off-by: Jon Mason

    Serge Semin
     

20 Jun, 2017

5 commits

  • Do not sleep in ntb_async_tx_submit, which could deadlock.
    This reverts commit "8c874cc140d667f84ae4642bb5b5e0d6396d2ca4"

    Fixes: 8c874cc140d6 ("NTB: Address out of DMA descriptor issue with NTB")
    Reported-by: Jia-Ju Bai
    Signed-off-by: Allen Hubbe
    Acked-by: Dave Jiang
    Signed-off-by: Jon Mason

    Allen Hubbe
     
  • Fixing doorbell register length to 32bits per spec. On Skylake NTB, the
    doorbell registers are 32bit write only registers. The source for the
    doorbell is a 64bit register that shows the interrupt bits.

    Signed-off-by: Dave Jiang
    Fixes: 783dfa6cc41b ("ntb: Adding Skylake Xeon NTB support")
    Acked-by: Allen Hubbe
    Signed-off-by: Jon Mason

    Dave Jiang
     
  • A divide by zero error occurs if qp_count is less than mw_count because
    num_qps_mw is calculated to be zero. The calculation appears to be
    incorrect.

    The requirement is for num_qps_mw to be set to qp_count / mw_count
    with any remainder divided among the earlier mws.

    For example, if mw_count is 5 and qp_count is 12 then mws 0 and 1
    will have 3 qps per window and mws 2 through 4 will have 2 qps per window.
    Thus, when mw_num < qp_count % mw_count, num_qps_mw is 1 higher
    than when mw_num >= qp_count.

    Signed-off-by: Logan Gunthorpe
    Fixes: e26a5843f7f5 ("NTB: Split ntb_hw_intel and ntb_transport drivers")
    Acked-by: Allen Hubbe
    Signed-off-by: Jon Mason

    Logan Gunthorpe
     
  • In cases where there are more mw's than spads/2-2, the mw count gets
    reduced to match the limitation. ntb_transport also tries to ensure that
    there are fewer qps than mws but uses the full mw count instead of
    the reduced one. When this happens, the math in
    'ntb_transport_setup_qp_mw' will get confused and result in a kernel
    paging request bug.

    This patch fixes the bug by reducing qp_count to the reduced mw count
    instead of the full mw count.

    Signed-off-by: Logan Gunthorpe
    Fixes: e26a5843f7f5 ("NTB: Split ntb_hw_intel and ntb_transport drivers")
    Acked-by: Allen Hubbe
    Signed-off-by: Jon Mason

    Logan Gunthorpe
     
  • The order parameters are powers of 2; adjust the usage information
    to use correct mathematical representations.

    Signed-off-by: Gary R Hook
    Fixes: 8a7b6a778a85 ("ntb: ntb perf tool")
    Acked-by: Dave Jiang
    Signed-off-by: Jon Mason

    Gary R Hook
     

17 Feb, 2017

4 commits

  • On Skylake hardware, the link_poll isn't clearing the pending interrupt
    bit. Adding a new function for SKX that handles clearing of status bit the
    right way.

    Signed-off-by: Dave Jiang
    Fixes: 783dfa6c ("ntb: Adding Skylake Xeon NTB support")
    Signed-off-by: Jon Mason

    Dave Jiang
     
  • Fix typo causing ntb_transport_create_queue to select the first
    queue every time, instead of using the next free queue.

    Signed-off-by: Thomas VanSelus
    Signed-off-by: Aaron Sierra
    Acked-by: Allen Hubbe
    Fixes: fce8a7bb5 ("PCI-Express Non-Transparent Bridge Support")
    Signed-off-by: Jon Mason

    Thomas VanSelus
     
  • In the normal I/O execution path, ntb_perf is missing a call to
    dmaengine_unmap_put() after submission. That causes us to leak
    unmap objects.

    Signed-off-by: Dave Jiang
    Fixes: 8a7b6a77 ("ntb: ntb perf tool")
    Signed-off-by: Jon Mason

    Dave Jiang
     
  • The call to debugfs_remove_recursive(qp->debugfs_dir) of the sub-level
    directory must not be later than
    debugfs_remove_recursive(nt_debugfs_dir) of the top-level directory.
    Otherwise, the sub-level directory will not exist, and it would be
    invalid (panic) to attempt to remove it. This removes the top-level
    directory last, after sub-level directories have been cleaned up.

    Signed-off-by: Allen Hubbe
    Fixes: e26a5843f ("NTB: Split ntb_hw_intel and ntb_transport drivers")
    Signed-off-by: Jon Mason

    Allen Hubbe
     

24 Dec, 2016

5 commits