| =========== | |
| NTB Drivers | |
| =========== | |
| NTB (Non-Transparent Bridge) is a type of PCI-Express bridge chip that connects | |
| the separate memory systems of two or more computers to the same PCI-Express | |
| fabric. Existing NTB hardware supports a common feature set: doorbell | |
| registers and memory translation windows, as well as non common features like | |
| scratchpad and message registers. Scratchpad registers are read-and-writable | |
| registers that are accessible from either side of the device, so that peers can | |
| exchange a small amount of information at a fixed address. Message registers can | |
| be utilized for the same purpose. Additionally they are provided with with | |
| special status bits to make sure the information isn't rewritten by another | |
| peer. Doorbell registers provide a way for peers to send interrupt events. | |
| Memory windows allow translated read and write access to the peer memory. | |
| NTB Core Driver (ntb) | |
| ===================== | |
| The NTB core driver defines an api wrapping the common feature set, and allows | |
| clients interested in NTB features to discover NTB the devices supported by | |
| hardware drivers. The term "client" is used here to mean an upper layer | |
| component making use of the NTB api. The term "driver," or "hardware driver," | |
| is used here to mean a driver for a specific vendor and model of NTB hardware. | |
| NTB Client Drivers | |
| ================== | |
| NTB client drivers should register with the NTB core driver. After | |
| registering, the client probe and remove functions will be called appropriately | |
| as ntb hardware, or hardware drivers, are inserted and removed. The | |
| registration uses the Linux Device framework, so it should feel familiar to | |
| anyone who has written a pci driver. | |
| NTB Typical client driver implementation | |
| ---------------------------------------- | |
| Primary purpose of NTB is to share some peace of memory between at least two | |
| systems. So the NTB device features like Scratchpad/Message registers are | |
| mainly used to perform the proper memory window initialization. Typically | |
| there are two types of memory window interfaces supported by the NTB API: | |
| inbound translation configured on the local ntb port and outbound translation | |
| configured by the peer, on the peer ntb port. The first type is | |
| depicted on the next figure:: | |
| Inbound translation: | |
| Memory: Local NTB Port: Peer NTB Port: Peer MMIO: | |
| ____________ | |
| | dma-mapped |-ntb_mw_set_trans(addr) | | |
| | memory | _v____________ | ______________ | |
| | (addr) |<======| MW xlat addr |<====| MW base addr |<== memory-mapped IO | |
| |------------| |--------------| | |--------------| | |
| So typical scenario of the first type memory window initialization looks: | |
| 1) allocate a memory region, 2) put translated address to NTB config, | |
| 3) somehow notify a peer device of performed initialization, 4) peer device | |
| maps corresponding outbound memory window so to have access to the shared | |
| memory region. | |
| The second type of interface, that implies the shared windows being | |
| initialized by a peer device, is depicted on the figure:: | |
| Outbound translation: | |
| Memory: Local NTB Port: Peer NTB Port: Peer MMIO: | |
| ____________ ______________ | |
| | dma-mapped | | | MW base addr |<== memory-mapped IO | |
| | memory | | |--------------| | |
| | (addr) |<===================| MW xlat addr |<-ntb_peer_mw_set_trans(addr) | |
| |------------| | |--------------| | |
| Typical scenario of the second type interface initialization would be: | |
| 1) allocate a memory region, 2) somehow deliver a translated address to a peer | |
| device, 3) peer puts the translated address to NTB config, 4) peer device maps | |
| outbound memory window so to have access to the shared memory region. | |
| As one can see the described scenarios can be combined in one portable | |
| algorithm. | |
| Local device: | |
| 1) Allocate memory for a shared window | |
| 2) Initialize memory window by translated address of the allocated region | |
| (it may fail if local memory window initialization is unsupported) | |
| 3) Send the translated address and memory window index to a peer device | |
| Peer device: | |
| 1) Initialize memory window with retrieved address of the allocated | |
| by another device memory region (it may fail if peer memory window | |
| initialization is unsupported) | |
| 2) Map outbound memory window | |
| In accordance with this scenario, the NTB Memory Window API can be used as | |
| follows: | |
| Local device: | |
| 1) ntb_mw_count(pidx) - retrieve number of memory ranges, which can | |
| be allocated for memory windows between local device and peer device | |
| of port with specified index. | |
| 2) ntb_get_align(pidx, midx) - retrieve parameters restricting the | |
| shared memory region alignment and size. Then memory can be properly | |
| allocated. | |
| 3) Allocate physically contiguous memory region in compliance with | |
| restrictions retrieved in 2). | |
| 4) ntb_mw_set_trans(pidx, midx) - try to set translation address of | |
| the memory window with specified index for the defined peer device | |
| (it may fail if local translated address setting is not supported) | |
| 5) Send translated base address (usually together with memory window | |
| number) to the peer device using, for instance, scratchpad or message | |
| registers. | |
| Peer device: | |
| 1) ntb_peer_mw_set_trans(pidx, midx) - try to set received from other | |
| device (related to pidx) translated address for specified memory | |
| window. It may fail if retrieved address, for instance, exceeds | |
| maximum possible address or isn't properly aligned. | |
| 2) ntb_peer_mw_get_addr(widx) - retrieve MMIO address to map the memory | |
| window so to have an access to the shared memory. | |
| Also it is worth to note, that method ntb_mw_count(pidx) should return the | |
| same value as ntb_peer_mw_count() on the peer with port index - pidx. | |
| NTB Transport Client (ntb\_transport) and NTB Netdev (ntb\_netdev) | |
| ------------------------------------------------------------------ | |
| The primary client for NTB is the Transport client, used in tandem with NTB | |
| Netdev. These drivers function together to create a logical link to the peer, | |
| across the ntb, to exchange packets of network data. The Transport client | |
| establishes a logical link to the peer, and creates queue pairs to exchange | |
| messages and data. The NTB Netdev then creates an ethernet device using a | |
| Transport queue pair. Network data is copied between socket buffers and the | |
| Transport queue pair buffer. The Transport client may be used for other things | |
| besides Netdev, however no other applications have yet been written. | |
| NTB Ping Pong Test Client (ntb\_pingpong) | |
| ----------------------------------------- | |
| The Ping Pong test client serves as a demonstration to exercise the doorbell | |
| and scratchpad registers of NTB hardware, and as an example simple NTB client. | |
| Ping Pong enables the link when started, waits for the NTB link to come up, and | |
| then proceeds to read and write the doorbell scratchpad registers of the NTB. | |
| The peers interrupt each other using a bit mask of doorbell bits, which is | |
| shifted by one in each round, to test the behavior of multiple doorbell bits | |
| and interrupt vectors. The Ping Pong driver also reads the first local | |
| scratchpad, and writes the value plus one to the first peer scratchpad, each | |
| round before writing the peer doorbell register. | |
| Module Parameters: | |
| * unsafe - Some hardware has known issues with scratchpad and doorbell | |
| registers. By default, Ping Pong will not attempt to exercise such | |
| hardware. You may override this behavior at your own risk by setting | |
| unsafe=1. | |
| * delay\_ms - Specify the delay between receiving a doorbell | |
| interrupt event and setting the peer doorbell register for the next | |
| round. | |
| * init\_db - Specify the doorbell bits to start new series of rounds. A new | |
| series begins once all the doorbell bits have been shifted out of | |
| range. | |
| * dyndbg - It is suggested to specify dyndbg=+p when loading this module, and | |
| then to observe debugging output on the console. | |
| NTB Tool Test Client (ntb\_tool) | |
| -------------------------------- | |
| The Tool test client serves for debugging, primarily, ntb hardware and drivers. | |
| The Tool provides access through debugfs for reading, setting, and clearing the | |
| NTB doorbell, and reading and writing scratchpads. | |
| The Tool does not currently have any module parameters. | |
| Debugfs Files: | |
| * *debugfs*/ntb\_tool/*hw*/ | |
| A directory in debugfs will be created for each | |
| NTB device probed by the tool. This directory is shortened to *hw* | |
| below. | |
| * *hw*/db | |
| This file is used to read, set, and clear the local doorbell. Not | |
| all operations may be supported by all hardware. To read the doorbell, | |
| read the file. To set the doorbell, write `s` followed by the bits to | |
| set (eg: `echo 's 0x0101' > db`). To clear the doorbell, write `c` | |
| followed by the bits to clear. | |
| * *hw*/mask | |
| This file is used to read, set, and clear the local doorbell mask. | |
| See *db* for details. | |
| * *hw*/peer\_db | |
| This file is used to read, set, and clear the peer doorbell. | |
| See *db* for details. | |
| * *hw*/peer\_mask | |
| This file is used to read, set, and clear the peer doorbell | |
| mask. See *db* for details. | |
| * *hw*/spad | |
| This file is used to read and write local scratchpads. To read | |
| the values of all scratchpads, read the file. To write values, write a | |
| series of pairs of scratchpad number and value | |
| (eg: `echo '4 0x123 7 0xabc' > spad` | |
| # to set scratchpads `4` and `7` to `0x123` and `0xabc`, respectively). | |
| * *hw*/peer\_spad | |
| This file is used to read and write peer scratchpads. See | |
| *spad* for details. | |
| NTB MSI Test Client (ntb\_msi\_test) | |
| ------------------------------------ | |
| The MSI test client serves to test and debug the MSI library which | |
| allows for passing MSI interrupts across NTB memory windows. The | |
| test client is interacted with through the debugfs filesystem: | |
| * *debugfs*/ntb\_tool/*hw*/ | |
| A directory in debugfs will be created for each | |
| NTB device probed by the tool. This directory is shortened to *hw* | |
| below. | |
| * *hw*/port | |
| This file describes the local port number | |
| * *hw*/irq*_occurrences | |
| One occurrences file exists for each interrupt and, when read, | |
| returns the number of times the interrupt has been triggered. | |
| * *hw*/peer*/port | |
| This file describes the port number for each peer | |
| * *hw*/peer*/count | |
| This file describes the number of interrupts that can be | |
| triggered on each peer | |
| * *hw*/peer*/trigger | |
| Writing an interrupt number (any number less than the value | |
| specified in count) will trigger the interrupt on the | |
| specified peer. That peer's interrupt's occurrence file | |
| should be incremented. | |
| NTB Hardware Drivers | |
| ==================== | |
| NTB hardware drivers should register devices with the NTB core driver. After | |
| registering, clients probe and remove functions will be called. | |
| NTB Intel Hardware Driver (ntb\_hw\_intel) | |
| ------------------------------------------ | |
| The Intel hardware driver supports NTB on Xeon and Atom CPUs. | |
| Module Parameters: | |
| * b2b\_mw\_idx | |
| If the peer ntb is to be accessed via a memory window, then use | |
| this memory window to access the peer ntb. A value of zero or positive | |
| starts from the first mw idx, and a negative value starts from the last | |
| mw idx. Both sides MUST set the same value here! The default value is | |
| `-1`. | |
| * b2b\_mw\_share | |
| If the peer ntb is to be accessed via a memory window, and if | |
| the memory window is large enough, still allow the client to use the | |
| second half of the memory window for address translation to the peer. | |
| * xeon\_b2b\_usd\_bar2\_addr64 | |
| If using B2B topology on Xeon hardware, use | |
| this 64 bit address on the bus between the NTB devices for the window | |
| at BAR2, on the upstream side of the link. | |
| * xeon\_b2b\_usd\_bar4\_addr64 - See *xeon\_b2b\_bar2\_addr64*. | |
| * xeon\_b2b\_usd\_bar4\_addr32 - See *xeon\_b2b\_bar2\_addr64*. | |
| * xeon\_b2b\_usd\_bar5\_addr32 - See *xeon\_b2b\_bar2\_addr64*. | |
| * xeon\_b2b\_dsd\_bar2\_addr64 - See *xeon\_b2b\_bar2\_addr64*. | |
| * xeon\_b2b\_dsd\_bar4\_addr64 - See *xeon\_b2b\_bar2\_addr64*. | |
| * xeon\_b2b\_dsd\_bar4\_addr32 - See *xeon\_b2b\_bar2\_addr64*. | |
| * xeon\_b2b\_dsd\_bar5\_addr32 - See *xeon\_b2b\_bar2\_addr64*. |