Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1420097 > unrolled thread
| Started by | Henrik Austad <henrik@austad.us> |
|---|---|
| First post | 2016-06-12 01:10 +0200 |
| Last post | 2016-06-15 05:30 +0200 |
| Articles | 20 on this page of 47 — 9 participants |
Back to article view | Back to linux.kernel
[very-RFC 0/8] TSN driver for the kernel Henrik Austad <henrik@austad.us> - 2016-06-12 01:10 +0200
[very-RFC 1/8] TSN: add documentation Henrik Austad <henrik@austad.us> - 2016-06-12 01:10 +0200
[very-RFC 3/8] Adding TSN-driver to Intel I210 controller Henrik Austad <henrik@austad.us> - 2016-06-12 01:10 +0200
[very-RFC 6/8] Add TSN event-tracing Henrik Austad <henrik@austad.us> - 2016-06-12 01:10 +0200
Re: [very-RFC 6/8] Add TSN event-tracing Steven Rostedt <rostedt@goodmis.org> - 2016-06-12 19:00 +0200
Re: [very-RFC 6/8] Add TSN event-tracing Henrik Austad <henrik@austad.us> - 2016-06-12 23:30 +0200
Re: [very-RFC 6/8] Add TSN event-tracing Steven Rostedt <rostedt@goodmis.org> - 2016-06-13 04:30 +0200
Re: [very-RFC 6/8] Add TSN event-tracing Henrik Austad <henrik@austad.us> - 2016-06-13 09:30 +0200
[very-RFC 8/8] MAINTAINERS: add TSN/AVB-entries Henrik Austad <henrik@austad.us> - 2016-06-12 01:10 +0200
Re: [very-RFC 0/8] TSN driver for the kernel Richard Cochran <richardcochran@gmail.com> - 2016-06-13 13:50 +0200
Re: [very-RFC 0/8] TSN driver for the kernel Henrik Austad <henrik@austad.us> - 2016-06-13 15:10 +0200
Re: [very-RFC 0/8] TSN driver for the kernel Richard Cochran <richardcochran@gmail.com> - 2016-06-13 21:40 +0200
Re: [very-RFC 0/8] TSN driver for the kernel Henrik Austad <henrik@austad.us> - 2016-06-14 11:40 +0200
Re: [very-RFC 0/8] TSN driver for the kernel Richard Cochran <richardcochran@gmail.com> - 2016-06-14 20:30 +0200
Re: [very-RFC 0/8] TSN driver for the kernel Henrik Austad <henrik@austad.us> - 2016-06-14 22:40 +0200
Re: [very-RFC 0/8] TSN driver for the kernel Richard Cochran <richardcochran@gmail.com> - 2016-06-15 09:10 +0200
Re: [very-RFC 0/8] TSN driver for the kernel Henrik Austad <henrik@austad.us> - 2016-06-15 10:00 +0200
Re: [very-RFC 0/8] TSN driver for the kernel Richard Cochran <richardcochran@gmail.com> - 2016-06-15 13:50 +0200
Re: [very-RFC 0/8] TSN driver for the kernel Richard Cochran <richardcochran@gmail.com> - 2016-06-15 09:20 +0200
Re: [very-RFC 0/8] TSN driver for the kernel Richard Cochran <richardcochran@gmail.com> - 2016-06-13 21:40 +0200
Re: [very-RFC 0/8] TSN driver for the kernel Arnd Bergmann <arnd@linaro.org> - 2016-06-13 15:20 +0200
Re: [very-RFC 0/8] TSN driver for the kernel John Fastabend <john.fastabend@gmail.com> - 2016-06-13 18:00 +0200
Re: [very-RFC 0/8] TSN driver for the kernel Henrik Austad <henrik@austad.us> - 2016-06-14 10:40 +0200
Re: [very-RFC 0/8] TSN driver for the kernel Richard Cochran <richardcochran@gmail.com> - 2016-06-13 22:00 +0200
Re: [very-RFC 0/8] TSN driver for the kernel One Thousand Gnomes <gnomes@lxorguk.ukuu.org.uk> - 2016-06-14 13:20 +0200
Re: [very-RFC 0/8] TSN driver for the kernel Richard Cochran <richardcochran@gmail.com> - 2016-06-14 19:10 +0200
Re: [very-RFC 0/8] TSN driver for the kernel Takashi Sakamoto <o-takashi@sakamocchi.jp> - 2016-06-15 05:30 +0200
Re: [very-RFC 0/8] TSN driver for the kernel Richard Cochran <richardcochran@gmail.com> - 2016-06-15 10:10 +0200
Re: [very-RFC 0/8] TSN driver for the kernel Takashi Sakamoto <o-takashi@sakamocchi.jp> - 2016-06-18 07:30 +0200
Re: [very-RFC 0/8] TSN driver for the kernel Henrik Austad <henrik@austad.us> - 2016-06-19 00:50 +0200
Re: [very-RFC 0/8] TSN driver for the kernel Richard Cochran <richardcochran@gmail.com> - 2016-06-19 11:50 +0200
Re: [very-RFC 0/8] TSN driver for the kernel Henrik Austad <henrik@austad.us> - 2016-06-20 11:50 +0200
Re: [alsa-devel] [very-RFC 0/8] TSN driver for the kernel Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> - 2016-06-20 13:20 +0200
Re: [alsa-devel] [very-RFC 0/8] TSN driver for the kernel Henrik Austad <henrik@austad.us> - 2016-06-20 14:00 +0200
Re: [alsa-devel] [very-RFC 0/8] TSN driver for the kernel Richard Cochran <richardcochran@gmail.com> - 2016-06-20 14:30 +0200
Re: [alsa-devel] [very-RFC 0/8] TSN driver for the kernel Richard Cochran <richardcochran@gmail.com> - 2016-06-20 15:00 +0200
Re: [alsa-devel] [very-RFC 0/8] TSN driver for the kernel Richard Cochran <richardcochran@gmail.com> - 2016-06-20 17:40 +0200
Re: [alsa-devel] [very-RFC 0/8] TSN driver for the kernel Takashi Iwai <tiwai@suse.de> - 2016-06-21 08:00 +0200
Re: [alsa-devel] [very-RFC 0/8] TSN driver for the kernel Richard Cochran <richardcochran@gmail.com> - 2016-06-21 08:40 +0200
Re: [alsa-devel] [very-RFC 0/8] TSN driver for the kernel Takashi Iwai <tiwai@suse.de> - 2016-06-21 08:50 +0200
Re: [alsa-devel] [very-RFC 0/8] TSN driver for the kernel Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> - 2016-06-21 19:20 +0200
Re: [alsa-devel] [very-RFC 0/8] TSN driver for the kernel Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> - 2016-06-21 19:50 +0200
Re: [alsa-devel] [very-RFC 0/8] TSN driver for the kernel Richard Cochran <richardcochran@gmail.com> - 2016-06-21 23:20 +0200
Re: [alsa-devel] [very-RFC 0/8] TSN driver for the kernel Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> - 2016-06-22 14:40 +0200
Re: [alsa-devel] [very-RFC 0/8] TSN driver for the kernel Henrik Austad <henrik@austad.us> - 2016-06-23 12:40 +0200
Re: [alsa-devel] [very-RFC 0/8] TSN driver for the kernel Richard Cochran <richardcochran@gmail.com> - 2016-06-23 15:30 +0200
Re: [very-RFC 0/8] TSN driver for the kernel Takashi Sakamoto <o-takashi@sakamocchi.jp> - 2016-06-15 05:30 +0200
Page 1 of 3 [1] 2 3 Next page →
| From | Henrik Austad <henrik@austad.us> |
|---|---|
| Date | 2016-06-12 01:10 +0200 |
| Subject | [very-RFC 0/8] TSN driver for the kernel |
| Message-ID | <rJ0cp-QL-3@gated-at.bofh.it> |
Hi all (series based on v4.7-rc2, now with the correct netdev) This is a *very* early RFC for a TSN-driver in the kernel. It has been floating around in my repo for a while and I would appreciate some feedback on the overall design to avoid doing some major blunders. TSN: Time Sensitive Networking, formely known as AVB (Audio/Video Bridging). There are at least one AVB-driver (the AV-part of TSN) in the kernel already, however this driver aims to solve a wider scope as TSN can do much more than just audio. A very basic ALSA-driver is added to the end that allows you to play music between 2 machines using aplay in one end and arecord | aplay on the other (some fiddling required) We have plans for doing the same for v4l2 eventually (but there are other fishes to fry first). The same goes for a TSN_SOCK type approach as well. TSN is all about providing infrastructure. Allthough there are a few very interesting uses for TSN (reliable, deterministic network for audio and video), once you have that reliable link, you can do a lot more. Some notes on the design: The driver is directed via ConfigFS as we need userspace to handle stream-reservation (MSRP), discovery and enumeration (IEEE 1722.1) and whatever other management is needed. Once we have all the required attributes, we can create link using mkdir, and use write() to set the attributes. Once ready, specify the 'shim' (basically a thin wrapper between TSN and another subsystem) and we start pushing out frames. The network part: it ties directly into the rx-handler for receive and writes skb's using netdev_start_xmit(). This could probably be improved. 2 new fields in netdev_ops have been introduced, and the Intel igb-driver has been updated (as this is available as a PCI-e card). The igb-driver works-ish What remains - tie to (g)PTP properly, currently using ktime_get() for presentation time - get time from shim into TSN and vice versa - let shim create/manage buffer Henrik Austad (8): TSN: add documentation TSN: Add the standard formerly known as AVB to the kernel Adding TSN-driver to Intel I210 controller Add TSN header for the driver Add TSN machinery to drive the traffic from a shim over the network Add TSN event-tracing AVB ALSA - Add ALSA shim for TSN MAINTAINERS: add TSN/AVB-entries Documentation/TSN/tsn.txt | 147 +++++ MAINTAINERS | 14 + drivers/media/Kconfig | 15 + drivers/media/Makefile | 3 +- drivers/media/avb/Makefile | 5 + drivers/media/avb/avb_alsa.c | 742 +++++++++++++++++++++++ drivers/media/avb/tsn_iec61883.h | 124 ++++ drivers/net/ethernet/intel/Kconfig | 18 + drivers/net/ethernet/intel/igb/Makefile | 2 +- drivers/net/ethernet/intel/igb/igb.h | 19 + drivers/net/ethernet/intel/igb/igb_main.c | 10 +- drivers/net/ethernet/intel/igb/igb_tsn.c | 396 ++++++++++++ include/linux/netdevice.h | 32 + include/linux/tsn.h | 806 ++++++++++++++++++++++++ include/trace/events/tsn.h | 349 +++++++++++ net/Kconfig | 1 + net/Makefile | 1 + net/tsn/Kconfig | 32 + net/tsn/Makefile | 6 + net/tsn/tsn_configfs.c | 623 +++++++++++++++++++ net/tsn/tsn_core.c | 975 ++++++++++++++++++++++++++++++ net/tsn/tsn_header.c | 203 +++++++ net/tsn/tsn_internal.h | 383 ++++++++++++ net/tsn/tsn_net.c | 403 ++++++++++++ 24 files changed, 5306 insertions(+), 3 deletions(-) create mode 100644 Documentation/TSN/tsn.txt create mode 100644 drivers/media/avb/Makefile create mode 100644 drivers/media/avb/avb_alsa.c create mode 100644 drivers/media/avb/tsn_iec61883.h create mode 100644 drivers/net/ethernet/intel/igb/igb_tsn.c create mode 100644 include/linux/tsn.h create mode 100644 include/trace/events/tsn.h create mode 100644 net/tsn/Kconfig create mode 100644 net/tsn/Makefile create mode 100644 net/tsn/tsn_configfs.c create mode 100644 net/tsn/tsn_core.c create mode 100644 net/tsn/tsn_header.c create mode 100644 net/tsn/tsn_internal.h create mode 100644 net/tsn/tsn_net.c -- 2.7.4
[toc] | [next] | [standalone]
| From | Henrik Austad <henrik@austad.us> |
|---|---|
| Date | 2016-06-12 01:10 +0200 |
| Subject | [very-RFC 1/8] TSN: add documentation |
| Message-ID | <rJ0cp-QL-13@gated-at.bofh.it> |
| In reply to | #1420097 |
From: Henrik Austad <haustad@cisco.com> Describe the overall design behind the TSN standard, the TSN-driver, requirements to userspace and new functionality introduced. Cc: "David S. Miller" <davem@davemloft.net> Signed-off-by: Henrik Austad <haustad@cisco.com> --- Documentation/TSN/tsn.txt | 147 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 Documentation/TSN/tsn.txt Index: linux/Documentation/TSN/tsn.txt =================================================================== --- /dev/null +++ linux/Documentation/TSN/tsn.txt @@ -0,0 +1,188 @@ + Time Sensitive Networking (TSN) + ------------------------------- + +[work in progress] + +1. Motivation +============= + +TSN is a set of open standards, formerly known as 'AVB' (Audio/Video +Bridging). It was renamed to TSN to better reflect that it can do much +more than just media transport. + +TSN is a way to create reliable streams across a network without loss of +frames due to congestion in the network. By using gPTP (a specialized +IEEE-1588v2 PTP profile), the time can be synchronized with sub-us +granularity across all the connected devices in the AVB domain. + +2. Intro to AVB/TSN +=================== + +The original standards were written with Audio/Video in mind, so the +initial standards refer to this as 'AVB'. In later standards, this has +changed to TSN, and AVB now refers to a service you can add on top of +TSN. Hopefully it will not be too confusing. + +In this document, we refer to the infrastructure part as TSN and AVB to +the ALSA/V4L2 shim which can be added on top of TSN to provide a +media-service. + +TSN operates with 'streams', and one stream can contain pretty much +whatever you like. Currently, only media has been defined properly +though, which is why you only have media-subtypes for the +avtp_subtype-field. + +For a media-setup, one stream can contain multiple channels, all going +to the same destination. A destination can be a single Listener +(singlecast) or a group of Listeners (multicast). + +2.1 Endpoints + +A TSN 'endpoint' is where a stream either originates or ends -what +others would call sources (Talkers) and sinks (Listeners). Looking back +at pre-TSN when this was called AVB, these names make a bit more sense. + +Common for both types, they need to be PTPv2 capable, i.e. you need to +timestamp gPTP frames upon ingress/egress to improve the accuracy of +PTP. + +2.1.1 Talkers + +Hardware requirements: +- Multiple Tx-queues +- Credit based shaper on at least one of the queues for pacing the + frames onto the network +- VLAN capable + +2.1.2 Listener + +A Listener does not have the same requirements as a Talker as it cannot +control the pace of the incoming frames anyway. It is beneficial if the +NIC understands VLANs and has a few Rx-queues so that you can steer all +TSN-frames to a dedicated queue. + +2.2 Bridges + +What TSN calls switches that are TSN-capable. They must be able to +prioritize TSN-streams, have the credit-based shaper available for that +class, support SRP, support gPTP and so on. + +2.3 Relevant standards + +* IEEE 802.1BA-2011 Audio Video Bridging (AVB) Systems + +* IEEE 802.1Q-2011 sec 34 and 35 + + What is referred to as: + IEEE 802.1Qav (Forwarding and Queueing for Time-sensitive Streams) + IEEE 802.1Qat (Stream Registration protocol) + +* IEEE 802.1AS gPTP + + A PTPv2 profile (from IEEE 1588) tailored for this domain. Notable + changes include the requirement that all nodes in the network must be + gPTP capable (i.e. no traversing non-PTP entities), and it allows + traffic over a wider range of medium that what "pure" PTPv2 allows. + +* IEEE 1722 AVTP Layer 2 Transport Protocol for Time-Sensitive + Applications in Bridged Local Area Networks + +* IEEE 1722.1 Device Discovery, Connection Management and Control for 1722 + + What allows AVB (TSN) devices to handle discovery, enumeration and + control, basically let you connect 2 devices from a 3rd + + In this (in the scope of the Linux kernel TSN driver) must be done + purely from userspace as we do not want the kernel to suddenly attach + to a remote system without the user's knowledge. This is further + reflected in how the attributes for the link is managed via ConfigFS. + + +3. Overview and/or design of the TSN-driver +=========================================== + +The driver handles the shifting of data for TSN-streams. Anything else +is left for userspace to handle. This includes stream reservation (using +some sort of MSRP client), negotiating multicast addresses, finding the +value of the different attributes and connect application(s) to the +exposed devices (currently we only have an ALSA-device). + + /--------------------\ + | | + | Media application | + | | + \--------------------/ + | | + +----------+ +----+ + | | + | | + +------------+ | + | ALSA | | + +------------+ | + | | + | | + +------------+ +--------------+ + | avb_alsa | | tsn_configfs | + | (tsn-shim) | +--------------+ + +------------+ | + | | + | | + +------+ | + | | + | | + +------------+ | + | tsn_core |<--------+ + +------------+ + | + | + +------------+ + | tsn_net | + +------------+ + | + | + +------------+ + | network | + | subsystem | + +------------+ + | + | + ... + + +3.1 Terms and concepts + +TSN uses the concept of streams and shims. + +- A shim is a thin wrapper that binds TSN to another subsystem (or + directly to userspace). avb_alsa is an example of such a shim. + +- A stream is the only data TSN cares about. What the data inside the + stream represents, is left for the associated shim to handle. TSN will + verify the headers up to the protocol specific header and then pass it + along to the shim. + +Note: currently, only the data-unit part is implemented, the control +part, in which 1722.1 (discovery and enumeration) is part, is not +handled. + +3.2 Userspace requirements + +(msrp-client, "tsnctl"-tool + +4. Creating a new link from userspace +===================================== + +[coming] + + +5. Creating a new shim +====================== + +shim_ops +[coming] + + +6. Other resources: +=================== + +https://en.wikipedia.org/wiki/Audio_Video_Bridging
[toc] | [prev] | [next] | [standalone]
| From | Henrik Austad <henrik@austad.us> |
|---|---|
| Date | 2016-06-12 01:10 +0200 |
| Subject | [very-RFC 3/8] Adding TSN-driver to Intel I210 controller |
| Message-ID | <rJ0cq-QL-19@gated-at.bofh.it> |
| In reply to | #1420097 |
This adds support for loading the igb.ko module with tsn
capabilities. This requires a 2-step approach. First enabling TSN in
.config, then load the module with use_tsn=1.
Once enabled and loaded, the controller will be placed in "Qav-mode"
which is when the credit-based shaper is available, 3 of the queues are
removed from regular traffic, max payload is set to 1522 octets (no
jumboframes allowed).
It dumps the registers of interest before and after, so this clutters
kern.log a bit. In time this will be reduced / tied to the debug-param
for the module.
Note: currently this driver is *not* stable, it is still a work in
progress.
Cc: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Cc: intel-wired-lan@lists.osuosl.org
Cc: "David S. Miller" <davem@davemloft.net>
Signed-off-by: Henrik Austad <haustad@cisco.com>
---
drivers/net/ethernet/intel/Kconfig | 18 ++
drivers/net/ethernet/intel/igb/Makefile | 2 +-
drivers/net/ethernet/intel/igb/igb.h | 19 ++
drivers/net/ethernet/intel/igb/igb_main.c | 10 +-
drivers/net/ethernet/intel/igb/igb_tsn.c | 396 ++++++++++++++++++++++++++++++
5 files changed, 443 insertions(+), 2 deletions(-)
create mode 100644 drivers/net/ethernet/intel/igb/igb_tsn.c
diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig
index 714bd10..8e620a9 100644
--- a/drivers/net/ethernet/intel/Kconfig
+++ b/drivers/net/ethernet/intel/Kconfig
@@ -99,6 +99,24 @@ config IGB
To compile this driver as a module, choose M here. The module
will be called igb.
+config IGB_TSN
+ tristate "TSN Support for Intel(R) 82575/82576 i210 Network Controller"
+ depends on IGB && TSN
+ ---help---
+ This driver supports TSN (AVB) on Intel I210 network controllers.
+
+ When enabled, it will allow the module to be loaded with
+ "use_tsn" which will initialize the controller to A/V-mode
+ instead of legacy-mode. This will take 3 of the tx-queues and
+ place them in 802.1Q QoS mode and enable the credit-based
+ shaper for 2 of the queues.
+
+ If built with this option, but not loaded with use_tsn, the
+ only difference is a slightly larger module, no extra
+ code paths are called.
+
+ If unsure, say No
+
config IGB_HWMON
bool "Intel(R) PCI-Express Gigabit adapters HWMON support"
default y
diff --git a/drivers/net/ethernet/intel/igb/Makefile b/drivers/net/ethernet/intel/igb/Makefile
index 5bcb2de..1a9b776 100644
--- a/drivers/net/ethernet/intel/igb/Makefile
+++ b/drivers/net/ethernet/intel/igb/Makefile
@@ -33,4 +33,4 @@ obj-$(CONFIG_IGB) += igb.o
igb-objs := igb_main.o igb_ethtool.o e1000_82575.o \
e1000_mac.o e1000_nvm.o e1000_phy.o e1000_mbx.o \
- e1000_i210.o igb_ptp.o igb_hwmon.o
+ e1000_i210.o igb_ptp.o igb_hwmon.o igb_tsn.o
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index b9609af..708f705 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -356,6 +356,7 @@ struct hwmon_buff {
#define IGB_RETA_SIZE 128
/* board specific private data structure */
+
struct igb_adapter {
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
@@ -472,6 +473,13 @@ struct igb_adapter {
int copper_tries;
struct e1000_info ei;
u16 eee_advert;
+
+#if IS_ENABLED(CONFIG_IGB_TSN)
+ /* Reserved BW for class A and B */
+ u16 sra_idleslope_res;
+ u16 srb_idleslope_res;
+ u8 tsn_ready:1;
+#endif /* IGB_TSN */
};
#define IGB_FLAG_HAS_MSI BIT(0)
@@ -552,6 +560,17 @@ void igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector, unsigned char *va,
struct sk_buff *skb);
int igb_ptp_set_ts_config(struct net_device *netdev, struct ifreq *ifr);
int igb_ptp_get_ts_config(struct net_device *netdev, struct ifreq *ifr);
+/* This should be the only place where we add ifdeffery
+ * to include tsn-stuff or not. Everything else is located in igb_tsn.c
+ */
+#if IS_ENABLED(CONFIG_IGB_TSN)
+void igb_tsn_init(struct igb_adapter *adapter);
+int igb_tsn_capable(struct net_device *netdev);
+int igb_tsn_link_configure(struct net_device *netdev, enum sr_class sr_class,
+ u16 framesize, u16 vid);
+#else
+static inline void igb_tsn_init(struct igb_adapter *adapter) { }
+#endif /* CONFIG_IGB_TSN */
void igb_set_flag_queue_pairs(struct igb_adapter *, const u32);
#ifdef CONFIG_IGB_HWMON
void igb_sysfs_exit(struct igb_adapter *adapter);
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index ef3d642..4d8789f 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -2142,6 +2142,10 @@ static const struct net_device_ops igb_netdev_ops = {
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = igb_netpoll,
#endif
+#if IS_ENABLED(CONFIG_IGB_TSN)
+ .ndo_tsn_capable = igb_tsn_capable,
+ .ndo_tsn_link_configure = igb_tsn_link_configure,
+#endif /* CONFIG_IGB_TSN */
.ndo_fix_features = igb_fix_features,
.ndo_set_features = igb_set_features,
.ndo_fdb_add = igb_ndo_fdb_add,
@@ -2665,6 +2669,8 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* do hw tstamp init after resetting */
igb_ptp_init(adapter);
+ igb_tsn_init(adapter);
+
dev_info(&pdev->dev, "Intel(R) Gigabit Ethernet Network Connection\n");
/* print bus type/speed/width info, not applicable to i354 */
if (hw->mac.type != e1000_i354) {
@@ -5323,8 +5329,10 @@ static netdev_tx_t igb_xmit_frame(struct sk_buff *skb,
/* The minimum packet size with TCTL.PSP set is 17 so pad the skb
* in order to meet this minimum size requirement.
*/
- if (skb_put_padto(skb, 17))
+ if (skb_put_padto(skb, 17)) {
+ pr_err("%s: skb_put_padto FAILED. skb->len < 17\n", __func__);
return NETDEV_TX_OK;
+ }
return igb_xmit_frame_ring(skb, igb_tx_queue_mapping(adapter, skb));
}
diff --git a/drivers/net/ethernet/intel/igb/igb_tsn.c b/drivers/net/ethernet/intel/igb/igb_tsn.c
new file mode 100644
index 0000000..641f4f2
--- /dev/null
+++ b/drivers/net/ethernet/intel/igb/igb_tsn.c
@@ -0,0 +1,396 @@
+/*
+ * Copyright(c) 2015-2016 Henrik Austad <haustad@cisco.com>
+ * Cisco Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+/* FIXME: This should probably be handled by some Makefile-magic */
+
+#if IS_ENABLED(CONFIG_IGB_TSN)
+#include "igb.h"
+#include <linux/module.h>
+
+/* NOTE: keep the defines not present in e1000_regs.h to avoid
+ * cluttering too many files. Once we are pretty stable, these will move
+ * into it's proper home. Until then, make merge a bit easier by
+ * avoiding it
+ */
+
+/* Qav regs */
+#define E1000_IRPBS 0x02404 /* Rx Packet Buffer Size - RW */
+#define E1000_ITPBS 0x03404 /* Tx buffer size assignment */
+#define E1000_TQAVCTRL 0x03570 /* Tx Qav Control */
+#define E1000_DTXMXPKTSZ 0x0355C /* DMA TX Maximum Packet Size */
+
+/* Qav defines. */
+#define E1000_TQAVCH_ZERO_CREDIT 0x80000000
+#define E1000_LINK_RATE 0x7735
+
+/* queue mode, 0=strict, 1=SR mode */
+#define E1000_TQAVCC_QUEUEMODE 0x80000000
+/* Transmit mode, 0=legacy, 1=QAV */
+#define E1000_TQAVCTRL_TXMODE 0x00000001
+/* report DMA time of tx packets */
+#define E1000_TQAVCTRL_1588_STAT_EN 0x00000004
+/* data fetch arbitration */
+#define E1000_TQAVCTRL_DATA_FETCH_ARB 0x00000010
+/* data tx arbitration */
+#define E1000_TQAVCTRL_DATA_TRAN_ARB 0x00000100
+/* data launch time valid */
+#define E1000_TQAVCTRL_DATA_TRAN_TIM 0x00000200
+/* stall SP to guarantee SR */
+#define E1000_TQAVCTRL_SP_WAIT_SR 0x00000400
+
+/* ... and associated shift value */
+#define E1000_TQAVCTRL_FETCH_TM_SHIFT (16)
+
+/* QAV Tx mode control registers where _n can be 0 or 1. */
+#define E1000_TQAVCC(_idx) (0x03004 + 0x40 * (_idx))
+
+/* Tx Qav High Credit - See 7.2.7.6 for calculations
+ * intel 8.12.18
+ */
+#define E1000_TQAVHC(_idx) (0x0300C + 0x40 * (_idx))
+
+/* Queues priority masks where _n and _p can be 0-3. */
+
+#define MAX_FRAME_SIZE 1522
+#define MIN_FRAME_SIZE 64
+
+static int use_tsn = -1;
+static int debug_tsn = -1;
+module_param(use_tsn, int, 0);
+module_param(debug_tsn, int, 0);
+MODULE_PARM_DESC(use_tsn, "use_tsn (0=off, 1=enabled)");
+MODULE_PARM_DESC(debug_tsn, "debug_tsn (0=off, 1=enabled)");
+
+/* For a full list of the registers dumped here, see sec 8.1.3 in the
+ * i210 controller datasheet.
+ */
+static inline void _tsn_dump_regs(struct igb_adapter *adapter)
+{
+ u32 val = 0;
+ struct device *dev;
+ struct e1000_hw *hw = &adapter->hw;
+
+ /* do not dump regs if we're not debugging driver */
+ if (debug_tsn != 1)
+ return;
+
+ dev = &adapter->pdev->dev;
+ dev_info(dev, "num_tx_queues=%d, num_rx_queues=%d\n",
+ adapter->num_tx_queues, adapter->num_rx_queues);
+
+ /* 0x0008 - E1000_STATUS Device status register */
+ val = rd32(E1000_STATUS);
+ dev_info(&adapter->pdev->dev, "\n");
+ dev_info(dev, "Status: FullDuplex=%s, LinkUp=%s, speed=%0x01x\n",
+ val & 0x1 ? "FD" : "HD",
+ val & 0x2 ? "LU" : "LD",
+ val & 0xc0 >> 6);
+
+ /* E1000_VET vlan ether type */
+ val = rd32(E1000_VET);
+ dev_info(dev, "VLAN ether type: VET.VET=0x%04x, VET.VET_EXT=0x%04x\n",
+ val & 0xffff, (val >> 16) & 0xffff);
+
+ /* E1000_RXPBS (RXPBSIZE) Rx Packet Buffer Size */
+ val = rd32(E1000_RXPBS);
+ dev_info(dev, "Rx Packet buffer: RXPBSIZE=%dkB, Bmc2ospbsize=%dkB, cfg_ts_en=%s\n",
+ val & 0x1f,
+ (val >> 6) & 0x1f,
+ (val & (1 << 31)) ? "cfg_ts_en" : "cfg_ts_dis");
+
+ /* Transmit stuff */
+ /* E1000_TXPBS (TXPBSIZE) Tx Packet Buffer Size - RW */
+ val = rd32(E1000_TXPBS);
+ dev_info(dev, "Tx Packet buffer: Txpb0size=%dkB, Txpb1size=%dkB, Txpb2size=%dkB, Txpb3size=%dkB, os2Bmcpbsize=%dkB\n",
+ val & 0x3f, (val >> 6) & 0x3f, (val >> 12) & 0x3f,
+ (val >> 18) & 0x3f, (val >> 24) & 0x3f);
+
+ /* E1000_TCTL (TCTL) Tx control - RW*/
+ val = rd32(E1000_TCTL);
+ dev_info(dev, "Tx control reg: TxEnable=%s, CT=0x%X\n",
+ val & 2 ? "EN" : "DIS", (val >> 3) & 0x3F);
+
+ /* TQAVHC : Transmit Qav High credits 0x300C + 0x40*n - RW */
+ val = rd32(E1000_TQAVHC(0));
+ dev_info(dev, "E1000_TQAVHC0: %0x08x\n", val);
+ val = rd32(E1000_TQAVHC(1));
+ dev_info(dev, "E1000_TQAVHC1: %0x08x\n", val);
+
+ /* TQAVCC[0-1]: Transmit Qav 0x3004 + 0x40*n - RW */
+ val = rd32(E1000_TQAVCC(0));
+ dev_info(dev, "E1000_TQAVCC0: idleSlope=%02x, QueueMode=%s\n",
+ val % 0xff,
+ val > 31 ? "Stream reservation" : "Strict priority");
+ val = rd32(E1000_TQAVCC(1));
+ dev_info(dev, "E1000_TQAVCC1: idleSlope=%02x, QueueMode=%s\n",
+ val % 0xff,
+ val > 31 ? "Stream reservation" : "Strict priority");
+
+ /* TQAVCTRL : Transmit Qav control - RW */
+ val = rd32(E1000_TQAVCTRL);
+ dev_info(dev, "E1000_TQAVCTRL: TransmitMode=%s,1588_STAT_EN=%s,DataFetchARB=%s,DataTranARB=%s,DataTranTIM=%s,SP_WAIT_SR=%s,FetchTimDelta=%dns (0x%04x)\n",
+ (val & 0x0001) ? "Qav" : "Legacy",
+ (val & 0x0004) ? "En" : "Dis",
+ (val & 0x0010) ? "Most Empty" : "Round Robin",
+ (val & 0x0100) ? "Credit Shaper" : "Strict priority",
+ (val & 0x0200) ? "Valid" : "N/A",
+ (val & 0x0400) ? "Wait" : "nowait",
+ (val >> 16) * 32, (val >> 16));
+}
+
+/* Place the NIC in Qav-mode.
+ *
+ * This will result in a _single_ queue for normal BE traffic, the rest
+ * will be grabbed by the Qav-machinery and kept for strict priority
+ * transmission.
+ *
+ * I210 Datasheet Sec 7.2.7.7 gives a lot of information.
+ */
+void igb_tsn_init(struct igb_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u32 val;
+
+ if (use_tsn != 1) {
+ adapter->tsn_ready = 0;
+ dev_info(&adapter->pdev->dev, "%s got use_tsn > 0 (%d)\n",
+ __func__, use_tsn);
+ return;
+ }
+
+ if (debug_tsn < 0 || debug_tsn > 1)
+ debug_tsn = 0;
+
+ if (!adapter->pdev) {
+ adapter->tsn_ready = 0;
+ return;
+ }
+
+ switch (adapter->pdev->device) {
+ case 0x1533: /* E1000_DEV_ID_I210_COPPER */
+ case 0x1536: /* E1000_DEV_ID_I210_FIBER */
+ case 0x1537: /* E1000_DEV_ID_I210_SERDES: */
+ case 0x1538: /* E1000_DEV_ID_I210_SGMII: */
+ case 0x157b: /* E1000_DEV_ID_I210_COPPER_FLASHLESS: */
+ case 0x157c: /* E1000_DEV_ID_I210_SERDES_FLASHLESS: */
+ break;
+ default:
+ /* not a known IGB-TSN capable device */
+ adapter->tsn_ready = 0;
+ return;
+ }
+ _tsn_dump_regs(adapter);
+
+ /* Set Tx packet buffer size assignment, see 7.2.7.7 in i210
+ * PB0: 8kB
+ * PB1: 8kB
+ * PB2: 4kB
+ * PB3: 4kB
+ * os2bmcsize: 2kB
+ * sumTx: 26kB
+ *
+ * Rxpbsize: 0x20 (32kB)
+ * bmc2ossize: 0x02
+ * sumRx: 34kB
+ *
+ * See 8.3.1 && 8.3.2
+ */
+ val = (0x02 << 24 | 0x04 << 18 | 0x04 << 12 | 0x08 << 6 | 0x08);
+ wr32(E1000_ITPBS, val);
+ wr32(E1000_IRPBS, (0x02 << 6 | 0x20));
+
+ /* DMA Tx maximum packet size, the largest frame DMA should transport
+ * do not allow frames larger than 1522 + preample. Reg expects
+ * size in 64B increments. 802.1BA 6.3
+ * Round up to 1536 to handle 64B increments
+ *
+ * Initial value: 0x98 (152 => 9728 bytes)
+ */
+ wr32(E1000_DTXMXPKTSZ, 1536 >> 6);
+
+ /* Place card in Qav-mode, use tx-queue 0,1 for Qav
+ * (Credit-based shaper), 2,3 for standard priority (and
+ * best-effort) traffic.
+ *
+ * i210 8.12.19 and 8.12.21
+ *
+ * - Fetch: most empty and time based (not round-robin)
+ * - Transmit: Credit based shaper for SR queues
+ * - Data launch time valid (in Qav mode)
+ * - Wait for SR queues to ensure that launch time is always valid.
+ * - Set ~10us wait-time-delta, 32ns granularity
+ *
+ * Do *not* enable Tx for shaper (E1000_TQAVCTRL_DATA_TRAN_ARB)
+ * yet as we do not have data to Tx
+ */
+ val = E1000_TQAVCTRL_TXMODE |
+ E1000_TQAVCTRL_DATA_FETCH_ARB |
+ E1000_TQAVCTRL_DATA_TRAN_TIM |
+ E1000_TQAVCTRL_SP_WAIT_SR |
+ 320 << E1000_TQAVCTRL_FETCH_TM_SHIFT;
+
+ wr32(E1000_TQAVCTRL, val);
+
+ /* For now, only set CreditBased shaper for A and B, not set
+ * idleSlope as we have not yet gotten any streams.
+ * 8.12.19
+ */
+ wr32(E1000_TQAVCC(0), E1000_TQAVCC_QUEUEMODE);
+ wr32(E1000_TQAVCC(1), E1000_TQAVCC_QUEUEMODE);
+
+ wr32(E1000_TQAVHC(0), E1000_TQAVCH_ZERO_CREDIT);
+ wr32(E1000_TQAVHC(1), E1000_TQAVCH_ZERO_CREDIT);
+
+ /* reset Tx Descriptor tail and head for the queues */
+ wr32(E1000_TDT(0), 0);
+ wr32(E1000_TDT(1), 0);
+ wr32(E1000_TDH(0), 0);
+ wr32(E1000_TDH(1), 0);
+
+ _tsn_dump_regs(adapter);
+ dev_info(&adapter->pdev->dev, "\n");
+
+ adapter->sra_idleslope_res = 0;
+ adapter->srb_idleslope_res = 0;
+ adapter->tsn_ready = 1;
+
+ dev_info(&adapter->pdev->dev, "%s: setup done\n", __func__);
+}
+
+int igb_tsn_capable(struct net_device *netdev)
+{
+ struct igb_adapter *adapter;
+
+ if (!netdev)
+ return -EINVAL;
+ adapter = netdev_priv(netdev);
+ if (use_tsn == 1)
+ return adapter->tsn_ready == 1;
+ return 0;
+}
+
+/* igb_tsn_link_configure - configure NIC to handle a new stream
+ *
+ * @netdev: pointer to NIC device
+ * @class: the class for the stream used to find the correct queue.
+ * @framesize: size of each frame, *including* headers (not preamble)
+ * @vid: VLAN ID
+ *
+ * NOTE: the sr_class only instructs the driver which queue to use, not
+ * what priority the network expects for a given class. This is
+ * something userspace must find out and then let the tsn-driver set in
+ * the frame before xmit.
+ *
+ * FIXME: remove bw-req from a stream that goes away.
+ */
+int igb_tsn_link_configure(struct net_device *netdev, enum sr_class class,
+ u16 framesize, u16 vid)
+{
+ /* FIXME: push into adapter-storage */
+ static int class_a_size;
+ static int class_b_size;
+ int err;
+ u32 idle_slope_a = 0;
+ u32 idle_slope_b = 0;
+ u32 new_is = 0;
+ u32 hicred_a = 0;
+ u32 hicred_b = 0;
+ u32 tqavctrl;
+
+ struct igb_adapter *adapter;
+ struct e1000_hw *hw;
+
+ if (!netdev)
+ return -EINVAL;
+ adapter = netdev_priv(netdev);
+ hw = &adapter->hw;
+
+ if (!igb_tsn_capable(netdev)) {
+ pr_err("%s: NIC not capable\n", __func__);
+ return -EINVAL;
+ }
+
+ if (framesize > MAX_FRAME_SIZE || framesize < MIN_FRAME_SIZE) {
+ pr_err("%s: framesize (%u) must be [%d,%d]\n", __func__,
+ framesize, MIN_FRAME_SIZE, MAX_FRAME_SIZE);
+ return -EINVAL;
+ }
+
+ /* TODO: is this the correct place/way? Is it required? */
+ rtnl_lock();
+ pr_info("%s: adding VLAN %u to HW filter on device %s\n",
+ __func__, vid, netdev->name);
+ err = vlan_vid_add(netdev, htons(ETH_P_8021Q), vid);
+ if (err != 0)
+ pr_err("%s: error adding vlan %u, res=%d\n",
+ __func__, vid, err);
+ rtnl_unlock();
+
+ /* Grab current values of idle_slope */
+ idle_slope_a = rd32(E1000_TQAVHC(0)) & ~E1000_TQAVCH_ZERO_CREDIT;
+ idle_slope_b = rd32(E1000_TQAVHC(1)) & ~E1000_TQAVCH_ZERO_CREDIT;
+
+ /* Calculate new idle slope and add to appropriate idle_slope
+ * idle_slope = BW * linkrate * 2 (0r 0.2 for 100Mbit)
+ * BW: % of total bandwidth
+ */
+ new_is = framesize * E1000_LINK_RATE * 16 / 1000000;
+
+ switch (class) {
+ case SR_CLASS_A:
+ new_is *= 2; /* A is 8kHz, B is 4kHz */
+ idle_slope_a += new_is;
+ class_a_size = framesize;
+ break;
+ case SR_CLASS_B:
+ idle_slope_b += new_is;
+ class_b_size = framesize;
+ break;
+ default:
+ pr_err("%s: unhandled SR-class (%d)\n", __func__, class);
+ return -EINVAL;
+ }
+
+ /* HiCred: cred obtained while waiting for current frame &&
+ * higher-class frames to finish xmit.
+ *
+ * Covered in detail in 7.2.7.6 in i210 datasheet
+ * For class A: only worst-case framesize that just started;
+ * i.e. 1522 * idleSlope / linkrate;
+ * For class B: (worst-case framesize + burstSize(A))*idleSlope
+ *
+ * See 802.1Q Annex L, eq L.10 for hicred_a and L.41 for
+ * hicred_b
+ */
+ if (class == SR_CLASS_A) {
+ hicred_a = E1000_TQAVCH_ZERO_CREDIT + idle_slope_a * MAX_FRAME_SIZE / E1000_LINK_RATE;
+ wr32(E1000_TQAVCC(0), E1000_TQAVCC_QUEUEMODE | idle_slope_a);
+ wr32(E1000_TQAVHC(0), hicred_a);
+ } else {
+ hicred_b = E1000_TQAVCH_ZERO_CREDIT | idle_slope_b * (MAX_FRAME_SIZE + class_a_size) / (E1000_LINK_RATE - idle_slope_a);
+ wr32(E1000_TQAVCC(1), E1000_TQAVCC_QUEUEMODE | idle_slope_b);
+ wr32(E1000_TQAVHC(1), hicred_b);
+ }
+
+ /* Enable Tx for shaper now that we have data */
+ tqavctrl = rd32(E1000_TQAVCTRL);
+ if (!(tqavctrl & E1000_TQAVCTRL_DATA_TRAN_ARB)) {
+ tqavctrl |= E1000_TQAVCTRL_DATA_TRAN_ARB;
+ wr32(E1000_TQAVCTRL, tqavctrl);
+ }
+ _tsn_dump_regs(netdev_priv(netdev));
+ return 0;
+}
+
+#endif /* #if IS_ENABLED(CONFIG_IGB_TSN) */
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Henrik Austad <henrik@austad.us> |
|---|---|
| Date | 2016-06-12 01:10 +0200 |
| Subject | [very-RFC 6/8] Add TSN event-tracing |
| Message-ID | <rJ0cq-QL-21@gated-at.bofh.it> |
| In reply to | #1420097 |
From: Henrik Austad <haustad@cisco.com>
This needs refactoring and should be updated to use TRACE_CLASS, but for
now it provides a fair debug-window into TSN.
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Steven Rostedt <rostedt@goodmis.org> (maintainer:TRACING)
Cc: Ingo Molnar <mingo@redhat.com> (maintainer:TRACING)
Signed-off-by: Henrik Austad <haustad@cisco.com>
---
include/trace/events/tsn.h | 349 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 349 insertions(+)
create mode 100644 include/trace/events/tsn.h
diff --git a/include/trace/events/tsn.h b/include/trace/events/tsn.h
new file mode 100644
index 0000000..ac1f31b
--- /dev/null
+++ b/include/trace/events/tsn.h
@@ -0,0 +1,349 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM tsn
+
+#if !defined(_TRACE_TSN_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_TSN_H
+
+#include <linux/tsn.h>
+#include <linux/tracepoint.h>
+
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+/* #include <linux/skbuff.h> */
+
+/* FIXME: update to TRACE_CLASS to reduce overhead */
+TRACE_EVENT(tsn_buffer_write,
+
+ TP_PROTO(struct tsn_link *link,
+ size_t bytes),
+
+ TP_ARGS(link, bytes),
+
+ TP_STRUCT__entry(
+ __field(u64, stream_id)
+ __field(size_t, size)
+ __field(size_t, bsize)
+ __field(size_t, size_left)
+ __field(void *, buffer)
+ __field(void *, head)
+ __field(void *, tail)
+ __field(void *, end)
+ ),
+
+ TP_fast_assign(
+ __entry->stream_id = link->stream_id;
+ __entry->size = bytes;
+ __entry->bsize = link->used_buffer_size;
+ __entry->size_left = (link->head - link->tail) % link->used_buffer_size;
+ __entry->buffer = link->buffer;
+ __entry->head = link->head;
+ __entry->tail = link->tail;
+ __entry->end = link->end;
+ ),
+
+ TP_printk("stream_id=%llu, copy=%zd, buffer: %zd, avail=%zd, [buffer=%p, head=%p, tail=%p, end=%p]",
+ __entry->stream_id, __entry->size, __entry->bsize, __entry->size_left,
+ __entry->buffer, __entry->head, __entry->tail, __entry->end)
+
+ );
+
+TRACE_EVENT(tsn_buffer_write_net,
+
+ TP_PROTO(struct tsn_link *link,
+ size_t bytes),
+
+ TP_ARGS(link, bytes),
+
+ TP_STRUCT__entry(
+ __field(u64, stream_id)
+ __field(size_t, size)
+ __field(size_t, bsize)
+ __field(size_t, size_left)
+ __field(void *, buffer)
+ __field(void *, head)
+ __field(void *, tail)
+ __field(void *, end)
+ ),
+
+ TP_fast_assign(
+ __entry->stream_id = link->stream_id;
+ __entry->size = bytes;
+ __entry->bsize = link->used_buffer_size;
+ __entry->size_left = (link->head - link->tail) % link->used_buffer_size;
+ __entry->buffer = link->buffer;
+ __entry->head = link->head;
+ __entry->tail = link->tail;
+ __entry->end = link->end;
+ ),
+
+ TP_printk("stream_id=%llu, copy=%zd, buffer: %zd, avail=%zd, [buffer=%p, head=%p, tail=%p, end=%p]",
+ __entry->stream_id, __entry->size, __entry->bsize, __entry->size_left,
+ __entry->buffer, __entry->head, __entry->tail, __entry->end)
+
+ );
+
+
+TRACE_EVENT(tsn_buffer_read,
+
+ TP_PROTO(struct tsn_link *link,
+ size_t bytes),
+
+ TP_ARGS(link, bytes),
+
+ TP_STRUCT__entry(
+ __field(u64, stream_id)
+ __field(size_t, size)
+ __field(size_t, bsize)
+ __field(size_t, size_left)
+ __field(void *, buffer)
+ __field(void *, head)
+ __field(void *, tail)
+ __field(void *, end)
+ ),
+
+ TP_fast_assign(
+ __entry->stream_id = link->stream_id;
+ __entry->size = bytes;
+ __entry->bsize = link->used_buffer_size;
+ __entry->size_left = (link->head - link->tail) % link->used_buffer_size;
+ __entry->buffer = link->buffer;
+ __entry->head = link->head;
+ __entry->tail = link->tail;
+ __entry->end = link->end;
+ ),
+
+ TP_printk("stream_id=%llu, copy=%zd, buffer: %zd, avail=%zd, [buffer=%p, head=%p, tail=%p, end=%p]",
+ __entry->stream_id, __entry->size, __entry->bsize, __entry->size_left,
+ __entry->buffer, __entry->head, __entry->tail, __entry->end)
+
+ );
+
+TRACE_EVENT(tsn_refill,
+
+ TP_PROTO(struct tsn_link *link,
+ size_t reported_avail),
+
+ TP_ARGS(link, reported_avail),
+
+ TP_STRUCT__entry(
+ __field(u64, stream_id)
+ __field(size_t, bsize)
+ __field(size_t, size_left)
+ __field(size_t, reported_left)
+ __field(size_t, low_water)
+ ),
+
+ TP_fast_assign(
+ __entry->stream_id = link->stream_id;
+ __entry->bsize = link->used_buffer_size;
+ __entry->size_left = (link->head - link->tail) % link->used_buffer_size;
+ __entry->reported_left = reported_avail;
+ __entry->low_water = link->low_water_mark;
+ ),
+
+ TP_printk("stream_id=%llu, buffer=%zd, avail=%zd, reported=%zd, low=%zd",
+ __entry->stream_id, __entry->bsize, __entry->size_left, __entry->reported_left, __entry->low_water)
+ );
+
+TRACE_EVENT(tsn_send_batch,
+
+ TP_PROTO(struct tsn_link *link,
+ int num_send,
+ u64 ts_base_ns,
+ u64 ts_delta_ns),
+
+ TP_ARGS(link, num_send, ts_base_ns, ts_delta_ns),
+
+ TP_STRUCT__entry(
+ __field(u64, stream_id)
+ __field(int, seqnr)
+ __field(int, num_send)
+ __field(u64, ts_base_ns)
+ __field(u64, ts_delta_ns)
+ ),
+
+ TP_fast_assign(
+ __entry->stream_id = link->stream_id;
+ __entry->seqnr = (int)link->last_seqnr;
+ __entry->ts_base_ns = ts_base_ns;
+ __entry->ts_delta_ns = ts_delta_ns;
+ __entry->num_send = num_send;
+ ),
+
+ TP_printk("stream_id=%llu, seqnr=%d, num_send=%d, ts_base_ns=%llu, ts_delta_ns=%llu",
+ __entry->stream_id, __entry->seqnr, __entry->num_send, __entry->ts_base_ns, __entry->ts_delta_ns)
+ );
+
+
+TRACE_EVENT(tsn_rx_handler,
+
+ TP_PROTO(struct tsn_link *link,
+ const struct ethhdr *ethhdr,
+ u64 sid),
+
+ TP_ARGS(link, ethhdr, sid),
+
+ TP_STRUCT__entry(
+ __field(char *, name)
+ __field(u16, proto)
+ __field(u64, sid)
+ __field(u64, link_sid)
+ ),
+ TP_fast_assign(
+ __entry->name = link->nic->name;
+ __entry->proto = ethhdr->h_proto;
+ __entry->sid = sid;
+ __entry->link_sid = link->stream_id;
+ ),
+
+ TP_printk("name=%s, proto: 0x%04x, stream_id=%llu, link->sid=%llu",
+ __entry->name, ntohs(__entry->proto), __entry->sid, __entry->link_sid)
+ );
+
+TRACE_EVENT(tsn_du,
+
+ TP_PROTO(struct tsn_link *link,
+ size_t bytes),
+
+ TP_ARGS(link, bytes),
+
+ TP_STRUCT__entry(
+ __field(u64, link_sid)
+ __field(size_t, bytes)
+ ),
+ TP_fast_assign(
+ __entry->link_sid = link->stream_id;
+ __entry->bytes = bytes;
+ ),
+
+ TP_printk("stream_id=%llu,bytes=%zu",
+ __entry->link_sid, __entry->bytes)
+);
+
+TRACE_EVENT(tsn_set_buffer,
+
+ TP_PROTO(struct tsn_link *link, size_t bufsize),
+
+ TP_ARGS(link, bufsize),
+
+ TP_STRUCT__entry(
+ __field(u64, stream_id)
+ __field(size_t, size)
+ ),
+
+ TP_fast_assign(
+ __entry->stream_id = link->stream_id;
+ __entry->size = bufsize;
+ ),
+
+ TP_printk("stream_id=%llu,buffer_size=%zu",
+ __entry->stream_id, __entry->size)
+
+ );
+
+TRACE_EVENT(tsn_free_buffer,
+
+ TP_PROTO(struct tsn_link *link),
+
+ TP_ARGS(link),
+
+ TP_STRUCT__entry(
+ __field(u64, stream_id)
+ __field(size_t, bufsize)
+ ),
+
+ TP_fast_assign(
+ __entry->stream_id = link->stream_id;
+ __entry->bufsize = link->buffer_size;
+ ),
+
+ TP_printk("stream_id=%llu,size:%zd",
+ __entry->stream_id, __entry->bufsize)
+
+ );
+
+TRACE_EVENT(tsn_buffer_drain,
+
+ TP_PROTO(struct tsn_link *link, size_t used),
+
+ TP_ARGS(link, used),
+
+ TP_STRUCT__entry(
+ __field(u64, stream_id)
+ __field(size_t, used)
+ ),
+
+ TP_fast_assign(
+ __entry->stream_id = link->stream_id;
+ __entry->used = used;
+ ),
+
+ TP_printk("stream_id=%llu,used=%zu",
+ __entry->stream_id, __entry->used)
+
+);
+/* TODO: too long, need cleanup.
+ */
+TRACE_EVENT(tsn_pre_tx,
+
+ TP_PROTO(struct tsn_link *link, struct sk_buff *skb, size_t bytes),
+
+ TP_ARGS(link, skb, bytes),
+
+ TP_STRUCT__entry(
+ __field(u64, stream_id)
+ __field(u32, vlan_tag)
+ __field(size_t, bytes)
+ __field(size_t, data_len)
+ __field(unsigned int, headlen)
+ __field(u16, protocol)
+ __field(u16, prot_native)
+ __field(int, tx_idx)
+ __field(u16, mac_len)
+ __field(u16, hdr_len)
+ __field(u16, vlan_tci)
+ __field(u16, mac_header)
+ __field(unsigned int, tail)
+ __field(unsigned int, end)
+ __field(unsigned int, truesize)
+ ),
+
+ TP_fast_assign(
+ __entry->stream_id = link->stream_id;
+ __entry->vlan_tag = (skb_vlan_tag_present(skb) ? skb_vlan_tag_get(skb) : 0);
+ __entry->bytes = bytes;
+ __entry->data_len = skb->data_len;
+ __entry->headlen = skb_headlen(skb);
+ __entry->protocol = ntohs(vlan_get_protocol(skb));
+ __entry->prot_native = ntohs(skb->protocol);
+ __entry->tx_idx = skb_get_queue_mapping(skb);
+
+ __entry->mac_len = skb->mac_len;
+ __entry->hdr_len = skb->hdr_len;
+ __entry->vlan_tci = skb->vlan_tci;
+ __entry->mac_header = skb->mac_header;
+ __entry->tail = (unsigned int)skb->tail;
+ __entry->end = (unsigned int)skb->end;
+ __entry->truesize = skb->truesize;
+ ),
+
+ TP_printk("stream_id=%llu,vlan_tag=0x%04x,data_size=%zd,data_len=%zd,headlen=%u,proto=0x%04x (0x%04x),tx_idx=%d,mac_len=%u,hdr_len=%u,vlan_tci=0x%02x,mac_header=0x%02x,tail=%u,end=%u,truesize=%u",
+ __entry->stream_id,
+ __entry->vlan_tag,
+ __entry->bytes,
+ __entry->data_len,
+ __entry->headlen,
+ __entry->protocol,
+ __entry->prot_native, __entry->tx_idx,
+ __entry->mac_len,
+ __entry->hdr_len,
+ __entry->vlan_tci,
+ __entry->mac_header,
+ __entry->tail,
+ __entry->end,
+ __entry->truesize)
+ );
+
+#endif /* _TRACE_TSN_H || TRACE_HEADER_MULTI_READ */
+
+#include <trace/define_trace.h>
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Steven Rostedt <rostedt@goodmis.org> |
|---|---|
| Date | 2016-06-12 19:00 +0200 |
| Subject | Re: [very-RFC 6/8] Add TSN event-tracing |
| Message-ID | <rJgTT-2Fc-3@gated-at.bofh.it> |
| In reply to | #1420100 |
On Sun, 12 Jun 2016 01:01:34 +0200
Henrik Austad <henrik@austad.us> wrote:
> From: Henrik Austad <haustad@cisco.com>
>
> This needs refactoring and should be updated to use TRACE_CLASS, but for
> now it provides a fair debug-window into TSN.
>
> Cc: "David S. Miller" <davem@davemloft.net>
> Cc: Steven Rostedt <rostedt@goodmis.org> (maintainer:TRACING)
> Cc: Ingo Molnar <mingo@redhat.com> (maintainer:TRACING)
> Signed-off-by: Henrik Austad <haustad@cisco.com>
> ---
> include/trace/events/tsn.h | 349 +++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 349 insertions(+)
> create mode 100644 include/trace/events/tsn.h
>
> diff --git a/include/trace/events/tsn.h b/include/trace/events/tsn.h
> new file mode 100644
> index 0000000..ac1f31b
> --- /dev/null
> +++ b/include/trace/events/tsn.h
> @@ -0,0 +1,349 @@
> +#undef TRACE_SYSTEM
> +#define TRACE_SYSTEM tsn
> +
> +#if !defined(_TRACE_TSN_H) || defined(TRACE_HEADER_MULTI_READ)
> +#define _TRACE_TSN_H
> +
> +#include <linux/tsn.h>
> +#include <linux/tracepoint.h>
> +
> +#include <linux/if_ether.h>
> +#include <linux/if_vlan.h>
> +/* #include <linux/skbuff.h> */
> +
> +/* FIXME: update to TRACE_CLASS to reduce overhead */
I'm curious to why I didn't do this now. A class would make less
duplication of typing too ;-)
> +TRACE_EVENT(tsn_buffer_write,
> +
> + TP_PROTO(struct tsn_link *link,
> + size_t bytes),
> +
> + TP_ARGS(link, bytes),
> +
> + TP_STRUCT__entry(
> + __field(u64, stream_id)
> + __field(size_t, size)
> + __field(size_t, bsize)
> + __field(size_t, size_left)
> + __field(void *, buffer)
> + __field(void *, head)
> + __field(void *, tail)
> + __field(void *, end)
> + ),
> +
> + TP_fast_assign(
> + __entry->stream_id = link->stream_id;
> + __entry->size = bytes;
> + __entry->bsize = link->used_buffer_size;
> + __entry->size_left = (link->head - link->tail) % link->used_buffer_size;
Move this logic into the print statement, since you save head and tail.
> + __entry->buffer = link->buffer;
> + __entry->head = link->head;
> + __entry->tail = link->tail;
> + __entry->end = link->end;
> + ),
> +
> + TP_printk("stream_id=%llu, copy=%zd, buffer: %zd, avail=%zd, [buffer=%p, head=%p, tail=%p, end=%p]",
> + __entry->stream_id, __entry->size, __entry->bsize, __entry->size_left,
__entry->stream_id, __entry->size, __entry->bsize,
(__entry->head - __entry->tail) % __entry->bsize,
> + __entry->buffer, __entry->head, __entry->tail, __entry->end)
> +
> + );
> +
> +TRACE_EVENT(tsn_buffer_write_net,
> +
> + TP_PROTO(struct tsn_link *link,
> + size_t bytes),
> +
> + TP_ARGS(link, bytes),
> +
> + TP_STRUCT__entry(
> + __field(u64, stream_id)
> + __field(size_t, size)
> + __field(size_t, bsize)
> + __field(size_t, size_left)
> + __field(void *, buffer)
> + __field(void *, head)
> + __field(void *, tail)
> + __field(void *, end)
> + ),
> +
> + TP_fast_assign(
> + __entry->stream_id = link->stream_id;
> + __entry->size = bytes;
> + __entry->bsize = link->used_buffer_size;
> + __entry->size_left = (link->head - link->tail) % link->used_buffer_size;
> + __entry->buffer = link->buffer;
> + __entry->head = link->head;
> + __entry->tail = link->tail;
> + __entry->end = link->end;
> + ),
> +
> + TP_printk("stream_id=%llu, copy=%zd, buffer: %zd, avail=%zd, [buffer=%p, head=%p, tail=%p, end=%p]",
> + __entry->stream_id, __entry->size, __entry->bsize, __entry->size_left,
> + __entry->buffer, __entry->head, __entry->tail, __entry->end)
> +
> + );
> +
> +
> +TRACE_EVENT(tsn_buffer_read,
> +
> + TP_PROTO(struct tsn_link *link,
> + size_t bytes),
> +
> + TP_ARGS(link, bytes),
> +
> + TP_STRUCT__entry(
> + __field(u64, stream_id)
> + __field(size_t, size)
> + __field(size_t, bsize)
> + __field(size_t, size_left)
> + __field(void *, buffer)
> + __field(void *, head)
> + __field(void *, tail)
> + __field(void *, end)
> + ),
> +
> + TP_fast_assign(
> + __entry->stream_id = link->stream_id;
> + __entry->size = bytes;
> + __entry->bsize = link->used_buffer_size;
> + __entry->size_left = (link->head - link->tail) % link->used_buffer_size;
> + __entry->buffer = link->buffer;
> + __entry->head = link->head;
> + __entry->tail = link->tail;
> + __entry->end = link->end;
> + ),
> +
> + TP_printk("stream_id=%llu, copy=%zd, buffer: %zd, avail=%zd, [buffer=%p, head=%p, tail=%p, end=%p]",
> + __entry->stream_id, __entry->size, __entry->bsize, __entry->size_left,
> + __entry->buffer, __entry->head, __entry->tail, __entry->end)
> +
> + );
> +
> +TRACE_EVENT(tsn_refill,
> +
> + TP_PROTO(struct tsn_link *link,
> + size_t reported_avail),
> +
> + TP_ARGS(link, reported_avail),
> +
> + TP_STRUCT__entry(
> + __field(u64, stream_id)
> + __field(size_t, bsize)
> + __field(size_t, size_left)
> + __field(size_t, reported_left)
> + __field(size_t, low_water)
> + ),
> +
> + TP_fast_assign(
> + __entry->stream_id = link->stream_id;
> + __entry->bsize = link->used_buffer_size;
> + __entry->size_left = (link->head - link->tail) % link->used_buffer_size;
As you don't save head and tail here, this logic needs to remain.
> + __entry->reported_left = reported_avail;
> + __entry->low_water = link->low_water_mark;
> + ),
> +
> + TP_printk("stream_id=%llu, buffer=%zd, avail=%zd, reported=%zd, low=%zd",
> + __entry->stream_id, __entry->bsize, __entry->size_left, __entry->reported_left, __entry->low_water)
> + );
> +
> +TRACE_EVENT(tsn_send_batch,
> +
> + TP_PROTO(struct tsn_link *link,
> + int num_send,
> + u64 ts_base_ns,
> + u64 ts_delta_ns),
> +
> + TP_ARGS(link, num_send, ts_base_ns, ts_delta_ns),
> +
> + TP_STRUCT__entry(
> + __field(u64, stream_id)
> + __field(int, seqnr)
> + __field(int, num_send)
> + __field(u64, ts_base_ns)
> + __field(u64, ts_delta_ns)
> + ),
> +
> + TP_fast_assign(
> + __entry->stream_id = link->stream_id;
> + __entry->seqnr = (int)link->last_seqnr;
> + __entry->ts_base_ns = ts_base_ns;
> + __entry->ts_delta_ns = ts_delta_ns;
> + __entry->num_send = num_send;
> + ),
> +
> + TP_printk("stream_id=%llu, seqnr=%d, num_send=%d, ts_base_ns=%llu, ts_delta_ns=%llu",
> + __entry->stream_id, __entry->seqnr, __entry->num_send, __entry->ts_base_ns, __entry->ts_delta_ns)
> + );
> +
> +
> +TRACE_EVENT(tsn_rx_handler,
> +
> + TP_PROTO(struct tsn_link *link,
> + const struct ethhdr *ethhdr,
> + u64 sid),
> +
> + TP_ARGS(link, ethhdr, sid),
> +
> + TP_STRUCT__entry(
> + __field(char *, name)
> + __field(u16, proto)
> + __field(u64, sid)
> + __field(u64, link_sid)
> + ),
> + TP_fast_assign(
> + __entry->name = link->nic->name;
> + __entry->proto = ethhdr->h_proto;
> + __entry->sid = sid;
> + __entry->link_sid = link->stream_id;
> + ),
> +
> + TP_printk("name=%s, proto: 0x%04x, stream_id=%llu, link->sid=%llu",
> + __entry->name, ntohs(__entry->proto), __entry->sid, __entry->link_sid)
> + );
> +
> +TRACE_EVENT(tsn_du,
> +
> + TP_PROTO(struct tsn_link *link,
> + size_t bytes),
> +
> + TP_ARGS(link, bytes),
> +
> + TP_STRUCT__entry(
> + __field(u64, link_sid)
> + __field(size_t, bytes)
> + ),
> + TP_fast_assign(
> + __entry->link_sid = link->stream_id;
> + __entry->bytes = bytes;
> + ),
> +
> + TP_printk("stream_id=%llu,bytes=%zu",
> + __entry->link_sid, __entry->bytes)
> +);
> +
> +TRACE_EVENT(tsn_set_buffer,
> +
> + TP_PROTO(struct tsn_link *link, size_t bufsize),
> +
> + TP_ARGS(link, bufsize),
> +
> + TP_STRUCT__entry(
> + __field(u64, stream_id)
> + __field(size_t, size)
> + ),
> +
> + TP_fast_assign(
> + __entry->stream_id = link->stream_id;
> + __entry->size = bufsize;
> + ),
> +
> + TP_printk("stream_id=%llu,buffer_size=%zu",
> + __entry->stream_id, __entry->size)
> +
> + );
> +
> +TRACE_EVENT(tsn_free_buffer,
> +
> + TP_PROTO(struct tsn_link *link),
> +
> + TP_ARGS(link),
> +
> + TP_STRUCT__entry(
> + __field(u64, stream_id)
> + __field(size_t, bufsize)
> + ),
> +
> + TP_fast_assign(
> + __entry->stream_id = link->stream_id;
> + __entry->bufsize = link->buffer_size;
> + ),
> +
> + TP_printk("stream_id=%llu,size:%zd",
> + __entry->stream_id, __entry->bufsize)
> +
> + );
> +
> +TRACE_EVENT(tsn_buffer_drain,
> +
> + TP_PROTO(struct tsn_link *link, size_t used),
> +
> + TP_ARGS(link, used),
> +
> + TP_STRUCT__entry(
> + __field(u64, stream_id)
> + __field(size_t, used)
> + ),
> +
> + TP_fast_assign(
> + __entry->stream_id = link->stream_id;
> + __entry->used = used;
> + ),
> +
> + TP_printk("stream_id=%llu,used=%zu",
> + __entry->stream_id, __entry->used)
> +
> +);
> +/* TODO: too long, need cleanup.
> + */
> +TRACE_EVENT(tsn_pre_tx,
> +
> + TP_PROTO(struct tsn_link *link, struct sk_buff *skb, size_t bytes),
> +
> + TP_ARGS(link, skb, bytes),
> +
> + TP_STRUCT__entry(
> + __field(u64, stream_id)
> + __field(u32, vlan_tag)
> + __field(size_t, bytes)
> + __field(size_t, data_len)
> + __field(unsigned int, headlen)
> + __field(u16, protocol)
> + __field(u16, prot_native)
> + __field(int, tx_idx)
> + __field(u16, mac_len)
> + __field(u16, hdr_len)
> + __field(u16, vlan_tci)
> + __field(u16, mac_header)
> + __field(unsigned int, tail)
> + __field(unsigned int, end)
> + __field(unsigned int, truesize)
> + ),
> +
> + TP_fast_assign(
> + __entry->stream_id = link->stream_id;
> + __entry->vlan_tag = (skb_vlan_tag_present(skb) ? skb_vlan_tag_get(skb) : 0);
> + __entry->bytes = bytes;
> + __entry->data_len = skb->data_len;
> + __entry->headlen = skb_headlen(skb);
> + __entry->protocol = ntohs(vlan_get_protocol(skb));
Maybe it would be better to do the ntohs() in the TP_printk() as well.
> + __entry->prot_native = ntohs(skb->protocol);
here too.
> + __entry->tx_idx = skb_get_queue_mapping(skb);
> +
> + __entry->mac_len = skb->mac_len;
> + __entry->hdr_len = skb->hdr_len;
> + __entry->vlan_tci = skb->vlan_tci;
> + __entry->mac_header = skb->mac_header;
> + __entry->tail = (unsigned int)skb->tail;
> + __entry->end = (unsigned int)skb->end;
> + __entry->truesize = skb->truesize;
> + ),
> +
> + TP_printk("stream_id=%llu,vlan_tag=0x%04x,data_size=%zd,data_len=%zd,headlen=%u,proto=0x%04x (0x%04x),tx_idx=%d,mac_len=%u,hdr_len=%u,vlan_tci=0x%02x,mac_header=0x%02x,tail=%u,end=%u,truesize=%u",
> + __entry->stream_id,
> + __entry->vlan_tag,
> + __entry->bytes,
> + __entry->data_len,
> + __entry->headlen,
> + __entry->protocol,
> + __entry->prot_native, __entry->tx_idx,
> + __entry->mac_len,
> + __entry->hdr_len,
> + __entry->vlan_tci,
> + __entry->mac_header,
Is this an ether mac header? If so we support %M. But as it's defined
as only u16, it doesn't seem like it can be.
-- Steve
> + __entry->tail,
> + __entry->end,
> + __entry->truesize)
> + );
> +
> +#endif /* _TRACE_TSN_H || TRACE_HEADER_MULTI_READ */
> +
> +#include <trace/define_trace.h>
[toc] | [prev] | [next] | [standalone]
| From | Henrik Austad <henrik@austad.us> |
|---|---|
| Date | 2016-06-12 23:30 +0200 |
| Subject | Re: [very-RFC 6/8] Add TSN event-tracing |
| Message-ID | <rJl7b-5ms-9@gated-at.bofh.it> |
| In reply to | #1420298 |
[Multipart message — attachments visible in raw view] — view raw
On Sun, Jun 12, 2016 at 12:58:03PM -0400, Steven Rostedt wrote:
> On Sun, 12 Jun 2016 01:01:34 +0200
> Henrik Austad <henrik@austad.us> wrote:
>
> > From: Henrik Austad <haustad@cisco.com>
> >
> > This needs refactoring and should be updated to use TRACE_CLASS, but for
> > now it provides a fair debug-window into TSN.
> >
> > Cc: "David S. Miller" <davem@davemloft.net>
> > Cc: Steven Rostedt <rostedt@goodmis.org> (maintainer:TRACING)
> > Cc: Ingo Molnar <mingo@redhat.com> (maintainer:TRACING)
> > Signed-off-by: Henrik Austad <haustad@cisco.com>
> > ---
> > include/trace/events/tsn.h | 349 +++++++++++++++++++++++++++++++++++++++++++++
> > 1 file changed, 349 insertions(+)
> > create mode 100644 include/trace/events/tsn.h
> >
> > diff --git a/include/trace/events/tsn.h b/include/trace/events/tsn.h
> > new file mode 100644
> > index 0000000..ac1f31b
> > --- /dev/null
> > +++ b/include/trace/events/tsn.h
> > @@ -0,0 +1,349 @@
> > +#undef TRACE_SYSTEM
> > +#define TRACE_SYSTEM tsn
> > +
> > +#if !defined(_TRACE_TSN_H) || defined(TRACE_HEADER_MULTI_READ)
> > +#define _TRACE_TSN_H
> > +
> > +#include <linux/tsn.h>
> > +#include <linux/tracepoint.h>
> > +
> > +#include <linux/if_ether.h>
> > +#include <linux/if_vlan.h>
> > +/* #include <linux/skbuff.h> */
> > +
> > +/* FIXME: update to TRACE_CLASS to reduce overhead */
>
> I'm curious to why I didn't do this now. A class would make less
> duplication of typing too ;-)
Yeah, I found this in a really great article written by some tracing-dude,
I hear he talks really, really fast!
https://lwn.net/Articles/381064/
> > +TRACE_EVENT(tsn_buffer_write,
> > +
> > + TP_PROTO(struct tsn_link *link,
> > + size_t bytes),
> > +
> > + TP_ARGS(link, bytes),
> > +
> > + TP_STRUCT__entry(
> > + __field(u64, stream_id)
> > + __field(size_t, size)
> > + __field(size_t, bsize)
> > + __field(size_t, size_left)
> > + __field(void *, buffer)
> > + __field(void *, head)
> > + __field(void *, tail)
> > + __field(void *, end)
> > + ),
> > +
> > + TP_fast_assign(
> > + __entry->stream_id = link->stream_id;
> > + __entry->size = bytes;
> > + __entry->bsize = link->used_buffer_size;
> > + __entry->size_left = (link->head - link->tail) % link->used_buffer_size;
>
> Move this logic into the print statement, since you save head and tail.
Ok, any particular reason?
> > + __entry->buffer = link->buffer;
> > + __entry->head = link->head;
> > + __entry->tail = link->tail;
> > + __entry->end = link->end;
> > + ),
> > +
> > + TP_printk("stream_id=%llu, copy=%zd, buffer: %zd, avail=%zd, [buffer=%p, head=%p, tail=%p, end=%p]",
> > + __entry->stream_id, __entry->size, __entry->bsize, __entry->size_left,
>
> __entry->stream_id, __entry->size, __entry->bsize,
> (__entry->head - __entry->tail) % __entry->bsize,
>
Ok, so is this about saving space by dropping one intermediate value, or is
it some other point I'm missing here?
> > + __entry->buffer, __entry->head, __entry->tail, __entry->end)
> > +
> > + );
> > +
> > +TRACE_EVENT(tsn_buffer_write_net,
> > +
> > + TP_PROTO(struct tsn_link *link,
> > + size_t bytes),
> > +
> > + TP_ARGS(link, bytes),
> > +
> > + TP_STRUCT__entry(
> > + __field(u64, stream_id)
> > + __field(size_t, size)
> > + __field(size_t, bsize)
> > + __field(size_t, size_left)
> > + __field(void *, buffer)
> > + __field(void *, head)
> > + __field(void *, tail)
> > + __field(void *, end)
> > + ),
> > +
> > + TP_fast_assign(
> > + __entry->stream_id = link->stream_id;
> > + __entry->size = bytes;
> > + __entry->bsize = link->used_buffer_size;
> > + __entry->size_left = (link->head - link->tail) % link->used_buffer_size;
> > + __entry->buffer = link->buffer;
> > + __entry->head = link->head;
> > + __entry->tail = link->tail;
> > + __entry->end = link->end;
> > + ),
> > +
> > + TP_printk("stream_id=%llu, copy=%zd, buffer: %zd, avail=%zd, [buffer=%p, head=%p, tail=%p, end=%p]",
> > + __entry->stream_id, __entry->size, __entry->bsize, __entry->size_left,
> > + __entry->buffer, __entry->head, __entry->tail, __entry->end)
> > +
> > + );
> > +
> > +
> > +TRACE_EVENT(tsn_buffer_read,
> > +
> > + TP_PROTO(struct tsn_link *link,
> > + size_t bytes),
> > +
> > + TP_ARGS(link, bytes),
> > +
> > + TP_STRUCT__entry(
> > + __field(u64, stream_id)
> > + __field(size_t, size)
> > + __field(size_t, bsize)
> > + __field(size_t, size_left)
> > + __field(void *, buffer)
> > + __field(void *, head)
> > + __field(void *, tail)
> > + __field(void *, end)
> > + ),
> > +
> > + TP_fast_assign(
> > + __entry->stream_id = link->stream_id;
> > + __entry->size = bytes;
> > + __entry->bsize = link->used_buffer_size;
> > + __entry->size_left = (link->head - link->tail) % link->used_buffer_size;
> > + __entry->buffer = link->buffer;
> > + __entry->head = link->head;
> > + __entry->tail = link->tail;
> > + __entry->end = link->end;
> > + ),
> > +
> > + TP_printk("stream_id=%llu, copy=%zd, buffer: %zd, avail=%zd, [buffer=%p, head=%p, tail=%p, end=%p]",
> > + __entry->stream_id, __entry->size, __entry->bsize, __entry->size_left,
> > + __entry->buffer, __entry->head, __entry->tail, __entry->end)
> > +
> > + );
> > +
> > +TRACE_EVENT(tsn_refill,
> > +
> > + TP_PROTO(struct tsn_link *link,
> > + size_t reported_avail),
> > +
> > + TP_ARGS(link, reported_avail),
> > +
> > + TP_STRUCT__entry(
> > + __field(u64, stream_id)
> > + __field(size_t, bsize)
> > + __field(size_t, size_left)
> > + __field(size_t, reported_left)
> > + __field(size_t, low_water)
> > + ),
> > +
> > + TP_fast_assign(
> > + __entry->stream_id = link->stream_id;
> > + __entry->bsize = link->used_buffer_size;
> > + __entry->size_left = (link->head - link->tail) % link->used_buffer_size;
>
> As you don't save head and tail here, this logic needs to remain.
>
> > + __entry->reported_left = reported_avail;
> > + __entry->low_water = link->low_water_mark;
> > + ),
> > +
> > + TP_printk("stream_id=%llu, buffer=%zd, avail=%zd, reported=%zd, low=%zd",
> > + __entry->stream_id, __entry->bsize, __entry->size_left, __entry->reported_left, __entry->low_water)
> > + );
> > +
> > +TRACE_EVENT(tsn_send_batch,
> > +
> > + TP_PROTO(struct tsn_link *link,
> > + int num_send,
> > + u64 ts_base_ns,
> > + u64 ts_delta_ns),
> > +
> > + TP_ARGS(link, num_send, ts_base_ns, ts_delta_ns),
> > +
> > + TP_STRUCT__entry(
> > + __field(u64, stream_id)
> > + __field(int, seqnr)
> > + __field(int, num_send)
> > + __field(u64, ts_base_ns)
> > + __field(u64, ts_delta_ns)
> > + ),
> > +
> > + TP_fast_assign(
> > + __entry->stream_id = link->stream_id;
> > + __entry->seqnr = (int)link->last_seqnr;
> > + __entry->ts_base_ns = ts_base_ns;
> > + __entry->ts_delta_ns = ts_delta_ns;
> > + __entry->num_send = num_send;
> > + ),
> > +
> > + TP_printk("stream_id=%llu, seqnr=%d, num_send=%d, ts_base_ns=%llu, ts_delta_ns=%llu",
> > + __entry->stream_id, __entry->seqnr, __entry->num_send, __entry->ts_base_ns, __entry->ts_delta_ns)
> > + );
> > +
> > +
> > +TRACE_EVENT(tsn_rx_handler,
> > +
> > + TP_PROTO(struct tsn_link *link,
> > + const struct ethhdr *ethhdr,
> > + u64 sid),
> > +
> > + TP_ARGS(link, ethhdr, sid),
> > +
> > + TP_STRUCT__entry(
> > + __field(char *, name)
> > + __field(u16, proto)
> > + __field(u64, sid)
> > + __field(u64, link_sid)
> > + ),
> > + TP_fast_assign(
> > + __entry->name = link->nic->name;
> > + __entry->proto = ethhdr->h_proto;
> > + __entry->sid = sid;
> > + __entry->link_sid = link->stream_id;
> > + ),
> > +
> > + TP_printk("name=%s, proto: 0x%04x, stream_id=%llu, link->sid=%llu",
> > + __entry->name, ntohs(__entry->proto), __entry->sid, __entry->link_sid)
> > + );
> > +
> > +TRACE_EVENT(tsn_du,
> > +
> > + TP_PROTO(struct tsn_link *link,
> > + size_t bytes),
> > +
> > + TP_ARGS(link, bytes),
> > +
> > + TP_STRUCT__entry(
> > + __field(u64, link_sid)
> > + __field(size_t, bytes)
> > + ),
> > + TP_fast_assign(
> > + __entry->link_sid = link->stream_id;
> > + __entry->bytes = bytes;
> > + ),
> > +
> > + TP_printk("stream_id=%llu,bytes=%zu",
> > + __entry->link_sid, __entry->bytes)
> > +);
> > +
> > +TRACE_EVENT(tsn_set_buffer,
> > +
> > + TP_PROTO(struct tsn_link *link, size_t bufsize),
> > +
> > + TP_ARGS(link, bufsize),
> > +
> > + TP_STRUCT__entry(
> > + __field(u64, stream_id)
> > + __field(size_t, size)
> > + ),
> > +
> > + TP_fast_assign(
> > + __entry->stream_id = link->stream_id;
> > + __entry->size = bufsize;
> > + ),
> > +
> > + TP_printk("stream_id=%llu,buffer_size=%zu",
> > + __entry->stream_id, __entry->size)
> > +
> > + );
> > +
> > +TRACE_EVENT(tsn_free_buffer,
> > +
> > + TP_PROTO(struct tsn_link *link),
> > +
> > + TP_ARGS(link),
> > +
> > + TP_STRUCT__entry(
> > + __field(u64, stream_id)
> > + __field(size_t, bufsize)
> > + ),
> > +
> > + TP_fast_assign(
> > + __entry->stream_id = link->stream_id;
> > + __entry->bufsize = link->buffer_size;
> > + ),
> > +
> > + TP_printk("stream_id=%llu,size:%zd",
> > + __entry->stream_id, __entry->bufsize)
> > +
> > + );
> > +
> > +TRACE_EVENT(tsn_buffer_drain,
> > +
> > + TP_PROTO(struct tsn_link *link, size_t used),
> > +
> > + TP_ARGS(link, used),
> > +
> > + TP_STRUCT__entry(
> > + __field(u64, stream_id)
> > + __field(size_t, used)
> > + ),
> > +
> > + TP_fast_assign(
> > + __entry->stream_id = link->stream_id;
> > + __entry->used = used;
> > + ),
> > +
> > + TP_printk("stream_id=%llu,used=%zu",
> > + __entry->stream_id, __entry->used)
> > +
> > +);
> > +/* TODO: too long, need cleanup.
> > + */
> > +TRACE_EVENT(tsn_pre_tx,
> > +
> > + TP_PROTO(struct tsn_link *link, struct sk_buff *skb, size_t bytes),
> > +
> > + TP_ARGS(link, skb, bytes),
> > +
> > + TP_STRUCT__entry(
> > + __field(u64, stream_id)
> > + __field(u32, vlan_tag)
> > + __field(size_t, bytes)
> > + __field(size_t, data_len)
> > + __field(unsigned int, headlen)
> > + __field(u16, protocol)
> > + __field(u16, prot_native)
> > + __field(int, tx_idx)
> > + __field(u16, mac_len)
> > + __field(u16, hdr_len)
> > + __field(u16, vlan_tci)
> > + __field(u16, mac_header)
> > + __field(unsigned int, tail)
> > + __field(unsigned int, end)
> > + __field(unsigned int, truesize)
> > + ),
> > +
> > + TP_fast_assign(
> > + __entry->stream_id = link->stream_id;
> > + __entry->vlan_tag = (skb_vlan_tag_present(skb) ? skb_vlan_tag_get(skb) : 0);
> > + __entry->bytes = bytes;
> > + __entry->data_len = skb->data_len;
> > + __entry->headlen = skb_headlen(skb);
> > + __entry->protocol = ntohs(vlan_get_protocol(skb));
>
> Maybe it would be better to do the ntohs() in the TP_printk() as well.
>
> > + __entry->prot_native = ntohs(skb->protocol);
>
> here too.
>
> > + __entry->tx_idx = skb_get_queue_mapping(skb);
> > +
> > + __entry->mac_len = skb->mac_len;
> > + __entry->hdr_len = skb->hdr_len;
> > + __entry->vlan_tci = skb->vlan_tci;
> > + __entry->mac_header = skb->mac_header;
> > + __entry->tail = (unsigned int)skb->tail;
> > + __entry->end = (unsigned int)skb->end;
> > + __entry->truesize = skb->truesize;
> > + ),
> > +
> > + TP_printk("stream_id=%llu,vlan_tag=0x%04x,data_size=%zd,data_len=%zd,headlen=%u,proto=0x%04x (0x%04x),tx_idx=%d,mac_len=%u,hdr_len=%u,vlan_tci=0x%02x,mac_header=0x%02x,tail=%u,end=%u,truesize=%u",
> > + __entry->stream_id,
> > + __entry->vlan_tag,
> > + __entry->bytes,
> > + __entry->data_len,
> > + __entry->headlen,
> > + __entry->protocol,
> > + __entry->prot_native, __entry->tx_idx,
> > + __entry->mac_len,
> > + __entry->hdr_len,
> > + __entry->vlan_tci,
> > + __entry->mac_header,
>
> Is this an ether mac header? If so we support %M. But as it's defined
> as only u16, it doesn't seem like it can be.
Actually, looking at the output, I'm not quite sure what it is that I
wanted to grab with that, the skb->mac_header should give an offset into
the header-area of skb, so it should be a constant offset from skb->head
(that is an actual pointer).
I *think* I wanted to make sure I updated things correctly so that the
offset didn't suddenly change, but the fact that I'm no longer sure
indicates that I should just drop that one. That whole printout is too long
anyway..
Thanks for pointing a finger at this!
I'm still a bit stymied as to why logic should be in TP_printk() and not
TP_fast_assign(). Not that I really have any preferences either way, just
curious.
--
Henrik Austad
[toc] | [prev] | [next] | [standalone]
| From | Steven Rostedt <rostedt@goodmis.org> |
|---|---|
| Date | 2016-06-13 04:30 +0200 |
| Subject | Re: [very-RFC 6/8] Add TSN event-tracing |
| Message-ID | <rJpNv-4T-1@gated-at.bofh.it> |
| In reply to | #1420332 |
On Sun, 12 Jun 2016 23:25:10 +0200
Henrik Austad <henrik@austad.us> wrote:
> > > +#include <linux/if_ether.h>
> > > +#include <linux/if_vlan.h>
> > > +/* #include <linux/skbuff.h> */
> > > +
> > > +/* FIXME: update to TRACE_CLASS to reduce overhead */
> >
> > I'm curious to why I didn't do this now. A class would make less
> > duplication of typing too ;-)
>
> Yeah, I found this in a really great article written by some tracing-dude,
> I hear he talks really, really fast!
I plead the 5th!
>
> https://lwn.net/Articles/381064/
>
> > > +TRACE_EVENT(tsn_buffer_write,
> > > +
> > > + TP_PROTO(struct tsn_link *link,
> > > + size_t bytes),
> > > +
> > > + TP_ARGS(link, bytes),
> > > +
> > > + TP_STRUCT__entry(
> > > + __field(u64, stream_id)
> > > + __field(size_t, size)
> > > + __field(size_t, bsize)
> > > + __field(size_t, size_left)
> > > + __field(void *, buffer)
> > > + __field(void *, head)
> > > + __field(void *, tail)
> > > + __field(void *, end)
> > > + ),
> > > +
> > > + TP_fast_assign(
> > > + __entry->stream_id = link->stream_id;
> > > + __entry->size = bytes;
> > > + __entry->bsize = link->used_buffer_size;
> > > + __entry->size_left = (link->head - link->tail) % link->used_buffer_size;
> >
> > Move this logic into the print statement, since you save head and tail.
>
> Ok, any particular reason?
Because it removes calculations during the trace. The calculations done
in TP_printk() are done at the time of reading the trace, and
calculations done in TP_fast_assign() are done during the recording and
hence adding more overhead to the trace itself.
>
> > > + __entry->buffer = link->buffer;
> > > + __entry->head = link->head;
> > > + __entry->tail = link->tail;
> > > + __entry->end = link->end;
> > > + ),
> > > +
> > > + TP_printk("stream_id=%llu, copy=%zd, buffer: %zd, avail=%zd, [buffer=%p, head=%p, tail=%p, end=%p]",
> > > + __entry->stream_id, __entry->size, __entry->bsize, __entry->size_left,
> >
> > __entry->stream_id, __entry->size, __entry->bsize,
> > (__entry->head - __entry->tail) % __entry->bsize,
> >
>
> Ok, so is this about saving space by dropping one intermediate value, or is
> it some other point I'm missing here?
Nope, just moving the overhead from the recording of the trace to the
reading of the trace.
>
> > > + __entry->buffer, __entry->head, __entry->tail, __entry->end)
> > > +
> > > + );
> > > +
> > > +
> > > + TP_fast_assign(
> > > + __entry->stream_id = link->stream_id;
> > > + __entry->vlan_tag = (skb_vlan_tag_present(skb) ? skb_vlan_tag_get(skb) : 0);
> > > + __entry->bytes = bytes;
> > > + __entry->data_len = skb->data_len;
> > > + __entry->headlen = skb_headlen(skb);
> > > + __entry->protocol = ntohs(vlan_get_protocol(skb));
> >
> > Maybe it would be better to do the ntohs() in the TP_printk() as well.
> >
> > > + __entry->prot_native = ntohs(skb->protocol);
> >
> > here too.
> >
> > > + __entry->tx_idx = skb_get_queue_mapping(skb);
> > > +
> > > + __entry->mac_len = skb->mac_len;
> > > + __entry->hdr_len = skb->hdr_len;
> > > + __entry->vlan_tci = skb->vlan_tci;
> > > + __entry->mac_header = skb->mac_header;
> > > + __entry->tail = (unsigned int)skb->tail;
> > > + __entry->end = (unsigned int)skb->end;
> > > + __entry->truesize = skb->truesize;
> > > + ),
> > > +
> > > + TP_printk("stream_id=%llu,vlan_tag=0x%04x,data_size=%zd,data_len=%zd,headlen=%u,proto=0x%04x (0x%04x),tx_idx=%d,mac_len=%u,hdr_len=%u,vlan_tci=0x%02x,mac_header=0x%02x,tail=%u,end=%u,truesize=%u",
> > > + __entry->stream_id,
> > > + __entry->vlan_tag,
> > > + __entry->bytes,
> > > + __entry->data_len,
> > > + __entry->headlen,
> > > + __entry->protocol,
> > > + __entry->prot_native, __entry->tx_idx,
> > > + __entry->mac_len,
> > > + __entry->hdr_len,
> > > + __entry->vlan_tci,
> > > + __entry->mac_header,
> >
> > Is this an ether mac header? If so we support %M. But as it's defined
> > as only u16, it doesn't seem like it can be.
>
> Actually, looking at the output, I'm not quite sure what it is that I
> wanted to grab with that, the skb->mac_header should give an offset into
> the header-area of skb, so it should be a constant offset from skb->head
> (that is an actual pointer).
>
> I *think* I wanted to make sure I updated things correctly so that the
> offset didn't suddenly change, but the fact that I'm no longer sure
> indicates that I should just drop that one. That whole printout is too long
> anyway..
>
> Thanks for pointing a finger at this!
>
>
> I'm still a bit stymied as to why logic should be in TP_printk() and not
> TP_fast_assign(). Not that I really have any preferences either way, just
> curious.
As said above, it's simply just trying to make tracing have less of an
effect on what is being traced. The more you can do in the post
transactions the faster the trace becomes and less invasive the trace
is on the system performance.
-- Steve
[toc] | [prev] | [next] | [standalone]
| From | Henrik Austad <henrik@austad.us> |
|---|---|
| Date | 2016-06-13 09:30 +0200 |
| Subject | Re: [very-RFC 6/8] Add TSN event-tracing |
| Message-ID | <rJutQ-355-27@gated-at.bofh.it> |
| In reply to | #1420411 |
[Multipart message — attachments visible in raw view] — view raw
On Sun, Jun 12, 2016 at 10:22:01PM -0400, Steven Rostedt wrote: > On Sun, 12 Jun 2016 23:25:10 +0200 > Henrik Austad <henrik@austad.us> wrote: > > > > > +#include <linux/if_ether.h> > > > > +#include <linux/if_vlan.h> > > > > +/* #include <linux/skbuff.h> */ > > > > + > > > > +/* FIXME: update to TRACE_CLASS to reduce overhead */ > > > > > > I'm curious to why I didn't do this now. A class would make less > > > duplication of typing too ;-) > > > > Yeah, I found this in a really great article written by some tracing-dude, > > I hear he talks really, really fast! > > I plead the 5th! > > > > > https://lwn.net/Articles/381064/ > > > > > > +TRACE_EVENT(tsn_buffer_write, > > > > + > > > > + TP_PROTO(struct tsn_link *link, > > > > + size_t bytes), > > > > + > > > > + TP_ARGS(link, bytes), > > > > + > > > > + TP_STRUCT__entry( > > > > + __field(u64, stream_id) > > > > + __field(size_t, size) > > > > + __field(size_t, bsize) > > > > + __field(size_t, size_left) > > > > + __field(void *, buffer) > > > > + __field(void *, head) > > > > + __field(void *, tail) > > > > + __field(void *, end) > > > > + ), > > > > + > > > > + TP_fast_assign( > > > > + __entry->stream_id = link->stream_id; > > > > + __entry->size = bytes; > > > > + __entry->bsize = link->used_buffer_size; > > > > + __entry->size_left = (link->head - link->tail) % link->used_buffer_size; > > > > > > Move this logic into the print statement, since you save head and tail. > > > > Ok, any particular reason? > > Because it removes calculations during the trace. The calculations done > in TP_printk() are done at the time of reading the trace, and > calculations done in TP_fast_assign() are done during the recording and > hence adding more overhead to the trace itself. Aha! that makes sense, thanks! (/me goes and updates the tracing-part) -Henrik
[toc] | [prev] | [next] | [standalone]
| From | Henrik Austad <henrik@austad.us> |
|---|---|
| Date | 2016-06-12 01:10 +0200 |
| Subject | [very-RFC 8/8] MAINTAINERS: add TSN/AVB-entries |
| Message-ID | <rJ0cq-QL-23@gated-at.bofh.it> |
| In reply to | #1420097 |
From: Henrik Austad <haustad@cisco.com> Not sure how relevant this is other than making a point about maintaining it. Signed-off-by: Henrik Austad <haustad@cisco.com> --- MAINTAINERS | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index ed42cb6..ef5d926 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11634,6 +11634,20 @@ T: git git://linuxtv.org/anttip/media_tree.git S: Maintained F: drivers/media/tuners/tua9001* +TSN CORE DRIVER +M: Henrik Austad <haustad@cisco.com> +L: linux-kernel@vger.kernel.org +S: Supported +F: drivers/net/tsn/ +F: include/linux/tsn.h +F: include/trace/events/tsn.h + +TSN_AVB_DRIVER +M: Henrik Austad <haustad@cisco.com> +L: alsa-devel@alsa-project.org (moderated for non-subscribers) +S: Supported +F: drivers/media/avb/ + TULIP NETWORK DRIVERS L: netdev@vger.kernel.org L: linux-parisc@vger.kernel.org -- 2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Richard Cochran <richardcochran@gmail.com> |
|---|---|
| Date | 2016-06-13 13:50 +0200 |
| Message-ID | <rJyxr-5JN-5@gated-at.bofh.it> |
| In reply to | #1420097 |
Henrik, On Sun, Jun 12, 2016 at 01:01:28AM +0200, Henrik Austad wrote: > There are at least one AVB-driver (the AV-part of TSN) in the kernel > already, Which driver is that? > however this driver aims to solve a wider scope as TSN can do > much more than just audio. A very basic ALSA-driver is added to the end > that allows you to play music between 2 machines using aplay in one end > and arecord | aplay on the other (some fiddling required) We have plans > for doing the same for v4l2 eventually (but there are other fishes to > fry first). The same goes for a TSN_SOCK type approach as well. Please, no new socket type for this. > What remains > - tie to (g)PTP properly, currently using ktime_get() for presentation > time > - get time from shim into TSN and vice versa ... and a whole lot more, see below. > - let shim create/manage buffer (BTW, shim is a terrible name for that.) [sigh] People have been asking me about TSN and Linux, and we've made some thoughts about it. The interest is there, and so I am glad to see discussion on this topic. Having said that, your series does not even begin to address the real issues. I did not review the patches too carefully (because the important stuff is missing), but surely configfs is the wrong interface for this. In the end, we will be able to support TSN using the existing networking and audio interfaces, adding appropriate extensions. Your patch features a buffer shared by networking and audio. This isn't strictly necessary for TSN, and it may be harmful. The Listeners are supposed to calculate the delay from frame reception to the DA conversion. They can easily include the time needed for a user space program to parse the frames, copy (and combine/convert) the data, and re-start the audio transfer. A flexible TSN implementation will leave all of the format and encoding task to the userland. After all, TSN will some include more that just AV data, as you know. Lets take a look at the big picture. One aspect of TSN is already fully supported, namely the gPTP. Using the linuxptp user stack and a modern kernel, you have a complete 802.1AS-2011 solution. Here is what is missing to support audio TSN: * User Space 1. A proper userland stack for AVDECC, MAAP, FQTSS, and so on. The OpenAVB project does not offer much beyond simple examples. 2. A user space audio application that puts it all together, making use of the services in #1, the linuxptp gPTP service, the ALSA services, and the network connections. This program will have all the knowledge about packet formats, AV encodings, and the local HW capabilities. This program cannot yet be written, as we still need some kernel work in the audio and networking subsystems. * Kernel Space 1. Providing frames with a future transmit time. For normal sockets, this can be in the CMESG data. For mmap'ed buffers, we will need a new format. (I think Arnd is working on a new layout.) 2. Time based qdisc for transmitted frames. For MACs that support this (like the i210), we only have to place the frame into the correct queue. For normal HW, we want to be able to reserve a time window in which non-TSN frames are blocked. This is some work, but in the end it should be a generic solution that not only works "perfectly" with TSN HW but also provides best effort service using any NIC. 3. ALSA support for tunable AD/DA clocks. The rate of the Listener's DA clock must match that of the Talker and the other Listeners. Either you adjust it in HW using a VCO or similar, or you do adaptive sample rate conversion in the application. (And that is another reason for *not* having a shared kernel buffer.) For the Talker, either you adjust the AD clock to match the PTP time, or you measure the frequency offset. 4. ALSA support for time triggered playback. The patch series completely ignore the critical issue of media clock recovery. The Listener must buffer the stream in order to play it exactly at a specified time. It cannot simply send the stream ASAP to the audio HW, because some other Listener might need longer. AFAICT, there is nothing in ALSA that allows you to say, sample X should be played at time Y. These are some ideas about implementing TSN. Maybe some of it is wrong (especially about ALSA), but we definitely need a proper design to get the kernel parts right. There is plenty of work to do, but we really don't need some hacky, in-kernel buffer with hard coded audio formats. Thanks, Richard
[toc] | [prev] | [next] | [standalone]
| From | Henrik Austad <henrik@austad.us> |
|---|---|
| Date | 2016-06-13 15:10 +0200 |
| Message-ID | <rJzMR-6In-1@gated-at.bofh.it> |
| In reply to | #1420742 |
[Multipart message — attachments visible in raw view] — view raw
On Mon, Jun 13, 2016 at 01:47:13PM +0200, Richard Cochran wrote: > Henrik, Hi Richard, > On Sun, Jun 12, 2016 at 01:01:28AM +0200, Henrik Austad wrote: > > There are at least one AVB-driver (the AV-part of TSN) in the kernel > > already, > > Which driver is that? drivers/net/ethernet/renesas/ > > however this driver aims to solve a wider scope as TSN can do > > much more than just audio. A very basic ALSA-driver is added to the end > > that allows you to play music between 2 machines using aplay in one end > > and arecord | aplay on the other (some fiddling required) We have plans > > for doing the same for v4l2 eventually (but there are other fishes to > > fry first). The same goes for a TSN_SOCK type approach as well. > > Please, no new socket type for this. The idea was to create a tsn-driver and then allow userspace to use it either for media or for whatever else they'd like - and then a socket made sense. Or so I thought :) What is the rationale for no new sockets? To avoid cluttering? or do sockets have a drawback I'm not aware of? > > What remains > > - tie to (g)PTP properly, currently using ktime_get() for presentation > > time > > - get time from shim into TSN and vice versa > > ... and a whole lot more, see below. > > > - let shim create/manage buffer > > (BTW, shim is a terrible name for that.) So something thin that is placed between to subystems should rather be called.. flimsy? The point of the name was to indicate that it glued 2 pieces together. If you have a better suggestion, I'm all ears. > [sigh] > > People have been asking me about TSN and Linux, and we've made some > thoughts about it. The interest is there, and so I am glad to see > discussion on this topic. I'm not aware of any such discussions, could you point me to where TSN has been discussed, it would be nice to see other peoples thought on the matter (which was one of the ideas behind this series in the first place) > Having said that, your series does not even begin to address the real > issues. Well, in all honesty, I did say so :) It is marked as "very-RFC", and not for being included in the kernel as-is. I also made a short list of the most crucial bits missing. I know there are real issues, but solving these won't matter if you don't have anything useful to do with it. I decided to start by adding a thin ALSA-driver and then continue to work with the kernel infrastructure. Having something that works-ish makes it a lot easier to test and get others interested in, especially when you are not deeply involved in a subsystem. At one point you get to where you need input from other more intimate with then inner workings of the different subsystems to see how things should be created without making too much of a mess. So where we are :) My primary motivation was to a) gather feedback (which you have provided, and for which I am very grateful) b) get the discussion going on how/if TSN should be added to the kernel > I did not review the patches too carefully (because the > important stuff is missing), but surely configfs is the wrong > interface for this. Why is configfs wrong? Unless you want to implement discovery and enumeration and srp-negotiation in the kernel, you need userspace to handle this. Once userspace has done all that (found priority-codes, streamIDs, vlanIDs and all the required bits), then userspace can create a new link. For that I find ConfigFS to be quite useful and up to the task. In my opinion, it also makes for a much tidier and saner interface than some obscure dark-magic ioctl() > In the end, we will be able to support TSN using > the existing networking and audio interfaces, adding appropriate > extensions. I surely hope so, but as I'm not deep into the networking part of the kernel finding those appropriate extensions is hard - which is why we started writing a standalone module- > Your patch features a buffer shared by networking and audio. This > isn't strictly necessary for TSN, and it may be harmful. At one stage, data has to flow in/out of the network, and whoever's using TSN probably need to store data somewhere as well, so you need some form of buffering at one place in the path the data flows through. That being said, one of the bits on my plate is to remove the "TSN-hosted-buffer" and let TSN read/write data via the shim_ops. What the best set of functions where are, remain to be seen, but it should provide a way to move data from either a single frame or a "few frames" to the shime (err.. <descriptive word for a thin layer slapped between 2 largers subsystems in the kernel> ;) > The > Listeners are supposed to calculate the delay from frame reception to > the DA conversion. They can easily include the time needed for a user > space program to parse the frames, copy (and combine/convert) the > data, and re-start the audio transfer. A flexible TSN implementation > will leave all of the format and encoding task to the userland. After > all, TSN will some include more that just AV data, as you know. Yes, or a ALSA-driver capable of same task. But yes, you need a way to propagate the presentation-time (and maybe a timestamp for when a frame was received) to the final destination of the samples. As far as I've been able to tell, this is not possible in the kernel at the moment. > Lets take a look at the big picture. One aspect of TSN is already > fully supported, namely the gPTP. Using the linuxptp user stack and a > modern kernel, you have a complete 802.1AS-2011 solution. Yes, I thought so, which is also why I have put that to the side and why I'm using ktime_get() for timestamps at the moment. There's also the issue of hooking the time into ALSA/V4L2 > Here is what is missing to support audio TSN: > > * User Space > > 1. A proper userland stack for AVDECC, MAAP, FQTSS, and so on. The > OpenAVB project does not offer much beyond simple examples. yes, I've noticed. I've refered to an imaginary 'tsnctl' in the code, which is supposed to be a "userspace catch-all for TSN-housekeeping". You probably need a tsnd or similar as well to send keepalive frames etc. > 2. A user space audio application that puts it all together, making > use of the services in #1, the linuxptp gPTP service, the ALSA > services, and the network connections. This program will have all > the knowledge about packet formats, AV encodings, and the local HW > capabilities. This program cannot yet be written, as we still need > some kernel work in the audio and networking subsystems. Why? the whole point should be to make it as easy for userspace as possible. If you need to tailor each individual media-appliation to use AVB, it is not going to be very useful outside pro-Audio. Sure, there will be challenges, but one key element here should be to *not* require upgrading every single media application. Then, back to the suggestion of adding a TSN_SOCKET (which you didn't like, but can we agree on a term "raw interface to TSN", and mode of transport can be defined later? ), was to let those applications that are TSN-aware to do what they need to do, whether it is controlling robots or media streams. > * Kernel Space > > 1. Providing frames with a future transmit time. For normal sockets, > this can be in the CMESG data. For mmap'ed buffers, we will need a > new format. (I think Arnd is working on a new layout.) Ah, I was unaware of this, both CMESG and mmap buffers. What is the accuracy of deferred transmit? If you have a class A stream, you push out a new frame every 125 us, you may end up with accuracy-constraints lower than that if you want to be able to state "send frame X at time Y". > 2. Time based qdisc for transmitted frames. For MACs that support > this (like the i210), we only have to place the frame into the > correct queue. For normal HW, we want to be able to reserve a time > window in which non-TSN frames are blocked. This is some work, but > in the end it should be a generic solution that not only works > "perfectly" with TSN HW but also provides best effort service using > any NIC. Yes, that would be very nice, and something like that is the ultimate goal of the netdev_ops I added, even though it is a far way away from that now. > 3. ALSA support for tunable AD/DA clocks. The rate of the Listener's > DA clock must match that of the Talker and the other Listeners. > Either you adjust it in HW using a VCO or similar, or you do > adaptive sample rate conversion in the application. (And that is > another reason for *not* having a shared kernel buffer.) For the > Talker, either you adjust the AD clock to match the PTP time, or > you measure the frequency offset. Yes, this is something missing that must be adressed. And yes, I know sharing a buffer the way the alsa-shim is currently doing is bad. > 4. ALSA support for time triggered playback. The patch series > completely ignore the critical issue of media clock recovery. The > Listener must buffer the stream in order to play it exactly at a > specified time. It cannot simply send the stream ASAP to the audio > HW, because some other Listener might need longer. AFAICT, there > is nothing in ALSA that allows you to say, sample X should be > played at time Y. > > These are some ideas about implementing TSN. Maybe some of it is > wrong (especially about ALSA), but we definitely need a proper design > to get the kernel parts right. There is plenty of work to do, but we > really don't need some hacky, in-kernel buffer with hard coded audio > formats. Well, the hard-coded audio format you refer to is placed with the avb_alsa shim, avtp_du is part of the actual TSN-header so that is not audio-only. And yes, it must be separated. Apart from requiring media-applications to know about AVB, I don't think we really disagree on anything. As I said, the main motivation for submitting this now was to kick off a discussion, get some critical response (your email was awesome - thanks!) and start steering the development in the right direction. Regards, -- Henrik Austad
[toc] | [prev] | [next] | [standalone]
| From | Richard Cochran <richardcochran@gmail.com> |
|---|---|
| Date | 2016-06-13 21:40 +0200 |
| Message-ID | <rJFSi-2fB-7@gated-at.bofh.it> |
| In reply to | #1420808 |
On Mon, Jun 13, 2016 at 03:00:59PM +0200, Henrik Austad wrote: > On Mon, Jun 13, 2016 at 01:47:13PM +0200, Richard Cochran wrote: > > Which driver is that? > > drivers/net/ethernet/renesas/ That driver is merely a PTP capable MAC driver, nothing more. Although AVB is in the device name, the driver doesn't implement anything beyond the PTP bits. > What is the rationale for no new sockets? To avoid cluttering? or do > sockets have a drawback I'm not aware of? The current raw sockets will work just fine. Again, there should be a application that sits in between with the network socket and the audio interface. > Why is configfs wrong? Because the application will use the already existing network and audio interfaces to configure the system. > > Lets take a look at the big picture. One aspect of TSN is already > > fully supported, namely the gPTP. Using the linuxptp user stack and a > > modern kernel, you have a complete 802.1AS-2011 solution. > > Yes, I thought so, which is also why I have put that to the side and why > I'm using ktime_get() for timestamps at the moment. There's also the issue > of hooking the time into ALSA/V4L2 So lets get that issue solved before anything else. It is absolutely essential for TSN. Without the synchronization, you are only playing audio over the network. We already have software for that. > > 2. A user space audio application that puts it all together, making > > use of the services in #1, the linuxptp gPTP service, the ALSA > > services, and the network connections. This program will have all > > the knowledge about packet formats, AV encodings, and the local HW > > capabilities. This program cannot yet be written, as we still need > > some kernel work in the audio and networking subsystems. > > Why? Because user space is right place to place the knowledge of the myriad formats and options. > the whole point should be to make it as easy for userspace as > possible. If you need to tailor each individual media-appliation to use > AVB, it is not going to be very useful outside pro-Audio. Sure, there will > be challenges, but one key element here should be to *not* require > upgrading every single media application. > > Then, back to the suggestion of adding a TSN_SOCKET (which you didn't like, > but can we agree on a term "raw interface to TSN", and mode of transport > can be defined later? ), was to let those applications that are TSN-aware > to do what they need to do, whether it is controlling robots or media > streams. First you say you don't want ot upgrade media applications, but then you invent a new socket type. That is a contradiction in terms. Audio apps already use networking, and they already use the audio subsystem. We need to help them get their job done by providing the missing kernel interfaces. They don't need extra magic buffering the kernel. They already can buffer audio data by themselves. > > * Kernel Space > > > > 1. Providing frames with a future transmit time. For normal sockets, > > this can be in the CMESG data. For mmap'ed buffers, we will need a > > new format. (I think Arnd is working on a new layout.) > > Ah, I was unaware of this, both CMESG and mmap buffers. > > What is the accuracy of deferred transmit? If you have a class A stream, > you push out a new frame every 125 us, you may end up with > accuracy-constraints lower than that if you want to be able to state "send > frame X at time Y". I have no idea what you are asking here. Sorry, Richard
[toc] | [prev] | [next] | [standalone]
| From | Henrik Austad <henrik@austad.us> |
|---|---|
| Date | 2016-06-14 11:40 +0200 |
| Message-ID | <rJSZb-2YW-3@gated-at.bofh.it> |
| In reply to | #1421245 |
[Multipart message — attachments visible in raw view] — view raw
On Mon, Jun 13, 2016 at 09:32:10PM +0200, Richard Cochran wrote: > On Mon, Jun 13, 2016 at 03:00:59PM +0200, Henrik Austad wrote: > > On Mon, Jun 13, 2016 at 01:47:13PM +0200, Richard Cochran wrote: > > > Which driver is that? > > > > drivers/net/ethernet/renesas/ > > That driver is merely a PTP capable MAC driver, nothing more. > Although AVB is in the device name, the driver doesn't implement > anything beyond the PTP bits. Yes, I think they do the rest from userspace, not sure though :) > > What is the rationale for no new sockets? To avoid cluttering? or do > > sockets have a drawback I'm not aware of? > > The current raw sockets will work just fine. Again, there should be a > application that sits in between with the network socket and the audio > interface. So loop data from kernel -> userspace -> kernelspace and finally back to userspace and the media application? I agree that you need a way to pipe the incoming data directly from the network to userspace for those TSN users that can handle it. But again, for media-applications that don't know (or care) about AVB, it should be fed to ALSA/v4l2 directly and not jump between kernel and userspace an extra round. I get the point of not including every single audio/video encoder in the kernel, but raw audio should be piped directly to alsa. V4L2 has a way of piping encoded video through the system and to the media application (in order to support cameras that to encoding). The same approach should be doable for AVB, no? (someone from alsa/v4l2 should probably comment on this) > > Why is configfs wrong? > > Because the application will use the already existing network and > audio interfaces to configure the system. Configuring this via the audio-interface is going to be a challenge since you need to configure the stream through the network before you can create the audio interface. If not, you will have to either drop data or block the caller until the link has been fully configured. This is actually the reason why configfs is used in the series now, as it allows userspace to figure out all the different attributes and configure the link before letting ALSA start pushing data. > > > Lets take a look at the big picture. One aspect of TSN is already > > > fully supported, namely the gPTP. Using the linuxptp user stack and a > > > modern kernel, you have a complete 802.1AS-2011 solution. > > > > Yes, I thought so, which is also why I have put that to the side and why > > I'm using ktime_get() for timestamps at the moment. There's also the issue > > of hooking the time into ALSA/V4L2 > > So lets get that issue solved before anything else. It is absolutely > essential for TSN. Without the synchronization, you are only playing > audio over the network. We already have software for that. Yes, I agree, presentation-time and local time needs to be handled properly. The same for adjusting sample-rate etc. This is a lot of work, so I hope you can understand why I started out with a simple approach to spark a discussion before moving on to the larger bits. > > > 2. A user space audio application that puts it all together, making > > > use of the services in #1, the linuxptp gPTP service, the ALSA > > > services, and the network connections. This program will have all > > > the knowledge about packet formats, AV encodings, and the local HW > > > capabilities. This program cannot yet be written, as we still need > > > some kernel work in the audio and networking subsystems. > > > > Why? > > Because user space is right place to place the knowledge of the myriad > formats and options. Se response above, better to let anything but uncompressed raw data trickle through. > > the whole point should be to make it as easy for userspace as > > possible. If you need to tailor each individual media-appliation to use > > AVB, it is not going to be very useful outside pro-Audio. Sure, there will > > be challenges, but one key element here should be to *not* require > > upgrading every single media application. > > > > Then, back to the suggestion of adding a TSN_SOCKET (which you didn't like, > > but can we agree on a term "raw interface to TSN", and mode of transport > > can be defined later? ), was to let those applications that are TSN-aware > > to do what they need to do, whether it is controlling robots or media > > streams. > > First you say you don't want ot upgrade media applications, but then > you invent a new socket type. That is a contradiction in terms. Hehe, no, bad phrasing on my part. I want *both* (hence the shim-interface) :) > Audio apps already use networking, and they already use the audio > subsystem. We need to help them get their job done by providing the > missing kernel interfaces. They don't need extra magic buffering the > kernel. They already can buffer audio data by themselves. Yes, I know some audio apps "use networking", I can stream netradio, I can use jack to connect devices using RTP and probably a whole lot of other applications do similar things. However, AVB is more about using the network as a virtual sound-card. For the media application, it should not have to care if the device it is using is a soudncard inside the box or a set of AVB-capable speakers somewhere on the network. > > > * Kernel Space > > > > > > 1. Providing frames with a future transmit time. For normal sockets, > > > this can be in the CMESG data. For mmap'ed buffers, we will need a > > > new format. (I think Arnd is working on a new layout.) > > > > Ah, I was unaware of this, both CMESG and mmap buffers. > > > > What is the accuracy of deferred transmit? If you have a class A stream, > > you push out a new frame every 125 us, you may end up with > > accuracy-constraints lower than that if you want to be able to state "send > > frame X at time Y". > > I have no idea what you are asking here. I assumed that when you had a mmap'd buffer you'd have to specify a point in time at which the frame should be sent. And since a class A has a 125us interval of sending frames, you have to be able to send frames with enough accuray to that. That's a pretty strict deadline coming from userspace. But as they say, never assume. I have a lot to dig into, and I've gotten a lot of very useful pointers. I should be busy for a while -- Henrik Austad
[toc] | [prev] | [next] | [standalone]
| From | Richard Cochran <richardcochran@gmail.com> |
|---|---|
| Date | 2016-06-14 20:30 +0200 |
| Message-ID | <rK1g6-8wa-31@gated-at.bofh.it> |
| In reply to | #1421712 |
On Tue, Jun 14, 2016 at 11:30:00AM +0200, Henrik Austad wrote:
> So loop data from kernel -> userspace -> kernelspace and finally back to
> userspace and the media application?
Huh? I wonder where you got that idea. Let me show an example of
what I mean.
void listener()
{
int in = socket();
int out = open("/dev/dsp");
char buf[];
while (1) {
recv(in, buf, packetsize);
write(out, buf + offset, datasize);
}
}
See?
> Yes, I know some audio apps "use networking", I can stream netradio, I can
> use jack to connect devices using RTP and probably a whole lot of other
> applications do similar things. However, AVB is more about using the
> network as a virtual sound-card.
That is news to me. I don't recall ever having seen AVB described
like that before.
> For the media application, it should not
> have to care if the device it is using is a soudncard inside the box or a
> set of AVB-capable speakers somewhere on the network.
So you would like a remote listener to appear in the system as a local
PCM audio sink? And a remote talker would be like a local media URL?
Sounds unworkable to me, but even if you were to implement it, the
logic would surely belong in alsa-lib and not in the kernel. Behind
the enulated device, the library would run a loop like the example,
above.
In any case, your patches don't implement that sort of thing at all,
do they?
Thanks,
Richard
[toc] | [prev] | [next] | [standalone]
| From | Henrik Austad <henrik@austad.us> |
|---|---|
| Date | 2016-06-14 22:40 +0200 |
| Message-ID | <rK3hT-1kA-11@gated-at.bofh.it> |
| In reply to | #1422190 |
[Multipart message — attachments visible in raw view] — view raw
On Tue, Jun 14, 2016 at 08:26:15PM +0200, Richard Cochran wrote:
> On Tue, Jun 14, 2016 at 11:30:00AM +0200, Henrik Austad wrote:
> > So loop data from kernel -> userspace -> kernelspace and finally back to
> > userspace and the media application?
>
> Huh? I wonder where you got that idea. Let me show an example of
> what I mean.
>
> void listener()
> {
> int in = socket();
> int out = open("/dev/dsp");
> char buf[];
>
> while (1) {
> recv(in, buf, packetsize);
> write(out, buf + offset, datasize);
> }
> }
>
> See?
Where is your media-application in this? You only loop the audio from
network to the dsp, is the media-application attached to the dsp-device?
Whereas I want to do
aplay some_song.wav
or mplayer
or spotify
or ..
> > Yes, I know some audio apps "use networking", I can stream netradio, I can
> > use jack to connect devices using RTP and probably a whole lot of other
> > applications do similar things. However, AVB is more about using the
> > network as a virtual sound-card.
>
> That is news to me. I don't recall ever having seen AVB described
> like that before.
>
> > For the media application, it should not
> > have to care if the device it is using is a soudncard inside the box or a
> > set of AVB-capable speakers somewhere on the network.
>
> So you would like a remote listener to appear in the system as a local
> PCM audio sink? And a remote talker would be like a local media URL?
> Sounds unworkable to me, but even if you were to implement it, the
> logic would surely belong in alsa-lib and not in the kernel. Behind
> the enulated device, the library would run a loop like the example,
> above.
>
> In any case, your patches don't implement that sort of thing at all,
> do they?
Subject: [very-RFC 7/8] AVB ALSA - Add ALSA shim for TSN
Did you even bother to look?
--
Henrik Austad
[toc] | [prev] | [next] | [standalone]
| From | Richard Cochran <richardcochran@gmail.com> |
|---|---|
| Date | 2016-06-15 09:10 +0200 |
| Message-ID | <rKd7A-7Q2-7@gated-at.bofh.it> |
| In reply to | #1422313 |
On Tue, Jun 14, 2016 at 10:38:10PM +0200, Henrik Austad wrote: > Whereas I want to do > > aplay some_song.wav Can you please explain how your patches accomplish this? Thanks, Richard
[toc] | [prev] | [next] | [standalone]
| From | Henrik Austad <henrik@austad.us> |
|---|---|
| Date | 2016-06-15 10:00 +0200 |
| Message-ID | <rKdTY-88q-15@gated-at.bofh.it> |
| In reply to | #1422677 |
[Multipart message — attachments visible in raw view] — view raw
On Wed, Jun 15, 2016 at 09:04:41AM +0200, Richard Cochran wrote: > On Tue, Jun 14, 2016 at 10:38:10PM +0200, Henrik Austad wrote: > > Whereas I want to do > > > > aplay some_song.wav > > Can you please explain how your patches accomplish this? In short: modprobe tsn modprobe avb_alsa mkdir /sys/kernel/config/eth0/link cd /sys/kernel/config/eth0/link <set approriate values vor the attributes> echo alsa > enabled aplay -Ddefault:CARD=avb some_song.wav Likewise on the receiver side, except add 'Listener' to end_station attribute arecord -c2 -r48000 -f S16_LE -Ddefault:CARD=avb > some_recording.wav I've not had time to fully fix the hw-aprams for alsa, so some manual tweaking of arecord is required. Again, this is a very early attempt to get something useful done with TSN, I know there are rough edges, I know buffer handling and timestamping is not finished Note: if you don't have an intel-card, load tsn in debug-mode and it will let you use all NICs present. modprobe tsn in_debug=1 -- Henrik Austad
[toc] | [prev] | [next] | [standalone]
| From | Richard Cochran <richardcochran@gmail.com> |
|---|---|
| Date | 2016-06-15 13:50 +0200 |
| Message-ID | <rKhux-21f-3@gated-at.bofh.it> |
| In reply to | #1422677 |
On Wed, Jun 15, 2016 at 09:04:41AM +0200, Richard Cochran wrote: > On Tue, Jun 14, 2016 at 10:38:10PM +0200, Henrik Austad wrote: > > Whereas I want to do > > > > aplay some_song.wav > > Can you please explain how your patches accomplish this? Never mind. Looking back, I found it in patch #7. Thanks, Richard
[toc] | [prev] | [next] | [standalone]
| From | Richard Cochran <richardcochran@gmail.com> |
|---|---|
| Date | 2016-06-15 09:20 +0200 |
| Message-ID | <rKdhg-7T3-7@gated-at.bofh.it> |
| In reply to | #1422313 |
On Tue, Jun 14, 2016 at 10:38:10PM +0200, Henrik Austad wrote: > Where is your media-application in this? Um, that *is* a media application. It plays music on the sound card. > You only loop the audio from > network to the dsp, is the media-application attached to the dsp-device? Sorry, I thought the old OSS API would be familiar and easy to understand. The /dev/dsp is the sound card. Thanks, Richard
[toc] | [prev] | [next] | [standalone]
| From | Richard Cochran <richardcochran@gmail.com> |
|---|---|
| Date | 2016-06-13 21:40 +0200 |
| Message-ID | <rJFSi-2fB-19@gated-at.bofh.it> |
| In reply to | #1420808 |
On Mon, Jun 13, 2016 at 03:00:59PM +0200, Henrik Austad wrote: > On Mon, Jun 13, 2016 at 01:47:13PM +0200, Richard Cochran wrote: > > People have been asking me about TSN and Linux, and we've made some > > thoughts about it. The interest is there, and so I am glad to see > > discussion on this topic. > > I'm not aware of any such discussions, could you point me to where TSN has > been discussed, it would be nice to see other peoples thought on the matter > (which was one of the ideas behind this series in the first place) To my knowledge, there hasn't been any previous TSN talk on lkml. (You have just now started the discussion ;) Sorry for not being clear. Richard
[toc] | [prev] | [next] | [standalone]
Page 1 of 3 [1] 2 3 Next page →
Back to top | Article view | linux.kernel
csiph-web