€•íÎŒsphinx.addnodes”Œdocument”“”)”}”(Œ rawsource”Œ”Œchildren”]”(Œ translations”Œ LanguagesNode”“”)”}”(hhh]”(hŒ pending_xref”“”)”}”(hhh]”Œdocutils.nodes”ŒText”“”ŒChinese (Simplified)”…””}”Œparent”hsbaŒ attributes”}”(Œids”]”Œclasses”]”Œnames”]”Œdupnames”]”Œbackrefs”]”Œ refdomain”Œstd”Œreftype”Œdoc”Œ reftarget”Œ'/translations/zh_CN/driver-api/xillybus”Œmodname”NŒ classname”NŒ refexplicit”ˆuŒtagname”hhh ubh)”}”(hhh]”hŒChinese (Traditional)”…””}”hh2sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ'/translations/zh_TW/driver-api/xillybus”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒItalian”…””}”hhFsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ'/translations/it_IT/driver-api/xillybus”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒJapanese”…””}”hhZsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ'/translations/ja_JP/driver-api/xillybus”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒKorean”…””}”hhnsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ'/translations/ko_KR/driver-api/xillybus”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒSpanish”…””}”hh‚sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ'/translations/sp_SP/driver-api/xillybus”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubeh}”(h]”h ]”h"]”h$]”h&]”Œcurrent_language”ŒEnglish”uh1h hhŒ _document”hŒsource”NŒline”NubhŒsection”“”)”}”(hhh]”(hŒtitle”“”)”}”(hŒ*Xillybus driver for generic FPGA interface”h]”hŒ*Xillybus driver for generic FPGA interface”…””}”(hh¨hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hh£hžhhŸŒA/var/lib/git/docbuild/linux/Documentation/driver-api/xillybus.rst”h KubhŒ field_list”“”)”}”(hhh]”(hŒfield”“”)”}”(hhh]”(hŒ field_name”“”)”}”(hŒAuthor”h]”hŒAuthor”…””}”(hhÃhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÁhh¾hŸh¶h KubhŒ field_body”“”)”}”(hŒ1Eli Billauer, Xillybus Ltd. (http://xillybus.com)”h]”hŒ paragraph”“”)”}”(hhÕh]”(hŒEli Billauer, Xillybus Ltd. (”…””}”(hhÙhžhhŸNh NubhŒ reference”“”)”}”(hŒhttp://xillybus.com”h]”hŒhttp://xillybus.com”…””}”(hhâhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”Œrefuri”häuh1hàhhÙubhŒ)”…””}”(hhÙhžhhŸNh Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KhhÓubah}”(h]”h ]”h"]”h$]”h&]”uh1hÑhh¾ubeh}”(h]”h ]”h"]”h$]”h&]”uh1h¼hŸh¶h Khh¹hžhubh½)”}”(hhh]”(hÂ)”}”(hŒEmail”h]”hŒEmail”…””}”(hj hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÁhjhŸh¶h KubhÒ)”}”(hŒ;eli.billauer@gmail.com or as advertised on Xillybus' site. ”h]”hØ)”}”(hŒ:eli.billauer@gmail.com or as advertised on Xillybus' site.”h]”(há)”}”(hŒeli.billauer@gmail.com”h]”hŒeli.billauer@gmail.com”…””}”(hj hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”Œrefuri”Œmailto:eli.billauer@gmail.com”uh1hàhjubhŒ& or as advertised on Xillybus’ site.”…””}”(hjhžhhŸNh Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h Khjubah}”(h]”h ]”h"]”h$]”h&]”uh1hÑhjubeh}”(h]”h ]”h"]”h$]”h&]”uh1h¼hŸh¶h Khh¹hžhubeh}”(h]”h ]”h"]”h$]”h&]”uh1h·hh£hžhhŸh¶h KubhŒcomment”“”)”}”(hX†Contents: - Introduction -- Background -- Xillybus Overview - Usage -- User interface -- Synchronization -- Seekable pipes - Internals -- Source code organization -- Pipe attributes -- Host never reads from the FPGA -- Channels, pipes, and the message channel -- Data streaming -- Data granularity -- Probing -- Buffer allocation -- The "nonempty" message (supporting poll)”h]”hX†Contents: - Introduction -- Background -- Xillybus Overview - Usage -- User interface -- Synchronization -- Seekable pipes - Internals -- Source code organization -- Pipe attributes -- Host never reads from the FPGA -- Channels, pipes, and the message channel -- Data streaming -- Data granularity -- Probing -- Buffer allocation -- The "nonempty" message (supporting poll)”…””}”hjNsbah}”(h]”h ]”h"]”h$]”h&]”Œ xml:space”Œpreserve”uh1jLhh£hžhhŸh¶h Kubh¢)”}”(hhh]”(h§)”}”(hŒ Introduction”h]”hŒ Introduction”…””}”(hjahžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hj^hžhhŸh¶h K ubh¢)”}”(hhh]”(h§)”}”(hŒ Background”h]”hŒ Background”…””}”(hjrhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hjohžhhŸh¶h K#ubhØ)”}”(hX†An FPGA (Field Programmable Gate Array) is a piece of logic hardware, which can be programmed to become virtually anything that is usually found as a dedicated chipset: For instance, a display adapter, network interface card, or even a processor with its peripherals. FPGAs are the LEGO of hardware: Based upon certain building blocks, you make your own toys the way you like them. It's usually pointless to reimplement something that is already available on the market as a chipset, so FPGAs are mostly used when some special functionality is needed, and the production volume is relatively low (hence not justifying the development of an ASIC).”h]”hXˆAn FPGA (Field Programmable Gate Array) is a piece of logic hardware, which can be programmed to become virtually anything that is usually found as a dedicated chipset: For instance, a display adapter, network interface card, or even a processor with its peripherals. FPGAs are the LEGO of hardware: Based upon certain building blocks, you make your own toys the way you like them. It’s usually pointless to reimplement something that is already available on the market as a chipset, so FPGAs are mostly used when some special functionality is needed, and the production volume is relatively low (hence not justifying the development of an ASIC).”…””}”(hj€hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h K%hjohžhubhØ)”}”(hXdThe challenge with FPGAs is that everything is implemented at a very low level, even lower than assembly language. In order to allow FPGA designers to focus on their specific project, and not reinvent the wheel over and over again, pre-designed building blocks, IP cores, are often used. These are the FPGA parallels of library functions. IP cores may implement certain mathematical functions, a functional unit (e.g. a USB interface), an entire processor (e.g. ARM) or anything that might come handy. Think of them as a building block, with electrical wires dangling on the sides for connection to other blocks.”h]”hXdThe challenge with FPGAs is that everything is implemented at a very low level, even lower than assembly language. In order to allow FPGA designers to focus on their specific project, and not reinvent the wheel over and over again, pre-designed building blocks, IP cores, are often used. These are the FPGA parallels of library functions. IP cores may implement certain mathematical functions, a functional unit (e.g. a USB interface), an entire processor (e.g. ARM) or anything that might come handy. Think of them as a building block, with electrical wires dangling on the sides for connection to other blocks.”…””}”(hjŽhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h K/hjohžhubhØ)”}”(hX’One of the daunting tasks in FPGA design is communicating with a fullblown operating system (actually, with the processor running it): Implementing the low-level bus protocol and the somewhat higher-level interface with the host (registers, interrupts, DMA etc.) is a project in itself. When the FPGA's function is a well-known one (e.g. a video adapter card, or a NIC), it can make sense to design the FPGA's interface logic specifically for the project. A special driver is then written to present the FPGA as a well-known interface to the kernel and/or user space. In that case, there is no reason to treat the FPGA differently than any device on the bus.”h]”hX–One of the daunting tasks in FPGA design is communicating with a fullblown operating system (actually, with the processor running it): Implementing the low-level bus protocol and the somewhat higher-level interface with the host (registers, interrupts, DMA etc.) is a project in itself. When the FPGA’s function is a well-known one (e.g. a video adapter card, or a NIC), it can make sense to design the FPGA’s interface logic specifically for the project. A special driver is then written to present the FPGA as a well-known interface to the kernel and/or user space. In that case, there is no reason to treat the FPGA differently than any device on the bus.”…””}”(hjœhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h K9hjohžhubhØ)”}”(hXIt's however common that the desired data communication doesn't fit any well- known peripheral function. Also, the effort of designing an elegant abstraction for the data exchange is often considered too big. In those cases, a quicker and possibly less elegant solution is sought: The driver is effectively written as a user space program, leaving the kernel space part with just elementary data transport. This still requires designing some interface logic for the FPGA, and write a simple ad-hoc driver for the kernel.”h]”hX It’s however common that the desired data communication doesn’t fit any well- known peripheral function. Also, the effort of designing an elegant abstraction for the data exchange is often considered too big. In those cases, a quicker and possibly less elegant solution is sought: The driver is effectively written as a user space program, leaving the kernel space part with just elementary data transport. This still requires designing some interface logic for the FPGA, and write a simple ad-hoc driver for the kernel.”…””}”(hjªhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KChjohžhubeh}”(h]”Œ background”ah ]”h"]”Œ background”ah$]”h&]”uh1h¡hj^hžhhŸh¶h K#ubh¢)”}”(hhh]”(h§)”}”(hŒXillybus Overview”h]”hŒXillybus Overview”…””}”(hjÃhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hjÀhžhhŸh¶h KLubhØ)”}”(hXxXillybus is an IP core and a Linux driver. Together, they form a kit for elementary data transport between an FPGA and the host, providing pipe-like data streams with a straightforward user interface. It's intended as a low- effort solution for mixed FPGA-host projects, for which it makes sense to have the project-specific part of the driver running in a user-space program.”h]”hXzXillybus is an IP core and a Linux driver. Together, they form a kit for elementary data transport between an FPGA and the host, providing pipe-like data streams with a straightforward user interface. It’s intended as a low- effort solution for mixed FPGA-host projects, for which it makes sense to have the project-specific part of the driver running in a user-space program.”…””}”(hjÑhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KNhjÀhžhubhØ)”}”(hXHSince the communication requirements may vary significantly from one FPGA project to another (the number of data pipes needed in each direction and their attributes), there isn't one specific chunk of logic being the Xillybus IP core. Rather, the IP core is configured and built based upon a specification given by its end user.”h]”hXJSince the communication requirements may vary significantly from one FPGA project to another (the number of data pipes needed in each direction and their attributes), there isn’t one specific chunk of logic being the Xillybus IP core. Rather, the IP core is configured and built based upon a specification given by its end user.”…””}”(hjßhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KThjÀhžhubhØ)”}”(hXXillybus presents independent data streams, which resemble pipes or TCP/IP communication to the user. At the host side, a character device file is used just like any pipe file. On the FPGA side, hardware FIFOs are used to stream the data. This is contrary to a common method of communicating through fixed- sized buffers (even though such buffers are used by Xillybus under the hood). There may be more than a hundred of these streams on a single IP core, but also no more than one, depending on the configuration.”h]”hXXillybus presents independent data streams, which resemble pipes or TCP/IP communication to the user. At the host side, a character device file is used just like any pipe file. On the FPGA side, hardware FIFOs are used to stream the data. This is contrary to a common method of communicating through fixed- sized buffers (even though such buffers are used by Xillybus under the hood). There may be more than a hundred of these streams on a single IP core, but also no more than one, depending on the configuration.”…””}”(hjíhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KZhjÀhžhubhØ)”}”(hXuIn order to ease the deployment of the Xillybus IP core, it contains a simple data structure which completely defines the core's configuration. The Linux driver fetches this data structure during its initialization process, and sets up the DMA buffers and character devices accordingly. As a result, a single driver is used to work out of the box with any Xillybus IP core.”h]”hXwIn order to ease the deployment of the Xillybus IP core, it contains a simple data structure which completely defines the core’s configuration. The Linux driver fetches this data structure during its initialization process, and sets up the DMA buffers and character devices accordingly. As a result, a single driver is used to work out of the box with any Xillybus IP core.”…””}”(hjûhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KbhjÀhžhubhØ)”}”(hŒuThe data structure just mentioned should not be confused with PCI's configuration space or the Flattened Device Tree.”h]”hŒwThe data structure just mentioned should not be confused with PCI’s configuration space or the Flattened Device Tree.”…””}”(hj hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KhhjÀhžhubeh}”(h]”Œxillybus-overview”ah ]”h"]”Œxillybus overview”ah$]”h&]”uh1h¡hj^hžhhŸh¶h KLubeh}”(h]”Œ introduction”ah ]”h"]”Œ introduction”ah$]”h&]”uh1h¡hh£hžhhŸh¶h K ubh¢)”}”(hhh]”(h§)”}”(hŒUsage”h]”hŒUsage”…””}”(hj*hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hj'hžhhŸh¶h Klubh¢)”}”(hhh]”(h§)”}”(hŒUser interface”h]”hŒUser interface”…””}”(hj;hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hj8hžhhŸh¶h KoubhØ)”}”(hXæOn the host, all interface with Xillybus is done through /dev/xillybus_* device files, which are generated automatically as the drivers loads. The names of these files depend on the IP core that is loaded in the FPGA (see Probing below). To communicate with the FPGA, open the device file that corresponds to the hardware FIFO you want to send data or receive data from, and use plain write() or read() calls, just like with a regular pipe. In particular, it makes perfect sense to go::”h]”hXåOn the host, all interface with Xillybus is done through /dev/xillybus_* device files, which are generated automatically as the drivers loads. The names of these files depend on the IP core that is loaded in the FPGA (see Probing below). To communicate with the FPGA, open the device file that corresponds to the hardware FIFO you want to send data or receive data from, and use plain write() or read() calls, just like with a regular pipe. In particular, it makes perfect sense to go:”…””}”(hjIhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h Kqhj8hžhubhŒ literal_block”“”)”}”(hŒM$ cat mydata > /dev/xillybus_thisfifo $ cat /dev/xillybus_thatfifo > hisdata”h]”hŒM$ cat mydata > /dev/xillybus_thisfifo $ cat /dev/xillybus_thatfifo > hisdata”…””}”hjYsbah}”(h]”h ]”h"]”h$]”h&]”j\j]uh1jWhŸh¶h Kyhj8hžhubhØ)”}”(hŒpossibly pressing CTRL-C as some stage, even though the xillybus_* pipes have the capability to send an EOF (but may not use it).”h]”hŒpossibly pressing CTRL-C as some stage, even though the xillybus_* pipes have the capability to send an EOF (but may not use it).”…””}”(hjghžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h K}hj8hžhubhØ)”}”(hŒLThe driver and hardware are designed to behave sensibly as pipes, including:”h]”hŒLThe driver and hardware are designed to behave sensibly as pipes, including:”…””}”(hjuhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h K€hj8hžhubhŒ bullet_list”“”)”}”(hhh]”(hŒ list_item”“”)”}”(hŒ@Supporting non-blocking I/O (by setting O_NONBLOCK on open() ). ”h]”hØ)”}”(hŒ?Supporting non-blocking I/O (by setting O_NONBLOCK on open() ).”h]”hŒ?Supporting non-blocking I/O (by setting O_NONBLOCK on open() ).”…””}”(hjŽhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h K‚hjŠubah}”(h]”h ]”h"]”h$]”h&]”uh1jˆhj…hžhhŸh¶h Nubj‰)”}”(hŒ Supporting poll() and select(). ”h]”hØ)”}”(hŒSupporting poll() and select().”h]”hŒSupporting poll() and select().”…””}”(hj¦hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h K„hj¢ubah}”(h]”h ]”h"]”h$]”h&]”uh1jˆhj…hžhhŸh¶h Nubj‰)”}”(hŒBeing bandwidth efficient under load (using DMA) but also handle small pieces of data sent across (like TCP/IP) by autoflushing. ”h]”hØ)”}”(hŒ€Being bandwidth efficient under load (using DMA) but also handle small pieces of data sent across (like TCP/IP) by autoflushing.”h]”hŒ€Being bandwidth efficient under load (using DMA) but also handle small pieces of data sent across (like TCP/IP) by autoflushing.”…””}”(hj¾hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h K†hjºubah}”(h]”h ]”h"]”h$]”h&]”uh1jˆhj…hžhhŸh¶h Nubeh}”(h]”h ]”h"]”h$]”h&]”Œbullet”Œ*”uh1jƒhŸh¶h K‚hj8hžhubhØ)”}”(hŒÅA device file can be read only, write only or bidirectional. Bidirectional device files are treated like two independent pipes (except for sharing a "channel" structure in the implementation code).”h]”hŒÉA device file can be read only, write only or bidirectional. Bidirectional device files are treated like two independent pipes (except for sharing a “channel†structure in the implementation code).”…””}”(hjÚhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h K‰hj8hžhubeh}”(h]”Œuser-interface”ah ]”h"]”Œuser interface”ah$]”h&]”uh1h¡hj'hžhhŸh¶h Koubh¢)”}”(hhh]”(h§)”}”(hŒSynchronization”h]”hŒSynchronization”…””}”(hjóhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hjðhžhhŸh¶h KŽubhØ)”}”(hXºXillybus pipes are configured (on the IP core) to be either synchronous or asynchronous. For a synchronous pipe, write() returns successfully only after some data has been submitted and acknowledged by the FPGA. This slows down bulk data transfers, and is nearly impossible for use with streams that require data at a constant rate: There is no data transmitted to the FPGA between write() calls, in particular when the process loses the CPU.”h]”hXºXillybus pipes are configured (on the IP core) to be either synchronous or asynchronous. For a synchronous pipe, write() returns successfully only after some data has been submitted and acknowledged by the FPGA. This slows down bulk data transfers, and is nearly impossible for use with streams that require data at a constant rate: There is no data transmitted to the FPGA between write() calls, in particular when the process loses the CPU.”…””}”(hjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KhjðhžhubhØ)”}”(hŒˆWhen a pipe is configured asynchronous, write() returns if there was enough room in the buffers to store any of the data in the buffers.”h]”hŒˆWhen a pipe is configured asynchronous, write() returns if there was enough room in the buffers to store any of the data in the buffers.”…””}”(hjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h K—hjðhžhubhØ)”}”(hXFor FPGA to host pipes, asynchronous pipes allow data transfer from the FPGA as soon as the respective device file is opened, regardless of if the data has been requested by a read() call. On synchronous pipes, only the amount of data requested by a read() call is transmitted.”h]”hXFor FPGA to host pipes, asynchronous pipes allow data transfer from the FPGA as soon as the respective device file is opened, regardless of if the data has been requested by a read() call. On synchronous pipes, only the amount of data requested by a read() call is transmitted.”…””}”(hjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KšhjðhžhubhØ)”}”(hŒäIn summary, for synchronous pipes, data between the host and FPGA is transmitted only to satisfy the read() or write() call currently handled by the driver, and those calls wait for the transmission to complete before returning.”h]”hŒäIn summary, for synchronous pipes, data between the host and FPGA is transmitted only to satisfy the read() or write() call currently handled by the driver, and those calls wait for the transmission to complete before returning.”…””}”(hj+hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KŸhjðhžhubhØ)”}”(hXNote that the synchronization attribute has nothing to do with the possibility that read() or write() completes less bytes than requested. There is a separate configuration flag ("allowpartial") that determines whether such a partial completion is allowed.”h]”hXNote that the synchronization attribute has nothing to do with the possibility that read() or write() completes less bytes than requested. There is a separate configuration flag (“allowpartialâ€) that determines whether such a partial completion is allowed.”…””}”(hj9hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h K¤hjðhžhubeh}”(h]”Œsynchronization”ah ]”h"]”Œsynchronization”ah$]”h&]”uh1h¡hj'hžhhŸh¶h KŽubh¢)”}”(hhh]”(h§)”}”(hŒSeekable pipes”h]”hŒSeekable pipes”…””}”(hjRhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hjOhžhhŸh¶h KªubhØ)”}”(hX—A synchronous pipe can be configured to have the stream's position exposed to the user logic at the FPGA. Such a pipe is also seekable on the host API. With this feature, a memory or register interface can be attached on the FPGA side to the seekable stream. Reading or writing to a certain address in the attached memory is done by seeking to the desired address, and calling read() or write() as required.”h]”hX™A synchronous pipe can be configured to have the stream’s position exposed to the user logic at the FPGA. Such a pipe is also seekable on the host API. With this feature, a memory or register interface can be attached on the FPGA side to the seekable stream. Reading or writing to a certain address in the attached memory is done by seeking to the desired address, and calling read() or write() as required.”…””}”(hj`hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h K¬hjOhžhubeh}”(h]”Œseekable-pipes”ah ]”h"]”Œseekable pipes”ah$]”h&]”uh1h¡hj'hžhhŸh¶h Kªubeh}”(h]”Œusage”ah ]”h"]”Œusage”ah$]”h&]”uh1h¡hh£hžhhŸh¶h Klubh¢)”}”(hhh]”(h§)”}”(hŒ Internals”h]”hŒ Internals”…””}”(hjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hj~hžhhŸh¶h Kµubh¢)”}”(hhh]”(h§)”}”(hŒSource code organization”h]”hŒSource code organization”…””}”(hj’hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hjhžhhŸh¶h K¸ubhØ)”}”(hŒšThe Xillybus driver consists of a core module, xillybus_core.c, and modules that depend on the specific bus interface (xillybus_of.c and xillybus_pcie.c).”h]”hŒšThe Xillybus driver consists of a core module, xillybus_core.c, and modules that depend on the specific bus interface (xillybus_of.c and xillybus_pcie.c).”…””}”(hj hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KºhjhžhubhØ)”}”(hX›The bus specific modules are those probed when a suitable device is found by the kernel. Since the DMA mapping and synchronization functions, which are bus dependent by their nature, are used by the core module, a xilly_endpoint_hardware structure is passed to the core module on initialization. This structure is populated with pointers to wrapper functions which execute the DMA-related operations on the bus.”h]”hX›The bus specific modules are those probed when a suitable device is found by the kernel. Since the DMA mapping and synchronization functions, which are bus dependent by their nature, are used by the core module, a xilly_endpoint_hardware structure is passed to the core module on initialization. This structure is populated with pointers to wrapper functions which execute the DMA-related operations on the bus.”…””}”(hj®hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h K½hjhžhubeh}”(h]”Œsource-code-organization”ah ]”h"]”Œsource code organization”ah$]”h&]”uh1h¡hj~hžhhŸh¶h K¸ubh¢)”}”(hhh]”(h§)”}”(hŒPipe attributes”h]”hŒPipe attributes”…””}”(hjÇhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hjÄhžhhŸh¶h KÅubhØ)”}”(hXEach pipe has a number of attributes which are set when the FPGA component (IP core) is built. They are fetched from the IDT (the data structure which defines the core's configuration, see Probing below) by xilly_setupchannels() in xillybus_core.c as follows:”h]”hXEach pipe has a number of attributes which are set when the FPGA component (IP core) is built. They are fetched from the IDT (the data structure which defines the core’s configuration, see Probing below) by xilly_setupchannels() in xillybus_core.c as follows:”…””}”(hjÕhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KÇhjÄhžhubj„)”}”(hhh]”(j‰)”}”(hŒiis_writebuf: The pipe's direction. A non-zero value means it's an FPGA to host pipe (the FPGA "writes"). ”h]”hØ)”}”(hŒhis_writebuf: The pipe's direction. A non-zero value means it's an FPGA to host pipe (the FPGA "writes").”h]”hŒpis_writebuf: The pipe’s direction. A non-zero value means it’s an FPGA to host pipe (the FPGA “writesâ€).”…””}”(hjêhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KÌhjæubah}”(h]”h ]”h"]”h$]”h&]”uh1jˆhjãhžhhŸh¶h Nubj‰)”}”(hŒYchannelnum: The pipe's identification number in communication between the host and FPGA. ”h]”hØ)”}”(hŒXchannelnum: The pipe's identification number in communication between the host and FPGA.”h]”hŒZchannelnum: The pipe’s identification number in communication between the host and FPGA.”…””}”(hjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KÏhjþubah}”(h]”h ]”h"]”h$]”h&]”uh1jˆhjãhžhhŸh¶h Nubj‰)”}”(hŒ?format: The underlying data width. See Data Granularity below. ”h]”hØ)”}”(hŒ>format: The underlying data width. See Data Granularity below.”h]”hŒ>format: The underlying data width. See Data Granularity below.”…””}”(hjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KÒhjubah}”(h]”h ]”h"]”h$]”h&]”uh1jˆhjãhžhhŸh¶h Nubj‰)”}”(hŒÓallowpartial: A non-zero value means that a read() or write() (whichever applies) may return with less than the requested number of bytes. The common choice is a non-zero value, to match standard UNIX behavior. ”h]”hØ)”}”(hŒÒallowpartial: A non-zero value means that a read() or write() (whichever applies) may return with less than the requested number of bytes. The common choice is a non-zero value, to match standard UNIX behavior.”h]”hŒÒallowpartial: A non-zero value means that a read() or write() (whichever applies) may return with less than the requested number of bytes. The common choice is a non-zero value, to match standard UNIX behavior.”…””}”(hj2hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KÔhj.ubah}”(h]”h ]”h"]”h$]”h&]”uh1jˆhjãhžhhŸh¶h Nubj‰)”}”(hŒ]synchronous: A non-zero value means that the pipe is synchronous. See Synchronization above. ”h]”hØ)”}”(hŒ\synchronous: A non-zero value means that the pipe is synchronous. See Synchronization above.”h]”hŒ\synchronous: A non-zero value means that the pipe is synchronous. See Synchronization above.”…””}”(hjJhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KØhjFubah}”(h]”h ]”h"]”h$]”h&]”uh1jˆhjãhžhhŸh¶h Nubj‰)”}”(hŒ8bufsize: Each DMA buffer's size. Always a power of two. ”h]”hØ)”}”(hŒ7bufsize: Each DMA buffer's size. Always a power of two.”h]”hŒ9bufsize: Each DMA buffer’s size. Always a power of two.”…””}”(hjbhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KÛhj^ubah}”(h]”h ]”h"]”h$]”h&]”uh1jˆhjãhžhhŸh¶h Nubj‰)”}”(hŒNbufnum: The number of buffers allocated for this pipe. Always a power of two. ”h]”hØ)”}”(hŒMbufnum: The number of buffers allocated for this pipe. Always a power of two.”h]”hŒMbufnum: The number of buffers allocated for this pipe. Always a power of two.”…””}”(hjzhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KÝhjvubah}”(h]”h ]”h"]”h$]”h&]”uh1jˆhjãhžhhŸh¶h Nubj‰)”}”(hŒÓexclusive_open: A non-zero value forces exclusive opening of the associated device file. If the device file is bidirectional, and already opened only in one direction, the opposite direction may be opened once. ”h]”hØ)”}”(hŒÒexclusive_open: A non-zero value forces exclusive opening of the associated device file. If the device file is bidirectional, and already opened only in one direction, the opposite direction may be opened once.”h]”hŒÒexclusive_open: A non-zero value forces exclusive opening of the associated device file. If the device file is bidirectional, and already opened only in one direction, the opposite direction may be opened once.”…””}”(hj’hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KßhjŽubah}”(h]”h ]”h"]”h$]”h&]”uh1jˆhjãhžhhŸh¶h Nubj‰)”}”(hŒZseekable: A non-zero value indicates that the pipe is seekable. See Seekable pipes above. ”h]”hØ)”}”(hŒYseekable: A non-zero value indicates that the pipe is seekable. See Seekable pipes above.”h]”hŒYseekable: A non-zero value indicates that the pipe is seekable. See Seekable pipes above.”…””}”(hjªhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h Kãhj¦ubah}”(h]”h ]”h"]”h$]”h&]”uh1jˆhjãhžhhŸh¶h Nubj‰)”}”(hŒ«supports_nonempty: A non-zero value (which is typical) indicates that the hardware will send the messages that are necessary to support select() and poll() for this pipe. ”h]”hØ)”}”(hŒªsupports_nonempty: A non-zero value (which is typical) indicates that the hardware will send the messages that are necessary to support select() and poll() for this pipe.”h]”hŒªsupports_nonempty: A non-zero value (which is typical) indicates that the hardware will send the messages that are necessary to support select() and poll() for this pipe.”…””}”(hjÂhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h Kæhj¾ubah}”(h]”h ]”h"]”h$]”h&]”uh1jˆhjãhžhhŸh¶h Nubeh}”(h]”h ]”h"]”h$]”h&]”jØjÙuh1jƒhŸh¶h KÌhjÄhžhubeh}”(h]”Œpipe-attributes”ah ]”h"]”Œpipe attributes”ah$]”h&]”uh1h¡hj~hžhhŸh¶h KÅubh¢)”}”(hhh]”(h§)”}”(hŒHost never reads from the FPGA”h]”hŒHost never reads from the FPGA”…””}”(hjçhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hjähžhhŸh¶h KëubhØ)”}”(hXUEven though PCI Express is hotpluggable in general, a typical motherboard doesn't expect a card to go away all of the sudden. But since the PCIe card is based upon reprogrammable logic, a sudden disappearance from the bus is quite likely as a result of an accidental reprogramming of the FPGA while the host is up. In practice, nothing happens immediately in such a situation. But if the host attempts to read from an address that is mapped to the PCI Express device, that leads to an immediate freeze of the system on some motherboards, even though the PCIe standard requires a graceful recovery.”h]”hXWEven though PCI Express is hotpluggable in general, a typical motherboard doesn’t expect a card to go away all of the sudden. But since the PCIe card is based upon reprogrammable logic, a sudden disappearance from the bus is quite likely as a result of an accidental reprogramming of the FPGA while the host is up. In practice, nothing happens immediately in such a situation. But if the host attempts to read from an address that is mapped to the PCI Express device, that leads to an immediate freeze of the system on some motherboards, even though the PCIe standard requires a graceful recovery.”…””}”(hjõhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KíhjähžhubhØ)”}”(hXµIn order to avoid these freezes, the Xillybus driver refrains completely from reading from the device's register space. All communication from the FPGA to the host is done through DMA. In particular, the Interrupt Service Routine doesn't follow the common practice of checking a status register when it's invoked. Rather, the FPGA prepares a small buffer which contains short messages, which inform the host what the interrupt was about.”h]”hX»In order to avoid these freezes, the Xillybus driver refrains completely from reading from the device’s register space. All communication from the FPGA to the host is done through DMA. In particular, the Interrupt Service Routine doesn’t follow the common practice of checking a status register when it’s invoked. Rather, the FPGA prepares a small buffer which contains short messages, which inform the host what the interrupt was about.”…””}”(hjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h KöhjähžhubhØ)”}”(hŒLThis mechanism is used on non-PCIe buses as well for the sake of uniformity.”h]”hŒLThis mechanism is used on non-PCIe buses as well for the sake of uniformity.”…””}”(hjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h Kýhjähžhubeh}”(h]”Œhost-never-reads-from-the-fpga”ah ]”h"]”Œhost never reads from the fpga”ah$]”h&]”uh1h¡hj~hžhhŸh¶h Këubh¢)”}”(hhh]”(h§)”}”(hŒ(Channels, pipes, and the message channel”h]”hŒ(Channels, pipes, and the message channel”…””}”(hj*hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hj'hžhhŸh¶h MubhØ)”}”(hX+Each of the (possibly bidirectional) pipes presented to the user is allocated a data channel between the FPGA and the host. The distinction between channels and pipes is necessary only because of channel 0, which is used for interrupt- related messages from the FPGA, and has no pipe attached to it.”h]”hX+Each of the (possibly bidirectional) pipes presented to the user is allocated a data channel between the FPGA and the host. The distinction between channels and pipes is necessary only because of channel 0, which is used for interrupt- related messages from the FPGA, and has no pipe attached to it.”…””}”(hj8hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h Mhj'hžhubeh}”(h]”Œ&channels-pipes-and-the-message-channel”ah ]”h"]”Œ(channels, pipes, and the message channel”ah$]”h&]”uh1h¡hj~hžhhŸh¶h Mubh¢)”}”(hhh]”(h§)”}”(hŒData streaming”h]”hŒData streaming”…””}”(hjQhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hjNhžhhŸh¶h M ubhØ)”}”(hX+Even though a non-segmented data stream is presented to the user at both sides, the implementation relies on a set of DMA buffers which is allocated for each channel. For the sake of illustration, let's take the FPGA to host direction: As data streams into the respective channel's interface in the FPGA, the Xillybus IP core writes it to one of the DMA buffers. When the buffer is full, the FPGA informs the host about that (appending a XILLYMSG_OPCODE_RELEASEBUF message channel 0 and sending an interrupt if necessary). The host responds by making the data available for reading through the character device. When all data has been read, the host writes on the FPGA's buffer control register, allowing the buffer's overwriting. Flow control mechanisms exist on both sides to prevent underflows and overflows.”h]”hX3Even though a non-segmented data stream is presented to the user at both sides, the implementation relies on a set of DMA buffers which is allocated for each channel. For the sake of illustration, let’s take the FPGA to host direction: As data streams into the respective channel’s interface in the FPGA, the Xillybus IP core writes it to one of the DMA buffers. When the buffer is full, the FPGA informs the host about that (appending a XILLYMSG_OPCODE_RELEASEBUF message channel 0 and sending an interrupt if necessary). The host responds by making the data available for reading through the character device. When all data has been read, the host writes on the FPGA’s buffer control register, allowing the buffer’s overwriting. Flow control mechanisms exist on both sides to prevent underflows and overflows.”…””}”(hj_hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h M hjNhžhubhØ)”}”(hX¨This is not good enough for creating a TCP/IP-like stream: If the data flow stops momentarily before a DMA buffer is filled, the intuitive expectation is that the partial data in buffer will arrive anyhow, despite the buffer not being completed. This is implemented by adding a field in the XILLYMSG_OPCODE_RELEASEBUF message, through which the FPGA informs not just which buffer is submitted, but how much data it contains.”h]”hX¨This is not good enough for creating a TCP/IP-like stream: If the data flow stops momentarily before a DMA buffer is filled, the intuitive expectation is that the partial data in buffer will arrive anyhow, despite the buffer not being completed. This is implemented by adding a field in the XILLYMSG_OPCODE_RELEASEBUF message, through which the FPGA informs not just which buffer is submitted, but how much data it contains.”…””}”(hjmhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h MhjNhžhubhØ)”}”(hXÅBut the FPGA will submit a partially filled buffer only if directed to do so by the host. This situation occurs when the read() method has been blocking for XILLY_RX_TIMEOUT jiffies (currently 10 ms), after which the host commands the FPGA to submit a DMA buffer as soon as it can. This timeout mechanism balances between bus bandwidth efficiency (preventing a lot of partially filled buffers being sent) and a latency held fairly low for tails of data.”h]”hXÅBut the FPGA will submit a partially filled buffer only if directed to do so by the host. This situation occurs when the read() method has been blocking for XILLY_RX_TIMEOUT jiffies (currently 10 ms), after which the host commands the FPGA to submit a DMA buffer as soon as it can. This timeout mechanism balances between bus bandwidth efficiency (preventing a lot of partially filled buffers being sent) and a latency held fairly low for tails of data.”…””}”(hj{hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h MhjNhžhubhØ)”}”(hX8A similar setting is used in the host to FPGA direction. The handling of partial DMA buffers is somewhat different, though. The user can tell the driver to submit all data it has in the buffers to the FPGA, by issuing a write() with the byte count set to zero. This is similar to a flush request, but it doesn't block. There is also an autoflushing mechanism, which triggers an equivalent flush roughly XILLY_RX_TIMEOUT jiffies after the last write(). This allows the user to be oblivious about the underlying buffering mechanism and yet enjoy a stream-like interface.”h]”hX:A similar setting is used in the host to FPGA direction. The handling of partial DMA buffers is somewhat different, though. The user can tell the driver to submit all data it has in the buffers to the FPGA, by issuing a write() with the byte count set to zero. This is similar to a flush request, but it doesn’t block. There is also an autoflushing mechanism, which triggers an equivalent flush roughly XILLY_RX_TIMEOUT jiffies after the last write(). This allows the user to be oblivious about the underlying buffering mechanism and yet enjoy a stream-like interface.”…””}”(hj‰hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h M%hjNhžhubhØ)”}”(hŒßNote that the issue of partial buffer flushing is irrelevant for pipes having the "synchronous" attribute nonzero, since synchronous pipes don't allow data to lay around in the DMA buffers between read() and write() anyhow.”h]”hŒåNote that the issue of partial buffer flushing is irrelevant for pipes having the “synchronous†attribute nonzero, since synchronous pipes don’t allow data to lay around in the DMA buffers between read() and write() anyhow.”…””}”(hj—hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h M.hjNhžhubeh}”(h]”Œdata-streaming”ah ]”h"]”Œdata streaming”ah$]”h&]”uh1h¡hj~hžhhŸh¶h M ubh¢)”}”(hhh]”(h§)”}”(hŒData granularity”h]”hŒData granularity”…””}”(hj°hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hj­hžhhŸh¶h M3ubhØ)”}”(hX*The data arrives or is sent at the FPGA as 8, 16 or 32 bit wide words, as configured by the "format" attribute. Whenever possible, the driver attempts to hide this when the pipe is accessed differently from its natural alignment. For example, reading single bytes from a pipe with 32 bit granularity works with no issues. Writing single bytes to pipes with 16 or 32 bit granularity will also work, but the driver can't send partially completed words to the FPGA, so the transmission of up to one word may be held until it's fully occupied with user data.”h]”hX2The data arrives or is sent at the FPGA as 8, 16 or 32 bit wide words, as configured by the “format†attribute. Whenever possible, the driver attempts to hide this when the pipe is accessed differently from its natural alignment. For example, reading single bytes from a pipe with 32 bit granularity works with no issues. Writing single bytes to pipes with 16 or 32 bit granularity will also work, but the driver can’t send partially completed words to the FPGA, so the transmission of up to one word may be held until it’s fully occupied with user data.”…””}”(hj¾hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h M5hj­hžhubhØ)”}”(hXmThis somewhat complicates the handling of host to FPGA streams, because when a buffer is flushed, it may contain up to 3 bytes don't form a word in the FPGA, and hence can't be sent. To prevent loss of data, these leftover bytes need to be moved to the next buffer. The parts in xillybus_core.c that mention "leftovers" in some way are related to this complication.”h]”hXuThis somewhat complicates the handling of host to FPGA streams, because when a buffer is flushed, it may contain up to 3 bytes don’t form a word in the FPGA, and hence can’t be sent. To prevent loss of data, these leftover bytes need to be moved to the next buffer. The parts in xillybus_core.c that mention “leftovers†in some way are related to this complication.”…””}”(hjÌhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h M>hj­hžhubeh}”(h]”Œdata-granularity”ah ]”h"]”Œdata granularity”ah$]”h&]”uh1h¡hj~hžhhŸh¶h M3ubh¢)”}”(hhh]”(h§)”}”(hŒProbing”h]”hŒProbing”…””}”(hjåhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hjâhžhhŸh¶h MEubhØ)”}”(hXTAs mentioned earlier, the number of pipes that are created when the driver loads and their attributes depend on the Xillybus IP core in the FPGA. During the driver's initialization, a blob containing configuration info, the Interface Description Table (IDT), is sent from the FPGA to the host. The bootstrap process is done in three phases:”h]”hXVAs mentioned earlier, the number of pipes that are created when the driver loads and their attributes depend on the Xillybus IP core in the FPGA. During the driver’s initialization, a blob containing configuration info, the Interface Description Table (IDT), is sent from the FPGA to the host. The bootstrap process is done in three phases:”…””}”(hjóhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h MGhjâhžhubhŒenumerated_list”“”)”}”(hhh]”(j‰)”}”(hŒÆAcquire the length of the IDT, so a buffer can be allocated for it. This is done by sending a quiesce command to the device, since the acknowledge for this command contains the IDT's buffer length. ”h]”hØ)”}”(hŒÅAcquire the length of the IDT, so a buffer can be allocated for it. This is done by sending a quiesce command to the device, since the acknowledge for this command contains the IDT's buffer length.”h]”hŒÇAcquire the length of the IDT, so a buffer can be allocated for it. This is done by sending a quiesce command to the device, since the acknowledge for this command contains the IDT’s buffer length.”…””}”(hj hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h MMhjubah}”(h]”h ]”h"]”h$]”h&]”uh1jˆhjhžhhŸh¶h Nubj‰)”}”(hŒAcquire the IDT itself. ”h]”hØ)”}”(hŒAcquire the IDT itself.”h]”hŒAcquire the IDT itself.”…””}”(hj"hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h MQhjubah}”(h]”h ]”h"]”h$]”h&]”uh1jˆhjhžhhŸh¶h Nubj‰)”}”(hŒ,Create the interfaces according to the IDT. ”h]”hØ)”}”(hŒ+Create the interfaces according to the IDT.”h]”hŒ+Create the interfaces according to the IDT.”…””}”(hj:hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h MShj6ubah}”(h]”h ]”h"]”h$]”h&]”uh1jˆhjhžhhŸh¶h Nubeh}”(h]”h ]”h"]”h$]”h&]”Œenumtype”Œarabic”Œprefix”hŒsuffix”Œ.”uh1jhjâhžhhŸh¶h MMubeh}”(h]”Œprobing”ah ]”h"]”Œprobing”ah$]”h&]”uh1h¡hj~hžhhŸh¶h MEubh¢)”}”(hhh]”(h§)”}”(hŒBuffer allocation”h]”hŒBuffer allocation”…””}”(hjdhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hjahžhhŸh¶h MVubhØ)”}”(hX÷In order to simplify the logic that prevents illegal boundary crossings of PCIe packets, the following rule applies: If a buffer is smaller than 4kB, it must not cross a 4kB boundary. Otherwise, it must be 4kB aligned. The xilly_setupchannels() functions allocates these buffers by requesting whole pages from the kernel, and diving them into DMA buffers as necessary. Since all buffers' sizes are powers of two, it's possible to pack any set of such buffers, with a maximal waste of one page of memory.”h]”hXûIn order to simplify the logic that prevents illegal boundary crossings of PCIe packets, the following rule applies: If a buffer is smaller than 4kB, it must not cross a 4kB boundary. Otherwise, it must be 4kB aligned. The xilly_setupchannels() functions allocates these buffers by requesting whole pages from the kernel, and diving them into DMA buffers as necessary. Since all buffers’ sizes are powers of two, it’s possible to pack any set of such buffers, with a maximal waste of one page of memory.”…””}”(hjrhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h MXhjahžhubhØ)”}”(hŒÙAll buffers are allocated when the driver is loaded. This is necessary, since large continuous physical memory segments are sometimes requested, which are more likely to be available when the system is freshly booted.”h]”hŒÙAll buffers are allocated when the driver is loaded. This is necessary, since large continuous physical memory segments are sometimes requested, which are more likely to be available when the system is freshly booted.”…””}”(hj€hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h M`hjahžhubhØ)”}”(hX–The allocation of buffer memory takes place in the same order they appear in the IDT. The driver relies on a rule that the pipes are sorted with decreasing buffer size in the IDT. If a requested buffer is larger or equal to a page, the necessary number of pages is requested from the kernel, and these are used for this buffer. If the requested buffer is smaller than a page, one single page is requested from the kernel, and that page is partially used. Or, if there already is a partially used page at hand, the buffer is packed into that page. It can be shown that all pages requested from the kernel (except possibly for the last) are 100% utilized this way.”h]”hX–The allocation of buffer memory takes place in the same order they appear in the IDT. The driver relies on a rule that the pipes are sorted with decreasing buffer size in the IDT. If a requested buffer is larger or equal to a page, the necessary number of pages is requested from the kernel, and these are used for this buffer. If the requested buffer is smaller than a page, one single page is requested from the kernel, and that page is partially used. Or, if there already is a partially used page at hand, the buffer is packed into that page. It can be shown that all pages requested from the kernel (except possibly for the last) are 100% utilized this way.”…””}”(hjŽhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h Mdhjahžhubeh}”(h]”Œbuffer-allocation”ah ]”h"]”Œbuffer allocation”ah$]”h&]”uh1h¡hj~hžhhŸh¶h MVubh¢)”}”(hhh]”(h§)”}”(hŒ(The "nonempty" message (supporting poll)”h]”hŒ,The “nonempty†message (supporting poll)”…””}”(hj§hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hj¤hžhhŸh¶h MoubhØ)”}”(hX9In order to support the "poll" method (and hence select() ), there is a small catch regarding the FPGA to host direction: The FPGA may have filled a DMA buffer with some data, but not submitted that buffer. If the host waited for the buffer's submission by the FPGA, there would be a possibility that the FPGA side has sent data, but a select() call would still block, because the host has not received any notification about this. This is solved with XILLYMSG_OPCODE_NONEMPTY messages sent by the FPGA when a channel goes from completely empty to containing some data.”h]”hX?In order to support the “poll†method (and hence select() ), there is a small catch regarding the FPGA to host direction: The FPGA may have filled a DMA buffer with some data, but not submitted that buffer. If the host waited for the buffer’s submission by the FPGA, there would be a possibility that the FPGA side has sent data, but a select() call would still block, because the host has not received any notification about this. This is solved with XILLYMSG_OPCODE_NONEMPTY messages sent by the FPGA when a channel goes from completely empty to containing some data.”…””}”(hjµhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h Mqhj¤hžhubhØ)”}”(hŒThese messages are used only to support poll() and select(). The IP core can be configured not to send them for a slight reduction of bandwidth.”h]”hŒThese messages are used only to support poll() and select(). The IP core can be configured not to send them for a slight reduction of bandwidth.”…””}”(hjÃhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h×hŸh¶h Mzhj¤hžhubeh}”(h]”Œ$the-nonempty-message-supporting-poll”ah ]”h"]”Œ(the "nonempty" message (supporting poll)”ah$]”h&]”uh1h¡hj~hžhhŸh¶h Moubeh}”(h]”Œ internals”ah ]”h"]”Œ internals”ah$]”h&]”uh1h¡hh£hžhhŸh¶h Kµubeh}”(h]”Œ*xillybus-driver-for-generic-fpga-interface”ah ]”h"]”Œ*xillybus driver for generic fpga interface”ah$]”h&]”uh1h¡hhhžhhŸh¶h Kubeh}”(h]”h ]”h"]”h$]”h&]”Œsource”h¶uh1hŒcurrent_source”NŒ current_line”NŒsettings”Œdocutils.frontend”ŒValues”“”)”}”(h¦NŒ generator”NŒ datestamp”NŒ source_link”NŒ source_url”NŒ toc_backlinks”Œentry”Œfootnote_backlinks”KŒ sectnum_xform”KŒstrip_comments”NŒstrip_elements_with_classes”NŒ strip_classes”NŒ report_level”KŒ halt_level”KŒexit_status_level”KŒdebug”NŒwarning_stream”NŒ traceback”ˆŒinput_encoding”Œ utf-8-sig”Œinput_encoding_error_handler”Œstrict”Œoutput_encoding”Œutf-8”Œoutput_encoding_error_handler”j Œerror_encoding”Œutf-8”Œerror_encoding_error_handler”Œbackslashreplace”Œ language_code”Œen”Œrecord_dependencies”NŒconfig”NŒ id_prefix”hŒauto_id_prefix”Œid”Œ dump_settings”NŒdump_internals”NŒdump_transforms”NŒdump_pseudo_xml”NŒexpose_internals”NŒstrict_visitor”NŒ_disable_config”NŒ_source”h¶Œ _destination”NŒ _config_files”]”Œ7/var/lib/git/docbuild/linux/Documentation/docutils.conf”aŒfile_insertion_enabled”ˆŒ raw_enabled”KŒline_length_limit”M'Œpep_references”NŒ pep_base_url”Œhttps://peps.python.org/”Œpep_file_url_template”Œpep-%04d”Œrfc_references”NŒ rfc_base_url”Œ&https://datatracker.ietf.org/doc/html/”Œ tab_width”KŒtrim_footnote_reference_space”‰Œsyntax_highlight”Œlong”Œ smart_quotes”ˆŒsmartquotes_locales”]”Œcharacter_level_inline_markup”‰Œdoctitle_xform”‰Œ docinfo_xform”KŒsectsubtitle_xform”‰Œ image_loading”Œlink”Œembed_stylesheet”‰Œcloak_email_addresses”ˆŒsection_self_link”‰Œenv”NubŒreporter”NŒindirect_targets”]”Œsubstitution_defs”}”Œsubstitution_names”}”Œrefnames”}”Œrefids”}”Œnameids”}”(jæjãj$j!j½jºjjj{jxjíjêjLjIjsjpjÞjÛjÁj¾jájÞj$j!jKjHjªj§jßjÜj^j[j¡jžjÖjÓuŒ nametypes”}”(jæ‰j$‰j½‰j‰j{‰jí‰jL‰js‰jÞ‰jÁ‰já‰j$‰jK‰jª‰j߉j^‰j¡‰jÖ‰uh}”(jãh£j!j^jºjojjÀjxj'jêj8jIjðjpjOjÛj~j¾jjÞjÄj!jäjHj'j§jNjÜj­j[jâjžjajÓj¤uŒ footnote_refs”}”Œ citation_refs”}”Œ autofootnotes”]”Œautofootnote_refs”]”Œsymbol_footnotes”]”Œsymbol_footnote_refs”]”Œ footnotes”]”Œ citations”]”Œautofootnote_start”KŒsymbol_footnote_start”KŒ id_counter”Œ collections”ŒCounter”“”}”…”R”Œparse_messages”]”Œtransform_messages”]”Œ transformer”NŒ include_log”]”Œ decoration”Nhžhub.