Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1656243 > unrolled thread
| Started by | Mika Westerberg <mika.westerberg@linux.intel.com> |
|---|---|
| First post | 2017-06-02 16:10 +0200 |
| Last post | 2017-06-06 08:50 +0200 |
| Articles | 20 on this page of 52 — 7 participants |
Back to article view | Back to linux.kernel
[PATCH v3 00/27] Thunderbolt security levels and NVM firmware upgrade Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-02 16:10 +0200
[PATCH v3 05/27] thunderbolt: Add MSI-X support Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-02 16:10 +0200
[PATCH v3 07/27] thunderbolt: Allow passing NULL to tb_ctl_free() Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-02 16:10 +0200
[PATCH v3 18/27] thunderbolt: Rework control channel to be more reliable Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-02 16:10 +0200
[PATCH v3 27/27] MAINTAINERS: Add maintainers for Thunderbolt driver Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-02 16:10 +0200
[PATCH v3 25/27] thunderbolt: Add support for host and device NVM firmware upgrade Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-02 16:10 +0200
[PATCH v3 01/27] thunderbolt: Use const buffer pointer in write operations Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-02 16:10 +0200
[PATCH v3 22/27] thunderbolt: Add support for DMA configuration based mailbox Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-02 16:10 +0200
[PATCH v3 06/27] thunderbolt: Rework capability handling Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-02 16:10 +0200
Re: [PATCH v3 06/27] thunderbolt: Rework capability handling Lukas Wunner <lukas@wunner.de> - 2017-06-04 16:00 +0200
Re: [PATCH v3 06/27] thunderbolt: Rework capability handling Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-04 17:10 +0200
Re: [PATCH v3 06/27] thunderbolt: Rework capability handling Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-04 17:10 +0200
Re: [PATCH v3 06/27] thunderbolt: Rework capability handling Andy Shevchenko <andy.shevchenko@gmail.com> - 2017-06-04 20:20 +0200
Re: [PATCH v3 06/27] thunderbolt: Rework capability handling Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-05 08:50 +0200
[PATCH v3 19/27] thunderbolt: Add new Thunderbolt PCI IDs Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-02 16:10 +0200
Re: [PATCH v3 19/27] thunderbolt: Add new Thunderbolt PCI IDs Lukas Wunner <lukas@wunner.de> - 2017-06-05 10:20 +0200
Re: [PATCH v3 19/27] thunderbolt: Add new Thunderbolt PCI IDs Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-05 11:40 +0200
Re: [PATCH v3 19/27] thunderbolt: Add new Thunderbolt PCI IDs Lukas Wunner <lukas@wunner.de> - 2017-06-05 14:10 +0200
Re: [PATCH v3 19/27] thunderbolt: Add new Thunderbolt PCI IDs Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-05 15:00 +0200
Re: [PATCH v3 19/27] thunderbolt: Add new Thunderbolt PCI IDs Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-05 15:40 +0200
Re: [PATCH v3 19/27] thunderbolt: Add new Thunderbolt PCI IDs Lukas Wunner <lukas@wunner.de> - 2017-06-05 15:50 +0200
Re: [PATCH v3 19/27] thunderbolt: Add new Thunderbolt PCI IDs Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-05 16:00 +0200
Re: [PATCH v3 19/27] thunderbolt: Add new Thunderbolt PCI IDs Andy Shevchenko <andriy.shevchenko@linux.intel.com> - 2017-06-05 16:30 +0200
Re: [PATCH v3 19/27] thunderbolt: Add new Thunderbolt PCI IDs Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-05 16:50 +0200
Re: [PATCH v3 19/27] thunderbolt: Add new Thunderbolt PCI IDs Greg Kroah-Hartman <gregkh@linuxfoundation.org> - 2017-06-05 17:30 +0200
Re: [PATCH v3 19/27] thunderbolt: Add new Thunderbolt PCI IDs Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-05 17:50 +0200
RE: [PATCH v3 19/27] thunderbolt: Add new Thunderbolt PCI IDs <Mario.Limonciello@dell.com> - 2017-06-05 18:00 +0200
Re: [PATCH v3 19/27] thunderbolt: Add new Thunderbolt PCI IDs Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-05 19:00 +0200
[PATCH v3 17/27] thunderbolt: Let the connection manager handle all notifications Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-02 16:10 +0200
[PATCH v3 04/27] thunderbolt: Do not warn about newer DROM versions Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-02 16:10 +0200
[PATCH v3 16/27] thunderbolt: Expose make_header() to other files Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-02 16:10 +0200
[PATCH v3 26/27] thunderbolt: Add documentation how Thunderbolt bus can be used Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-02 16:10 +0200
Re: [PATCH v3 26/27] thunderbolt: Add documentation how Thunderbolt bus can be used Greg Kroah-Hartman <gregkh@linuxfoundation.org> - 2017-06-03 16:20 +0200
[PATCH v3 10/27] thunderbolt: Fail switch adding operation if reading DROM fails Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-02 16:10 +0200
[PATCH v3 03/27] thunderbolt: Do not try to read UID if DROM offset is read as 0 Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-02 16:10 +0200
[PATCH v3 20/27] thunderbolt: Add support for NHI mailbox Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-02 16:10 +0200
[PATCH v3 08/27] thunderbolt: Introduce thunderbolt bus and connection manager Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-02 16:20 +0200
Re: [PATCH v3 08/27] thunderbolt: Introduce thunderbolt bus and connection manager Andreas Noever <andreas.noever@gmail.com> - 2017-06-05 17:20 +0200
[PATCH v3 02/27] thunderbolt: No need to read UID of the root switch on resume Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-02 16:20 +0200
[PATCH v3 14/27] thunderbolt: Move control channel messages to tb_msgs.h Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-02 16:20 +0200
[PATCH v3 13/27] thunderbolt: Read vendor and device name from DROM Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-02 16:20 +0200
[PATCH v3 11/27] thunderbolt: Do not fail if DROM data CRC32 is invalid Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-02 16:20 +0200
[PATCH v3 09/27] thunderbolt: Convert switch to a device Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-02 16:20 +0200
Re: [PATCH v3 09/27] thunderbolt: Convert switch to a device Greg Kroah-Hartman <gregkh@linuxfoundation.org> - 2017-06-03 16:20 +0200
[PATCH v3 21/27] thunderbolt: Store Thunderbolt generation in the switch structure Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-02 16:20 +0200
Re: [PATCH v3 00/27] Thunderbolt security levels and NVM firmware upgrade Andy Shevchenko <andriy.shevchenko@linux.intel.com> - 2017-06-02 20:10 +0200
Re: [PATCH v3 00/27] Thunderbolt security levels and NVM firmware upgrade Greg Kroah-Hartman <gregkh@linuxfoundation.org> - 2017-06-03 16:20 +0200
Re: [PATCH v3 00/27] Thunderbolt security levels and NVM firmware upgrade Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-05 09:20 +0200
Re: [PATCH v3 00/27] Thunderbolt security levels and NVM firmware upgrade Andreas Noever <andreas.noever@gmail.com> - 2017-06-05 19:10 +0200
Re: [PATCH v3 00/27] Thunderbolt security levels and NVM firmware upgrade Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-05 21:50 +0200
Re: [PATCH v3 00/27] Thunderbolt security levels and NVM firmware upgrade Greg Kroah-Hartman <gregkh@linuxfoundation.org> - 2017-06-06 08:10 +0200
Re: [PATCH v3 00/27] Thunderbolt security levels and NVM firmware upgrade Mika Westerberg <mika.westerberg@linux.intel.com> - 2017-06-06 08:50 +0200
Page 2 of 3 — ← Prev page 1 [2] 3 Next page →
| From | Lukas Wunner <lukas@wunner.de> |
|---|---|
| Date | 2017-06-05 15:50 +0200 |
| Subject | Re: [PATCH v3 19/27] thunderbolt: Add new Thunderbolt PCI IDs |
| Message-ID | <tP0yn-3wI-19@gated-at.bofh.it> |
| In reply to | #1657596 |
On Mon, Jun 05, 2017 at 04:33:34PM +0300, Mika Westerberg wrote: > On Mon, Jun 05, 2017 at 03:55:07PM +0300, Mika Westerberg wrote: > > > Yes, it's useful to have ICM-based Thunderbolt on Macs and personally > > > I'm totally fine with making it the default for Macs which support it. > > > (I can't speak for Andreas, obviously.) > > > > > > However it would be great to give people the *choice* between ICM versus > > > native mode, for at least two reasons: > > > > > > (1) Native mode uses free software. (I assume the ICM firmware remains > > > closed source.) > > > > > > (2) Native mode allows more versatility, e.g. how PCI tunnels are set up > > > to chained devices: PCI fanout or PCI direct routing, see: > > > https://developer.apple.com/library/content/documentation/HardwareDrivers/Conceptual/ThunderboltDevGuide/Basics/Basics.html > > > > > > Apple supports traffic prioritization to enable audio over Thunderbolt > > > with higher accuracy / minimal skew, I assume their choice to use > > > native mode was largely motivated by being able to support specialized > > > applications like that which are difficult or perhaps impossible to > > > implement in firmware: > > > http://pdfpiw.uspto.gov/.piw?Docid=09015384 > > > > Right, but do we need to do it now before we have got any feedback from > > users using Macs with Alpine Ridge and ICM? We can always add the module > > parameter later if really needed. > > It turns out that this is not too big change after all so I think it can > be included in the ICM patch if you want. > > Basically we would have module parameter: > > cm=auto|native|icm > > where auto is the default. > > Does that work? Yes, great, thanks! And in "auto" mode, it's ICM on non-Macs and TBT3-Macs, and native for TBT1/TBT2-Macs, right? Some Falcon Ridge Macs support ICM as well (e.g. the MacBookPro11,4 and MacBookPro11,5 introduced 2015), but maybe not all of them. This will have to be tested. If all of them support it, we could later default to ICM for those as well, or use DMI data to constrain it to specific models. Best regards, Lukas
[toc] | [prev] | [next] | [standalone]
| From | Mika Westerberg <mika.westerberg@linux.intel.com> |
|---|---|
| Date | 2017-06-05 16:00 +0200 |
| Subject | Re: [PATCH v3 19/27] thunderbolt: Add new Thunderbolt PCI IDs |
| Message-ID | <tP0I2-3zX-17@gated-at.bofh.it> |
| In reply to | #1657608 |
On Mon, Jun 05, 2017 at 03:46:43PM +0200, Lukas Wunner wrote: > On Mon, Jun 05, 2017 at 04:33:34PM +0300, Mika Westerberg wrote: > > On Mon, Jun 05, 2017 at 03:55:07PM +0300, Mika Westerberg wrote: > > > > Yes, it's useful to have ICM-based Thunderbolt on Macs and personally > > > > I'm totally fine with making it the default for Macs which support it. > > > > (I can't speak for Andreas, obviously.) > > > > > > > > However it would be great to give people the *choice* between ICM versus > > > > native mode, for at least two reasons: > > > > > > > > (1) Native mode uses free software. (I assume the ICM firmware remains > > > > closed source.) > > > > > > > > (2) Native mode allows more versatility, e.g. how PCI tunnels are set up > > > > to chained devices: PCI fanout or PCI direct routing, see: > > > > https://developer.apple.com/library/content/documentation/HardwareDrivers/Conceptual/ThunderboltDevGuide/Basics/Basics.html > > > > > > > > Apple supports traffic prioritization to enable audio over Thunderbolt > > > > with higher accuracy / minimal skew, I assume their choice to use > > > > native mode was largely motivated by being able to support specialized > > > > applications like that which are difficult or perhaps impossible to > > > > implement in firmware: > > > > http://pdfpiw.uspto.gov/.piw?Docid=09015384 > > > > > > Right, but do we need to do it now before we have got any feedback from > > > users using Macs with Alpine Ridge and ICM? We can always add the module > > > parameter later if really needed. > > > > It turns out that this is not too big change after all so I think it can > > be included in the ICM patch if you want. > > > > Basically we would have module parameter: > > > > cm=auto|native|icm > > > > where auto is the default. > > > > Does that work? > > Yes, great, thanks! > > And in "auto" mode, it's ICM on non-Macs and TBT3-Macs, and native for > TBT1/TBT2-Macs, right? Yes, that's correct. > Some Falcon Ridge Macs support ICM as well (e.g. the MacBookPro11,4 > and MacBookPro11,5 introduced 2015), but maybe not all of them. > This will have to be tested. If all of them support it, we could > later default to ICM for those as well, or use DMI data to constrain > it to specific models. Unfortunately starting ICM on Falcon Ridge Macs does not work (I tried that already) so there we need to stick with the native implementation.
[toc] | [prev] | [next] | [standalone]
| From | Andy Shevchenko <andriy.shevchenko@linux.intel.com> |
|---|---|
| Date | 2017-06-05 16:30 +0200 |
| Subject | Re: [PATCH v3 19/27] thunderbolt: Add new Thunderbolt PCI IDs |
| Message-ID | <tP1b4-41e-13@gated-at.bofh.it> |
| In reply to | #1657596 |
On Mon, 2017-06-05 at 16:33 +0300, Mika Westerberg wrote: > On Mon, Jun 05, 2017 at 03:55:07PM +0300, Mika Westerberg wrote: > > > > It turns out that this is not too big change after all so I think it > can > be included in the ICM patch if you want. > > Basically we would have module parameter: > > cm=auto|native|icm > > where auto is the default. > > Does that work? I remember Greg is opposite to being fan of module parameters in new code, so, please, if you are still going to do that, do it a separate patch which will be last in the series and can be discussed separately w.o. preventing everything else being applied. -- Andy Shevchenko <andriy.shevchenko@linux.intel.com> Intel Finland Oy
[toc] | [prev] | [next] | [standalone]
| From | Mika Westerberg <mika.westerberg@linux.intel.com> |
|---|---|
| Date | 2017-06-05 16:50 +0200 |
| Subject | Re: [PATCH v3 19/27] thunderbolt: Add new Thunderbolt PCI IDs |
| Message-ID | <tP1uq-499-23@gated-at.bofh.it> |
| In reply to | #1657630 |
On Mon, Jun 05, 2017 at 05:21:34PM +0300, Andy Shevchenko wrote: > On Mon, 2017-06-05 at 16:33 +0300, Mika Westerberg wrote: > > On Mon, Jun 05, 2017 at 03:55:07PM +0300, Mika Westerberg wrote: > > > > > > > It turns out that this is not too big change after all so I think it > > can > > be included in the ICM patch if you want. > > > > Basically we would have module parameter: > > > > cm=auto|native|icm > > > > where auto is the default. > > > > Does that work? > > > I remember Greg is opposite to being fan of module parameters in new > code, so, please, if you are still going to do that, do it a separate > patch which will be last in the series and can be discussed separately > w.o. preventing everything else being applied. Good point, thanks! I'll add it as a separate patch then.
[toc] | [prev] | [next] | [standalone]
| From | Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
|---|---|
| Date | 2017-06-05 17:30 +0200 |
| Subject | Re: [PATCH v3 19/27] thunderbolt: Add new Thunderbolt PCI IDs |
| Message-ID | <tP278-4D2-19@gated-at.bofh.it> |
| In reply to | #1657630 |
On Mon, Jun 05, 2017 at 05:21:34PM +0300, Andy Shevchenko wrote: > On Mon, 2017-06-05 at 16:33 +0300, Mika Westerberg wrote: > > On Mon, Jun 05, 2017 at 03:55:07PM +0300, Mika Westerberg wrote: > > > > > > > It turns out that this is not too big change after all so I think it > > can > > be included in the ICM patch if you want. > > > > Basically we would have module parameter: > > > > cm=auto|native|icm > > > > where auto is the default. > > > > Does that work? > > > I remember Greg is opposite to being fan of module parameters in new > code, so, please, if you are still going to do that, do it a separate > patch which will be last in the series and can be discussed separately > w.o. preventing everything else being applied. Yes, you should never need module parameters in "modern" code. As no one will ever set them, or know what to do here. Make it "automatic" please. thanks, greg k-h
[toc] | [prev] | [next] | [standalone]
| From | Mika Westerberg <mika.westerberg@linux.intel.com> |
|---|---|
| Date | 2017-06-05 17:50 +0200 |
| Subject | Re: [PATCH v3 19/27] thunderbolt: Add new Thunderbolt PCI IDs |
| Message-ID | <tP2qt-4Jd-1@gated-at.bofh.it> |
| In reply to | #1657672 |
On Mon, Jun 05, 2017 at 05:20:36PM +0200, Greg Kroah-Hartman wrote: > On Mon, Jun 05, 2017 at 05:21:34PM +0300, Andy Shevchenko wrote: > > On Mon, 2017-06-05 at 16:33 +0300, Mika Westerberg wrote: > > > On Mon, Jun 05, 2017 at 03:55:07PM +0300, Mika Westerberg wrote: > > > > > > > > > > It turns out that this is not too big change after all so I think it > > > can > > > be included in the ICM patch if you want. > > > > > > Basically we would have module parameter: > > > > > > cm=auto|native|icm > > > > > > where auto is the default. > > > > > > Does that work? > > > > > > I remember Greg is opposite to being fan of module parameters in new > > code, so, please, if you are still going to do that, do it a separate > > patch which will be last in the series and can be discussed separately > > w.o. preventing everything else being applied. > > Yes, you should never need module parameters in "modern" code. As no > one will ever set them, or know what to do here. Make it "automatic" > please. Well in current series it is already automatic :-) What Lukas wants here is a way to force a certain connection manager implementation to be used instead.
[toc] | [prev] | [next] | [standalone]
| From | <Mario.Limonciello@dell.com> |
|---|---|
| Date | 2017-06-05 18:00 +0200 |
| Subject | RE: [PATCH v3 19/27] thunderbolt: Add new Thunderbolt PCI IDs |
| Message-ID | <tP2Aa-4My-13@gated-at.bofh.it> |
| In reply to | #1657679 |
> -----Original Message----- > From: Mika Westerberg [mailto:mika.westerberg@linux.intel.com] > Sent: Monday, June 5, 2017 10:41 AM > To: Greg Kroah-Hartman <gregkh@linuxfoundation.org> > Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>; Lukas Wunner > <lukas@wunner.de>; Andreas Noever <andreas.noever@gmail.com>; Michael > Jamet <michael.jamet@intel.com>; Yehezkel Bernat <yehezkel.bernat@intel.com>; > Amir Levy <amir.jer.levy@intel.com>; Andy Lutomirski <luto@kernel.org>; > Limonciello, Mario <Mario_Limonciello@Dell.com>; Dominguez, Jared > <Jared_Dominguez@DELL.com>; linux-kernel@vger.kernel.org > Subject: Re: [PATCH v3 19/27] thunderbolt: Add new Thunderbolt PCI IDs > > On Mon, Jun 05, 2017 at 05:20:36PM +0200, Greg Kroah-Hartman wrote: > > On Mon, Jun 05, 2017 at 05:21:34PM +0300, Andy Shevchenko wrote: > > > On Mon, 2017-06-05 at 16:33 +0300, Mika Westerberg wrote: > > > > On Mon, Jun 05, 2017 at 03:55:07PM +0300, Mika Westerberg wrote: > > > > > > > > > > > > > It turns out that this is not too big change after all so I think it > > > > can > > > > be included in the ICM patch if you want. > > > > > > > > Basically we would have module parameter: > > > > > > > > cm=auto|native|icm > > > > > > > > where auto is the default. > > > > > > > > Does that work? > > > > > > > > > I remember Greg is opposite to being fan of module parameters in new > > > code, so, please, if you are still going to do that, do it a separate > > > patch which will be last in the series and can be discussed separately > > > w.o. preventing everything else being applied. > > > > Yes, you should never need module parameters in "modern" code. As no > > one will ever set them, or know what to do here. Make it "automatic" > > please. > > Well in current series it is already automatic :-) > > What Lukas wants here is a way to force a certain connection manager > implementation to be used instead. And presumably that's mostly for debugging purposes and will lead to additional quirks to get "automatic" to do the right thing on those machines that's it's found to be needed or more beneficial.
[toc] | [prev] | [next] | [standalone]
| From | Mika Westerberg <mika.westerberg@linux.intel.com> |
|---|---|
| Date | 2017-06-05 19:00 +0200 |
| Subject | Re: [PATCH v3 19/27] thunderbolt: Add new Thunderbolt PCI IDs |
| Message-ID | <tP3we-5oV-23@gated-at.bofh.it> |
| In reply to | #1657686 |
On Mon, Jun 05, 2017 at 03:50:24PM +0000, Mario.Limonciello@dell.com wrote: > And presumably that's mostly for debugging purposes and will lead > to additional quirks to get "automatic" to do the right thing on those > machines that's it's found to be needed or more beneficial. I would say that this is only for kernel hackers, like Lukas, who know what they are doing. But then again people needing that could just comment out one line in nhi.c to pick the implementation they want without any module parameter ;-) I think I'm not going to add that patch to this series after all - we can always do it later if really really needed.
[toc] | [prev] | [next] | [standalone]
| From | Mika Westerberg <mika.westerberg@linux.intel.com> |
|---|---|
| Date | 2017-06-02 16:10 +0200 |
| Subject | [PATCH v3 17/27] thunderbolt: Let the connection manager handle all notifications |
| Message-ID | <tNVr5-2dT-39@gated-at.bofh.it> |
| In reply to | #1656243 |
Currently the control channel (ctl.c) handles the one supported
notification (PLUG_EVENT) and sends back ACK accordingly. However, we
are going to add support for the internal connection manager (ICM) that
needs to handle a different notifications. So instead of dealing
everything in the control channel, we change the callback to take an
arbitrary thunderbolt packet and convert the native connection manager
to handle the event itself.
In addition we only push replies we know of to the response FIFO.
Everything else is treated as notification (or request) and is expected
to be dealt by the connection manager implementation.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Yehezkel Bernat <yehezkel.bernat@intel.com>
Reviewed-by: Michael Jamet <michael.jamet@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
drivers/thunderbolt/ctl.c | 86 ++++++++++++++++++++++++++++++--------------
drivers/thunderbolt/ctl.h | 5 +--
drivers/thunderbolt/domain.c | 15 +++++++-
drivers/thunderbolt/tb.c | 30 ++++++++++++----
drivers/thunderbolt/tb.h | 5 +--
5 files changed, 103 insertions(+), 38 deletions(-)
diff --git a/drivers/thunderbolt/ctl.c b/drivers/thunderbolt/ctl.c
index c6633da582b8..5417ed244edc 100644
--- a/drivers/thunderbolt/ctl.c
+++ b/drivers/thunderbolt/ctl.c
@@ -35,7 +35,7 @@ struct tb_ctl {
DECLARE_KFIFO(response_fifo, struct ctl_pkg*, 16);
struct completion response_ready;
- hotplug_cb callback;
+ event_cb callback;
void *callback_data;
};
@@ -52,6 +52,9 @@ struct tb_ctl {
#define tb_ctl_info(ctl, format, arg...) \
dev_info(&(ctl)->nhi->pdev->dev, format, ## arg)
+#define tb_ctl_dbg(ctl, format, arg...) \
+ dev_dbg(&(ctl)->nhi->pdev->dev, format, ## arg)
+
/* utility functions */
static int check_header(struct ctl_pkg *pkg, u32 len, enum tb_cfg_pkg_type type,
@@ -272,24 +275,12 @@ static int tb_ctl_tx(struct tb_ctl *ctl, const void *data, size_t len,
}
/**
- * tb_ctl_handle_plug_event() - acknowledge a plug event, invoke ctl->callback
+ * tb_ctl_handle_event() - acknowledge a plug event, invoke ctl->callback
*/
-static void tb_ctl_handle_plug_event(struct tb_ctl *ctl,
- struct ctl_pkg *response)
+static void tb_ctl_handle_event(struct tb_ctl *ctl, enum tb_cfg_pkg_type type,
+ struct ctl_pkg *pkg, size_t size)
{
- struct cfg_event_pkg *pkg = response->buffer;
- u64 route = tb_cfg_get_route(&pkg->header);
-
- if (check_header(response, sizeof(*pkg), TB_CFG_PKG_EVENT, route)) {
- tb_ctl_warn(ctl, "malformed TB_CFG_PKG_EVENT\n");
- return;
- }
-
- if (tb_cfg_error(ctl, route, pkg->port, TB_CFG_ERROR_ACK_PLUG_EVENT))
- tb_ctl_warn(ctl, "could not ack plug event on %llx:%x\n",
- route, pkg->port);
- WARN(pkg->zero, "pkg->zero is %#x\n", pkg->zero);
- ctl->callback(ctl->callback_data, route, pkg->port, pkg->unplug);
+ ctl->callback(ctl->callback_data, type, pkg->buffer, size);
}
static void tb_ctl_rx_submit(struct ctl_pkg *pkg)
@@ -302,10 +293,29 @@ static void tb_ctl_rx_submit(struct ctl_pkg *pkg)
*/
}
+static int tb_async_error(const struct ctl_pkg *pkg)
+{
+ const struct cfg_error_pkg *error = (const struct cfg_error_pkg *)pkg;
+
+ if (pkg->frame.eof != TB_CFG_PKG_ERROR)
+ return false;
+
+ switch (error->error) {
+ case TB_CFG_ERROR_LINK_ERROR:
+ case TB_CFG_ERROR_HEC_ERROR_DETECTED:
+ case TB_CFG_ERROR_FLOW_CONTROL_ERROR:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
static void tb_ctl_rx_callback(struct tb_ring *ring, struct ring_frame *frame,
bool canceled)
{
struct ctl_pkg *pkg = container_of(frame, typeof(*pkg), frame);
+ __be32 crc32;
if (canceled)
return; /*
@@ -320,18 +330,42 @@ static void tb_ctl_rx_callback(struct tb_ring *ring, struct ring_frame *frame,
}
frame->size -= 4; /* remove checksum */
- if (*(__be32 *) (pkg->buffer + frame->size)
- != tb_crc(pkg->buffer, frame->size)) {
- tb_ctl_err(pkg->ctl,
- "RX: checksum mismatch, dropping packet\n");
- goto rx;
- }
+ crc32 = tb_crc(pkg->buffer, frame->size);
be32_to_cpu_array(pkg->buffer, pkg->buffer, frame->size / 4);
- if (frame->eof == TB_CFG_PKG_EVENT) {
- tb_ctl_handle_plug_event(pkg->ctl, pkg);
+ switch (frame->eof) {
+ case TB_CFG_PKG_READ:
+ case TB_CFG_PKG_WRITE:
+ case TB_CFG_PKG_ERROR:
+ case TB_CFG_PKG_OVERRIDE:
+ case TB_CFG_PKG_RESET:
+ if (*(__be32 *)(pkg->buffer + frame->size) != crc32) {
+ tb_ctl_err(pkg->ctl,
+ "RX: checksum mismatch, dropping packet\n");
+ goto rx;
+ }
+ if (tb_async_error(pkg)) {
+ tb_ctl_handle_event(pkg->ctl, frame->eof,
+ pkg, frame->size);
+ goto rx;
+ }
+ break;
+
+ case TB_CFG_PKG_EVENT:
+ if (*(__be32 *)(pkg->buffer + frame->size) != crc32) {
+ tb_ctl_err(pkg->ctl,
+ "RX: checksum mismatch, dropping packet\n");
+ goto rx;
+ }
+ tb_ctl_handle_event(pkg->ctl, frame->eof, pkg, frame->size);
+ goto rx;
+
+ default:
+ tb_ctl_dbg(pkg->ctl, "RX: unknown package %#x, dropping\n",
+ frame->eof);
goto rx;
}
+
if (!kfifo_put(&pkg->ctl->response_fifo, pkg)) {
tb_ctl_err(pkg->ctl, "RX: fifo is full\n");
goto rx;
@@ -379,7 +413,7 @@ static struct tb_cfg_result tb_ctl_rx(struct tb_ctl *ctl, void *buffer,
*
* Return: Returns a pointer on success or NULL on failure.
*/
-struct tb_ctl *tb_ctl_alloc(struct tb_nhi *nhi, hotplug_cb cb, void *cb_data)
+struct tb_ctl *tb_ctl_alloc(struct tb_nhi *nhi, event_cb cb, void *cb_data)
{
int i;
struct tb_ctl *ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
diff --git a/drivers/thunderbolt/ctl.h b/drivers/thunderbolt/ctl.h
index 914da86ec77d..2b23e030a85b 100644
--- a/drivers/thunderbolt/ctl.h
+++ b/drivers/thunderbolt/ctl.h
@@ -13,9 +13,10 @@
/* control channel */
struct tb_ctl;
-typedef void (*hotplug_cb)(void *data, u64 route, u8 port, bool unplug);
+typedef void (*event_cb)(void *data, enum tb_cfg_pkg_type type,
+ const void *buf, size_t size);
-struct tb_ctl *tb_ctl_alloc(struct tb_nhi *nhi, hotplug_cb cb, void *cb_data);
+struct tb_ctl *tb_ctl_alloc(struct tb_nhi *nhi, event_cb cb, void *cb_data);
void tb_ctl_start(struct tb_ctl *ctl);
void tb_ctl_stop(struct tb_ctl *ctl);
void tb_ctl_free(struct tb_ctl *ctl);
diff --git a/drivers/thunderbolt/domain.c b/drivers/thunderbolt/domain.c
index e2f3777edee6..8ba6999c3165 100644
--- a/drivers/thunderbolt/domain.c
+++ b/drivers/thunderbolt/domain.c
@@ -94,6 +94,19 @@ struct tb *tb_domain_alloc(struct tb_nhi *nhi, size_t privsize)
return NULL;
}
+static void tb_domain_event_cb(void *data, enum tb_cfg_pkg_type type,
+ const void *buf, size_t size)
+{
+ struct tb *tb = data;
+
+ if (!tb->cm_ops->handle_event) {
+ tb_warn(tb, "domain does not have event handler\n");
+ return;
+ }
+
+ tb->cm_ops->handle_event(tb, type, buf, size);
+}
+
/**
* tb_domain_add() - Add domain to the system
* @tb: Domain to add
@@ -114,7 +127,7 @@ int tb_domain_add(struct tb *tb)
mutex_lock(&tb->lock);
- tb->ctl = tb_ctl_alloc(tb->nhi, tb->cm_ops->hotplug, tb);
+ tb->ctl = tb_ctl_alloc(tb->nhi, tb_domain_event_cb, tb);
if (!tb->ctl) {
ret = -ENOMEM;
goto err_unlock;
diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
index 94ecac012428..ea9de49b5e10 100644
--- a/drivers/thunderbolt/tb.c
+++ b/drivers/thunderbolt/tb.c
@@ -311,18 +311,34 @@ static void tb_handle_hotplug(struct work_struct *work)
*
* Delegates to tb_handle_hotplug.
*/
-static void tb_schedule_hotplug_handler(void *data, u64 route, u8 port,
- bool unplug)
+static void tb_handle_event(struct tb *tb, enum tb_cfg_pkg_type type,
+ const void *buf, size_t size)
{
- struct tb *tb = data;
- struct tb_hotplug_event *ev = kmalloc(sizeof(*ev), GFP_KERNEL);
+ const struct cfg_event_pkg *pkg = buf;
+ struct tb_hotplug_event *ev;
+ u64 route;
+
+ if (type != TB_CFG_PKG_EVENT) {
+ tb_warn(tb, "unexpected event %#x, ignoring\n", type);
+ return;
+ }
+
+ route = tb_cfg_get_route(&pkg->header);
+
+ if (tb_cfg_error(tb->ctl, route, pkg->port,
+ TB_CFG_ERROR_ACK_PLUG_EVENT)) {
+ tb_warn(tb, "could not ack plug event on %llx:%x\n", route,
+ pkg->port);
+ }
+
+ ev = kmalloc(sizeof(*ev), GFP_KERNEL);
if (!ev)
return;
INIT_WORK(&ev->work, tb_handle_hotplug);
ev->tb = tb;
ev->route = route;
- ev->port = port;
- ev->unplug = unplug;
+ ev->port = pkg->port;
+ ev->unplug = pkg->unplug;
queue_work(tb->wq, &ev->work);
}
@@ -419,7 +435,7 @@ static const struct tb_cm_ops tb_cm_ops = {
.stop = tb_stop,
.suspend_noirq = tb_suspend_noirq,
.resume_noirq = tb_resume_noirq,
- .hotplug = tb_schedule_hotplug_handler,
+ .handle_event = tb_handle_event,
};
struct tb *tb_probe(struct tb_nhi *nhi)
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
index 5e66dce53c65..73db614fa913 100644
--- a/drivers/thunderbolt/tb.h
+++ b/drivers/thunderbolt/tb.h
@@ -118,14 +118,15 @@ struct tb_path {
* @stop: Stops the domain
* @suspend_noirq: Connection manager specific suspend_noirq
* @resume_noirq: Connection manager specific resume_noirq
- * @hotplug: Handle hotplug event
+ * @handle_event: Handle thunderbolt event
*/
struct tb_cm_ops {
int (*start)(struct tb *tb);
void (*stop)(struct tb *tb);
int (*suspend_noirq)(struct tb *tb);
int (*resume_noirq)(struct tb *tb);
- hotplug_cb hotplug;
+ void (*handle_event)(struct tb *tb, enum tb_cfg_pkg_type,
+ const void *buf, size_t size);
};
/**
--
2.11.0
[toc] | [prev] | [next] | [standalone]
| From | Mika Westerberg <mika.westerberg@linux.intel.com> |
|---|---|
| Date | 2017-06-02 16:10 +0200 |
| Subject | [PATCH v3 04/27] thunderbolt: Do not warn about newer DROM versions |
| Message-ID | <tNVr5-2dT-41@gated-at.bofh.it> |
| In reply to | #1656243 |
DROM version 2 is compatible with the previous generation so no need to warn about that. Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Reviewed-by: Yehezkel Bernat <yehezkel.bernat@intel.com> Reviewed-by: Michael Jamet <michael.jamet@intel.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> --- drivers/thunderbolt/eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thunderbolt/eeprom.c b/drivers/thunderbolt/eeprom.c index e4e64b130514..eb2179c98b09 100644 --- a/drivers/thunderbolt/eeprom.c +++ b/drivers/thunderbolt/eeprom.c @@ -488,7 +488,7 @@ int tb_drom_read(struct tb_switch *sw) goto err; } - if (header->device_rom_revision > 1) + if (header->device_rom_revision > 2) tb_sw_warn(sw, "drom device_rom_revision %#x unknown\n", header->device_rom_revision); -- 2.11.0
[toc] | [prev] | [next] | [standalone]
| From | Mika Westerberg <mika.westerberg@linux.intel.com> |
|---|---|
| Date | 2017-06-02 16:10 +0200 |
| Subject | [PATCH v3 16/27] thunderbolt: Expose make_header() to other files |
| Message-ID | <tNVr5-2dT-37@gated-at.bofh.it> |
| In reply to | #1656243 |
We will be using this function in files introduced in subsequent
patches. While there the function is renamed to tb_cfg_make_header()
following tb_cfg_get_route().
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Yehezkel Bernat <yehezkel.bernat@intel.com>
Reviewed-by: Michael Jamet <michael.jamet@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
drivers/thunderbolt/ctl.c | 19 ++++---------------
drivers/thunderbolt/ctl.h | 11 +++++++++++
2 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/drivers/thunderbolt/ctl.c b/drivers/thunderbolt/ctl.c
index 8352ee8662aa..c6633da582b8 100644
--- a/drivers/thunderbolt/ctl.c
+++ b/drivers/thunderbolt/ctl.c
@@ -54,17 +54,6 @@ struct tb_ctl {
/* utility functions */
-static struct tb_cfg_header make_header(u64 route)
-{
- struct tb_cfg_header header = {
- .route_hi = route >> 32,
- .route_lo = route,
- };
- /* check for overflow, route_hi is not 32 bits! */
- WARN_ON(tb_cfg_get_route(&header) != route);
- return header;
-}
-
static int check_header(struct ctl_pkg *pkg, u32 len, enum tb_cfg_pkg_type type,
u64 route)
{
@@ -501,7 +490,7 @@ int tb_cfg_error(struct tb_ctl *ctl, u64 route, u32 port,
enum tb_cfg_error error)
{
struct cfg_error_pkg pkg = {
- .header = make_header(route),
+ .header = tb_cfg_make_header(route),
.port = port,
.error = error,
};
@@ -520,7 +509,7 @@ struct tb_cfg_result tb_cfg_reset(struct tb_ctl *ctl, u64 route,
int timeout_msec)
{
int err;
- struct cfg_reset_pkg request = { .header = make_header(route) };
+ struct cfg_reset_pkg request = { .header = tb_cfg_make_header(route) };
struct tb_cfg_header reply;
err = tb_ctl_tx(ctl, &request, sizeof(request), TB_CFG_PKG_RESET);
@@ -542,7 +531,7 @@ struct tb_cfg_result tb_cfg_read_raw(struct tb_ctl *ctl, void *buffer,
{
struct tb_cfg_result res = { 0 };
struct cfg_read_pkg request = {
- .header = make_header(route),
+ .header = tb_cfg_make_header(route),
.addr = {
.port = port,
.space = space,
@@ -579,7 +568,7 @@ struct tb_cfg_result tb_cfg_write_raw(struct tb_ctl *ctl, const void *buffer,
{
struct tb_cfg_result res = { 0 };
struct cfg_write_pkg request = {
- .header = make_header(route),
+ .header = tb_cfg_make_header(route),
.addr = {
.port = port,
.space = space,
diff --git a/drivers/thunderbolt/ctl.h b/drivers/thunderbolt/ctl.h
index 9812b1c86d4f..914da86ec77d 100644
--- a/drivers/thunderbolt/ctl.h
+++ b/drivers/thunderbolt/ctl.h
@@ -43,6 +43,17 @@ static inline u64 tb_cfg_get_route(const struct tb_cfg_header *header)
return (u64) header->route_hi << 32 | header->route_lo;
}
+static inline struct tb_cfg_header tb_cfg_make_header(u64 route)
+{
+ struct tb_cfg_header header = {
+ .route_hi = route >> 32,
+ .route_lo = route,
+ };
+ /* check for overflow, route_hi is not 32 bits! */
+ WARN_ON(tb_cfg_get_route(&header) != route);
+ return header;
+}
+
int tb_cfg_error(struct tb_ctl *ctl, u64 route, u32 port,
enum tb_cfg_error error);
struct tb_cfg_result tb_cfg_reset(struct tb_ctl *ctl, u64 route,
--
2.11.0
[toc] | [prev] | [next] | [standalone]
| From | Mika Westerberg <mika.westerberg@linux.intel.com> |
|---|---|
| Date | 2017-06-02 16:10 +0200 |
| Subject | [PATCH v3 26/27] thunderbolt: Add documentation how Thunderbolt bus can be used |
| Message-ID | <tNVr5-2dT-49@gated-at.bofh.it> |
| In reply to | #1656243 |
Since there are no such tool yet that handles all the low-level details
of connecting devices and upgrading their firmware, add a small document
that shows how the Thunderbolt bus can be used directly from command
line.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Yehezkel Bernat <yehezkel.bernat@intel.com>
Reviewed-by: Michael Jamet <michael.jamet@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
Documentation/admin-guide/index.rst | 1 +
Documentation/admin-guide/thunderbolt.rst | 199 ++++++++++++++++++++++++++++++
2 files changed, 200 insertions(+)
create mode 100644 Documentation/admin-guide/thunderbolt.rst
diff --git a/Documentation/admin-guide/index.rst b/Documentation/admin-guide/index.rst
index 8c60a8a32a1a..6d99a7ce6e21 100644
--- a/Documentation/admin-guide/index.rst
+++ b/Documentation/admin-guide/index.rst
@@ -61,6 +61,7 @@ configure specific aspects of kernel behavior to your liking.
java
ras
pm/index
+ thunderbolt
.. only:: subproject and html
diff --git a/Documentation/admin-guide/thunderbolt.rst b/Documentation/admin-guide/thunderbolt.rst
new file mode 100644
index 000000000000..6a4cd1f159ca
--- /dev/null
+++ b/Documentation/admin-guide/thunderbolt.rst
@@ -0,0 +1,199 @@
+=============
+ Thunderbolt
+=============
+The interface presented here is not meant for end users. Instead there
+should be a userspace tool that handles all the low-level details, keeps
+database of the authorized devices and prompts user for new connections.
+
+More details about the sysfs interface for Thunderbolt devices can be
+found in ``Documentation/ABI/testing/sysfs-bus-thunderbolt``.
+
+Those users who just want to connect any device without any sort of
+manual work, can add following line to
+``/etc/udev/rules.d/99-local.rules``::
+
+ ACTION=="add", SUBSYSTEM=="thunderbolt", ATTR{authorized}=="0", ATTR{authorized}="1"
+
+This will authorize all devices automatically when they appear. However,
+keep in mind that this bypasses the security levels and makes the system
+vulnerable to DMA attacks.
+
+Security levels and how to use them
+-----------------------------------
+Starting from Intel Falcon Ridge Thunderbolt controller there are 4
+security levels available. The reason for these is the fact that the
+connected devices can be DMA masters and thus read contents of the host
+memory without CPU and OS knowing about it. There are ways to prevent
+this by setting up an IOMMU but it is not always available for various
+reasons.
+
+The security levels are as follows:
+
+ none
+ All devices are automatically connected by the firmware. No user
+ approval is needed. In BIOS settings this is typically called
+ *Legacy mode*.
+
+ user
+ User is asked whether the device is allowed to be connected.
+ Based on the device identification information available through
+ ``/sys/bus/thunderbolt/devices``. user then can do the decision.
+ In BIOS settings this is typically called *Unique ID*.
+
+ secure
+ User is asked whether the device is allowed to be connected. In
+ addition to UUID the device (if it supports secure connect) is sent
+ a challenge that should match the expected one based on a random key
+ written to ``key`` sysfs attribute. In BIOS settings this is
+ typically called *One time saved key*.
+
+ dponly
+ The firmware automatically creates tunnels for Display Port and
+ USB. No PCIe tunneling is done. In BIOS settings this is
+ typically called *Display Port Only*.
+
+The current security level can be read from
+``/sys/bus/thunderbolt/devices/domainX/security`` where ``domainX`` is
+the Thunderbolt domain the host controller manages. There is typically
+one domain per Thunderbolt host controller.
+
+If the security level reads as ``user`` or ``secure`` the connected
+device must be authorized by the user before PCIe tunnels are created
+(e.g the PCIe device appears).
+
+Each Thunderbolt device plugged in will appear in sysfs under
+``/sys/bus/thunderbolt/devices``. The device directory carries
+information that can be used to identify the particular device,
+including its name and UUID.
+
+Authorizing devices when security level is ``user`` or ``secure``
+-----------------------------------------------------------------
+When a device is plugged in it will appear in sysfs as follows::
+
+ /sys/bus/thunderbolt/devices/0-1/authorized - 0
+ /sys/bus/thunderbolt/devices/0-1/device - 0x8004
+ /sys/bus/thunderbolt/devices/0-1/device_name - Thunderbolt to FireWire Adapter
+ /sys/bus/thunderbolt/devices/0-1/vendor - 0x1
+ /sys/bus/thunderbolt/devices/0-1/vendor_name - Apple, Inc.
+ /sys/bus/thunderbolt/devices/0-1/unique_id - e0376f00-0300-0100-ffff-ffffffffffff
+
+The ``authorized`` attribute reads 0 which means no PCIe tunnels are
+created yet. The user can authorize the device by simply::
+
+ # echo 1 > /sys/bus/thunderbolt/devices/0-1/authorized
+
+This will create the PCIe tunnels and the device is now connected.
+
+If the device supports secure connect, and the domain security level is
+set to ``secure``, it has an additional attribute ``key`` which can hold
+a random 32 byte value used for authorization and challenging the device in
+future connects::
+
+ /sys/bus/thunderbolt/devices/0-3/authorized - 0
+ /sys/bus/thunderbolt/devices/0-3/device - 0x305
+ /sys/bus/thunderbolt/devices/0-3/device_name - AKiTiO Thunder3 PCIe Box
+ /sys/bus/thunderbolt/devices/0-3/key -
+ /sys/bus/thunderbolt/devices/0-3/vendor - 0x41
+ /sys/bus/thunderbolt/devices/0-3/vendor_name - inXtron
+ /sys/bus/thunderbolt/devices/0-3/unique_id - dc010000-0000-8508-a22d-32ca6421cb16
+
+Notice the key is empty by default.
+
+If the user does not want to use secure connect it can just ``echo 1``
+to the ``authorized`` attribute and the PCIe tunnels will be created in
+the same way than in ``user`` security level.
+
+If the user wants to use secure connect, the first time the device is
+plugged a key needs to be created and send to the device::
+
+ # key=$(openssl rand -hex 32)
+ # echo $key > /sys/bus/thunderbolt/devices/0-3/key
+ # echo 1 > /sys/bus/thunderbolt/devices/0-3/authorized
+
+Now the device is connected (PCIe tunnels are created) and in addition
+the key is stored on the device NVM.
+
+Next time the device is plugged in the user can verify (challenge) the
+device using the same key::
+
+ # echo $key > /sys/bus/thunderbolt/devices/0-3/key
+ # echo 2 > /sys/bus/thunderbolt/devices/0-3/authorized
+
+If the challenge the device returns back matches the one we expect based
+on the key, the device is connected and the PCIe tunnels are created.
+However, if the challenge failed no tunnels are created and error is
+returned to the user.
+
+If the user still wants to connect the device it can either approve
+the device without a key or write new key and write 1 to the
+``authorized`` file to get the new key stored on the device NVM.
+
+Upgrading NVM on Thunderbolt device or host
+-------------------------------------------
+Since most of the functionality is handled in a firmware running on a
+host controller or a device, it is important that the firmware can be
+upgraded to the latest where possible bugs in it have been fixed.
+Typically OEMs provide this firmware from their support site.
+
+There is also a central site which has links where to download firmwares
+for some machines:
+
+ `Thunderbolt Updates <https://thunderbolttechnology.net/updates>`_
+
+Before you upgrade firmware on a device or host, please make sure it is
+the suitable. Failing to do that may render the device (or host) in a
+state where it cannot be used properly anymore without special tools!
+
+Host NVM upgrade on Apple Macs is not supported.
+
+Once the NVM image has been downloaded, you need to plug in a
+Thunderbolt device so that the host controller appears. It does not
+matter which device is connected (unless you are upgrading NVM on a
+device - then you need to connect that particular device).
+
+Note OEM-specific method to power the controller up ("force power") may
+be available for your system in which case there is no need to plug in a
+Thunderbolt device.
+
+After that we can write the firmware to the non-active parts of the NVM
+of the host or device. As an example here is how Intel NUC6i7KYK (Skull
+Canyon) Thunderbolt controller NVM is upgraded::
+
+ # dd if=KYK_TBT_FW_0018.bin of=/sys/bus/thunderbolt/devices/0-0/nvm_non_active0/nvmem
+
+Once the operation completes we can trigger NVM authentication and
+upgrade process as follows::
+
+ # echo 1 > /sys/bus/thunderbolt/devices/0-0/nvm_authenticate
+
+If no errors are returned, the host controller shortly disappears. Once
+it comes back the driver notices it and initiates a full power cycle.
+After a while the host controller appears again and this time it should
+be fully functional.
+
+We can verify that the new NVM firmware is active by running following
+commands::
+
+ # cat /sys/bus/thunderbolt/devices/0-0/nvm_authenticate
+ 0x0
+ # cat /sys/bus/thunderbolt/devices/0-0/nvm_version
+ 18.0
+
+If ``nvm_authenticate`` contains anything else than 0x0 it is the error
+code from the last authentication cycle, which means the authentication
+of the NVM image failed.
+
+Note names of the NVMem devices ``nvm_activeN`` and ``nvm_non_activeN``
+depends on the order they are registered in the NVMem subsystem. N in
+the name is the identifier added by the NVMem subsystem.
+
+Upgrading NVM when host controller is in safe mode
+--------------------------------------------------
+If the existing NVM is not properly authenticated (or is missing) the
+host controller goes into safe mode which means that only available
+functionality is flashing new NVM image. When in this mode the reading
+``nvm_version`` fails with ``ENODATA`` and the device identification
+information is missing.
+
+To recover from this mode, one needs to flash a valid NVM image to the
+host host controller in the same way it is done in the previous chapter.
--
2.11.0
[toc] | [prev] | [next] | [standalone]
| From | Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
|---|---|
| Date | 2017-06-03 16:20 +0200 |
| Subject | Re: [PATCH v3 26/27] thunderbolt: Add documentation how Thunderbolt bus can be used |
| Message-ID | <tOi4i-850-33@gated-at.bofh.it> |
| In reply to | #1656260 |
On Fri, Jun 02, 2017 at 05:05:23PM +0300, Mika Westerberg wrote: > Since there are no such tool yet that handles all the low-level details > of connecting devices and upgrading their firmware, add a small document > that shows how the Thunderbolt bus can be used directly from command > line. > > Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> > Reviewed-by: Yehezkel Bernat <yehezkel.bernat@intel.com> > Reviewed-by: Michael Jamet <michael.jamet@intel.com> > Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Very nice, thanks for documenting all of this. Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
[toc] | [prev] | [next] | [standalone]
| From | Mika Westerberg <mika.westerberg@linux.intel.com> |
|---|---|
| Date | 2017-06-02 16:10 +0200 |
| Subject | [PATCH v3 10/27] thunderbolt: Fail switch adding operation if reading DROM fails |
| Message-ID | <tNVr5-2dT-51@gated-at.bofh.it> |
| In reply to | #1656243 |
All non-root switches are expected to have DROM so if the operation
fails, it might be due the user unlugging the device. There is no point
continuing adding the switch further in that case. Just bail out.
For root switches (hosts) the DROM is either retrieved from a EFI
variable, NVM or hard-coded.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Yehezkel Bernat <yehezkel.bernat@intel.com>
Reviewed-by: Michael Jamet <michael.jamet@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
drivers/thunderbolt/switch.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index 5cd854dedeea..0ce8b600a23f 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -535,8 +535,11 @@ int tb_switch_add(struct tb_switch *sw)
int i, ret;
/* read drom */
- if (tb_drom_read(sw))
- tb_sw_warn(sw, "tb_eeprom_read_rom failed, continuing\n");
+ ret = tb_drom_read(sw);
+ if (ret) {
+ tb_sw_warn(sw, "tb_eeprom_read_rom failed\n");
+ return ret;
+ }
tb_sw_info(sw, "uid: %#llx\n", sw->uid);
tb_switch_set_uuid(sw);
--
2.11.0
[toc] | [prev] | [next] | [standalone]
| From | Mika Westerberg <mika.westerberg@linux.intel.com> |
|---|---|
| Date | 2017-06-02 16:10 +0200 |
| Subject | [PATCH v3 03/27] thunderbolt: Do not try to read UID if DROM offset is read as 0 |
| Message-ID | <tNVr5-2dT-55@gated-at.bofh.it> |
| In reply to | #1656243 |
At least Falcon Ridge when in host mode does not have any kind of DROM available and reading DROM offset returns 0 for these. Do not try to read DROM any further in that case. Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Reviewed-by: Yehezkel Bernat <yehezkel.bernat@intel.com> Reviewed-by: Michael Jamet <michael.jamet@intel.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> --- drivers/thunderbolt/eeprom.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/thunderbolt/eeprom.c b/drivers/thunderbolt/eeprom.c index 6392990c984d..e4e64b130514 100644 --- a/drivers/thunderbolt/eeprom.c +++ b/drivers/thunderbolt/eeprom.c @@ -276,6 +276,9 @@ int tb_drom_read_uid_only(struct tb_switch *sw, u64 *uid) if (res) return res; + if (drom_offset == 0) + return -ENODEV; + /* read uid */ res = tb_eeprom_read_n(sw, drom_offset, data, 9); if (res) -- 2.11.0
[toc] | [prev] | [next] | [standalone]
| From | Mika Westerberg <mika.westerberg@linux.intel.com> |
|---|---|
| Date | 2017-06-02 16:10 +0200 |
| Subject | [PATCH v3 20/27] thunderbolt: Add support for NHI mailbox |
| Message-ID | <tNVr5-2dT-57@gated-at.bofh.it> |
| In reply to | #1656243 |
The host controller includes two sets of registers that are used to
communicate with the firmware. Add functions that can be used to access
these registers.
This code is based on the work done by Amir Levy and Michael Jamet.
Signed-off-by: Michael Jamet <michael.jamet@intel.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Yehezkel Bernat <yehezkel.bernat@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
drivers/thunderbolt/nhi.c | 58 ++++++++++++++++++++++++++++++++++++++++++
drivers/thunderbolt/nhi.h | 16 ++++++++++++
drivers/thunderbolt/nhi_regs.h | 11 ++++++++
3 files changed, 85 insertions(+)
diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c
index fa4c2745dba2..c358c074f925 100644
--- a/drivers/thunderbolt/nhi.c
+++ b/drivers/thunderbolt/nhi.c
@@ -14,6 +14,7 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/dmi.h>
+#include <linux/delay.h>
#include "nhi.h"
#include "nhi_regs.h"
@@ -28,6 +29,8 @@
#define MSIX_MIN_VECS 6
#define MSIX_MAX_VECS 16
+#define NHI_MAILBOX_TIMEOUT 500 /* ms */
+
static int ring_interrupt_index(struct tb_ring *ring)
{
int bit = ring->hop;
@@ -525,6 +528,61 @@ void ring_free(struct tb_ring *ring)
kfree(ring);
}
+/**
+ * nhi_mailbox_cmd() - Send a command through NHI mailbox
+ * @nhi: Pointer to the NHI structure
+ * @cmd: Command to send
+ * @data: Data to be send with the command
+ *
+ * Sends mailbox command to the firmware running on NHI. Returns %0 in
+ * case of success and negative errno in case of failure.
+ */
+int nhi_mailbox_cmd(struct tb_nhi *nhi, enum nhi_mailbox_cmd cmd, u32 data)
+{
+ ktime_t timeout;
+ u32 val;
+
+ iowrite32(data, nhi->iobase + REG_INMAIL_DATA);
+
+ val = ioread32(nhi->iobase + REG_INMAIL_CMD);
+ val &= ~(REG_INMAIL_CMD_MASK | REG_INMAIL_ERROR);
+ val |= REG_INMAIL_OP_REQUEST | cmd;
+ iowrite32(val, nhi->iobase + REG_INMAIL_CMD);
+
+ timeout = ktime_add_ms(ktime_get(), NHI_MAILBOX_TIMEOUT);
+ do {
+ val = ioread32(nhi->iobase + REG_INMAIL_CMD);
+ if (!(val & REG_INMAIL_OP_REQUEST))
+ break;
+ usleep_range(10, 20);
+ } while (ktime_before(ktime_get(), timeout));
+
+ if (val & REG_INMAIL_OP_REQUEST)
+ return -ETIMEDOUT;
+ if (val & REG_INMAIL_ERROR)
+ return -EIO;
+
+ return 0;
+}
+
+/**
+ * nhi_mailbox_mode() - Return current firmware operation mode
+ * @nhi: Pointer to the NHI structure
+ *
+ * The function reads current firmware operation mode using NHI mailbox
+ * registers and returns it to the caller.
+ */
+enum nhi_fw_mode nhi_mailbox_mode(struct tb_nhi *nhi)
+{
+ u32 val;
+
+ val = ioread32(nhi->iobase + REG_OUTMAIL_CMD);
+ val &= REG_OUTMAIL_CMD_OPMODE_MASK;
+ val >>= REG_OUTMAIL_CMD_OPMODE_SHIFT;
+
+ return (enum nhi_fw_mode)val;
+}
+
static void nhi_interrupt_work(struct work_struct *work)
{
struct tb_nhi *nhi = container_of(work, typeof(*nhi), interrupt_work);
diff --git a/drivers/thunderbolt/nhi.h b/drivers/thunderbolt/nhi.h
index 8bd9b4e5a0b1..446ff6dac91d 100644
--- a/drivers/thunderbolt/nhi.h
+++ b/drivers/thunderbolt/nhi.h
@@ -143,6 +143,22 @@ static inline int ring_tx(struct tb_ring *ring, struct ring_frame *frame)
return __ring_enqueue(ring, frame);
}
+enum nhi_fw_mode {
+ NHI_FW_SAFE_MODE,
+ NHI_FW_AUTH_MODE,
+ NHI_FW_EP_MODE,
+ NHI_FW_CM_MODE,
+};
+
+enum nhi_mailbox_cmd {
+ NHI_MAILBOX_SAVE_DEVS = 0x05,
+ NHI_MAILBOX_DRV_UNLOADS = 0x07,
+ NHI_MAILBOX_ALLOW_ALL_DEVS = 0x23,
+};
+
+int nhi_mailbox_cmd(struct tb_nhi *nhi, enum nhi_mailbox_cmd cmd, u32 data);
+enum nhi_fw_mode nhi_mailbox_mode(struct tb_nhi *nhi);
+
/*
* PCI IDs used in this driver from Win Ridge forward. There is no
* need for the PCI quirk anymore as we will use ICM also on Apple
diff --git a/drivers/thunderbolt/nhi_regs.h b/drivers/thunderbolt/nhi_regs.h
index 48b98d3c7e6a..322fe1fa3a3c 100644
--- a/drivers/thunderbolt/nhi_regs.h
+++ b/drivers/thunderbolt/nhi_regs.h
@@ -107,4 +107,15 @@ struct ring_desc {
#define REG_DMA_MISC 0x39864
#define REG_DMA_MISC_INT_AUTO_CLEAR BIT(2)
+#define REG_INMAIL_DATA 0x39900
+
+#define REG_INMAIL_CMD 0x39904
+#define REG_INMAIL_CMD_MASK GENMASK(7, 0)
+#define REG_INMAIL_ERROR BIT(30)
+#define REG_INMAIL_OP_REQUEST BIT(31)
+
+#define REG_OUTMAIL_CMD 0x3990c
+#define REG_OUTMAIL_CMD_OPMODE_SHIFT 8
+#define REG_OUTMAIL_CMD_OPMODE_MASK GENMASK(11, 8)
+
#endif
--
2.11.0
[toc] | [prev] | [next] | [standalone]
| From | Mika Westerberg <mika.westerberg@linux.intel.com> |
|---|---|
| Date | 2017-06-02 16:20 +0200 |
| Subject | [PATCH v3 08/27] thunderbolt: Introduce thunderbolt bus and connection manager |
| Message-ID | <tNVAK-2ht-3@gated-at.bofh.it> |
| In reply to | #1656243 |
Thunderbolt fabric consists of one or more switches. This fabric is
called domain and it is controlled by an entity called connection
manager. The connection manager can be either internal (driven by a
firmware running on the host controller) or external (software driver).
This driver currently implements support for the latter.
In order to manage switches and their properties more easily we model
this domain structure as a Linux bus. Each host controller adds a domain
device to this bus, and these devices are named as domainN where N
stands for index or id of the current domain.
We then abstract connection manager specific operations into a new
structure tb_cm_ops and convert the existing tb.c to fill those
accordingly. This makes it easier to add support for the internal
connection manager in subsequent patches.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Yehezkel Bernat <yehezkel.bernat@intel.com>
Reviewed-by: Michael Jamet <michael.jamet@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
drivers/thunderbolt/Makefile | 2 +-
drivers/thunderbolt/domain.c | 229 +++++++++++++++++++++++++++++++++++++++
drivers/thunderbolt/nhi.c | 31 ++++--
drivers/thunderbolt/tb.c | 156 ++++++++++++--------------
drivers/thunderbolt/tb.h | 70 +++++++++---
drivers/thunderbolt/tunnel_pci.c | 9 +-
6 files changed, 376 insertions(+), 121 deletions(-)
create mode 100644 drivers/thunderbolt/domain.c
diff --git a/drivers/thunderbolt/Makefile b/drivers/thunderbolt/Makefile
index 5d1053cdfa54..e276a9a62261 100644
--- a/drivers/thunderbolt/Makefile
+++ b/drivers/thunderbolt/Makefile
@@ -1,3 +1,3 @@
obj-${CONFIG_THUNDERBOLT} := thunderbolt.o
thunderbolt-objs := nhi.o ctl.o tb.o switch.o cap.o path.o tunnel_pci.o eeprom.o
-
+thunderbolt-objs += domain.o
diff --git a/drivers/thunderbolt/domain.c b/drivers/thunderbolt/domain.c
new file mode 100644
index 000000000000..e2f3777edee6
--- /dev/null
+++ b/drivers/thunderbolt/domain.c
@@ -0,0 +1,229 @@
+/*
+ * Thunderbolt bus support
+ *
+ * Copyright (C) 2017, Intel Corporation
+ * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/idr.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "tb.h"
+
+static DEFINE_IDA(tb_domain_ida);
+
+struct bus_type tb_bus_type = {
+ .name = "thunderbolt",
+};
+
+static void tb_domain_release(struct device *dev)
+{
+ struct tb *tb = container_of(dev, struct tb, dev);
+
+ tb_ctl_free(tb->ctl);
+ destroy_workqueue(tb->wq);
+ ida_simple_remove(&tb_domain_ida, tb->index);
+ kfree(tb);
+}
+
+struct device_type tb_domain_type = {
+ .name = "thunderbolt_domain",
+ .release = tb_domain_release,
+};
+
+/**
+ * tb_domain_alloc() - Allocate a domain
+ * @nhi: Pointer to the host controller
+ * @privsize: Size of the connection manager private data
+ *
+ * Allocates and initializes a new Thunderbolt domain. Connection
+ * managers are expected to call this and then fill in @cm_ops
+ * accordingly.
+ *
+ * Call tb_domain_put() to release the domain before it has been added
+ * to the system.
+ *
+ * Return: allocated domain structure on %NULL in case of error
+ */
+struct tb *tb_domain_alloc(struct tb_nhi *nhi, size_t privsize)
+{
+ struct tb *tb;
+
+ /*
+ * Make sure the structure sizes map with that the hardware
+ * expects because bit-fields are being used.
+ */
+ BUILD_BUG_ON(sizeof(struct tb_regs_switch_header) != 5 * 4);
+ BUILD_BUG_ON(sizeof(struct tb_regs_port_header) != 8 * 4);
+ BUILD_BUG_ON(sizeof(struct tb_regs_hop) != 2 * 4);
+
+ tb = kzalloc(sizeof(*tb) + privsize, GFP_KERNEL);
+ if (!tb)
+ return NULL;
+
+ tb->nhi = nhi;
+ mutex_init(&tb->lock);
+
+ tb->index = ida_simple_get(&tb_domain_ida, 0, 0, GFP_KERNEL);
+ if (tb->index < 0)
+ goto err_free;
+
+ tb->wq = alloc_ordered_workqueue("thunderbolt%d", 0, tb->index);
+ if (!tb->wq)
+ goto err_remove_ida;
+
+ tb->dev.parent = &nhi->pdev->dev;
+ tb->dev.bus = &tb_bus_type;
+ tb->dev.type = &tb_domain_type;
+ dev_set_name(&tb->dev, "domain%d", tb->index);
+ device_initialize(&tb->dev);
+
+ return tb;
+
+err_remove_ida:
+ ida_simple_remove(&tb_domain_ida, tb->index);
+err_free:
+ kfree(tb);
+
+ return NULL;
+}
+
+/**
+ * tb_domain_add() - Add domain to the system
+ * @tb: Domain to add
+ *
+ * Starts the domain and adds it to the system. Hotplugging devices will
+ * work after this has been returned successfully. In order to remove
+ * and release the domain after this function has been called, call
+ * tb_domain_remove().
+ *
+ * Return: %0 in case of success and negative errno in case of error
+ */
+int tb_domain_add(struct tb *tb)
+{
+ int ret;
+
+ if (WARN_ON(!tb->cm_ops))
+ return -EINVAL;
+
+ mutex_lock(&tb->lock);
+
+ tb->ctl = tb_ctl_alloc(tb->nhi, tb->cm_ops->hotplug, tb);
+ if (!tb->ctl) {
+ ret = -ENOMEM;
+ goto err_unlock;
+ }
+
+ /*
+ * tb_schedule_hotplug_handler may be called as soon as the config
+ * channel is started. Thats why we have to hold the lock here.
+ */
+ tb_ctl_start(tb->ctl);
+
+ ret = device_add(&tb->dev);
+ if (ret)
+ goto err_ctl_stop;
+
+ /* Start the domain */
+ if (tb->cm_ops->start) {
+ ret = tb->cm_ops->start(tb);
+ if (ret)
+ goto err_domain_del;
+ }
+
+ /* This starts event processing */
+ mutex_unlock(&tb->lock);
+
+ return 0;
+
+err_domain_del:
+ device_del(&tb->dev);
+err_ctl_stop:
+ tb_ctl_stop(tb->ctl);
+err_unlock:
+ mutex_unlock(&tb->lock);
+
+ return ret;
+}
+
+/**
+ * tb_domain_remove() - Removes and releases a domain
+ * @tb: Domain to remove
+ *
+ * Stops the domain, removes it from the system and releases all
+ * resources once the last reference has been released.
+ */
+void tb_domain_remove(struct tb *tb)
+{
+ mutex_lock(&tb->lock);
+ if (tb->cm_ops->stop)
+ tb->cm_ops->stop(tb);
+ /* Stop the domain control traffic */
+ tb_ctl_stop(tb->ctl);
+ mutex_unlock(&tb->lock);
+
+ flush_workqueue(tb->wq);
+ device_unregister(&tb->dev);
+}
+
+/**
+ * tb_domain_suspend_noirq() - Suspend a domain
+ * @tb: Domain to suspend
+ *
+ * Suspends all devices in the domain and stops the control channel.
+ */
+int tb_domain_suspend_noirq(struct tb *tb)
+{
+ int ret = 0;
+
+ /*
+ * The control channel interrupt is left enabled during suspend
+ * and taking the lock here prevents any events happening before
+ * we actually have stopped the domain and the control channel.
+ */
+ mutex_lock(&tb->lock);
+ if (tb->cm_ops->suspend_noirq)
+ ret = tb->cm_ops->suspend_noirq(tb);
+ if (!ret)
+ tb_ctl_stop(tb->ctl);
+ mutex_unlock(&tb->lock);
+
+ return ret;
+}
+
+/**
+ * tb_domain_resume_noirq() - Resume a domain
+ * @tb: Domain to resume
+ *
+ * Re-starts the control channel, and resumes all devices connected to
+ * the domain.
+ */
+int tb_domain_resume_noirq(struct tb *tb)
+{
+ int ret = 0;
+
+ mutex_lock(&tb->lock);
+ tb_ctl_start(tb->ctl);
+ if (tb->cm_ops->resume_noirq)
+ ret = tb->cm_ops->resume_noirq(tb);
+ mutex_unlock(&tb->lock);
+
+ return ret;
+}
+
+int tb_domain_init(void)
+{
+ return bus_register(&tb_bus_type);
+}
+
+void tb_domain_exit(void)
+{
+ bus_unregister(&tb_bus_type);
+ ida_destroy(&tb_domain_ida);
+}
diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c
index ed75c49748f5..c1113a3c4128 100644
--- a/drivers/thunderbolt/nhi.c
+++ b/drivers/thunderbolt/nhi.c
@@ -586,16 +586,16 @@ static int nhi_suspend_noirq(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct tb *tb = pci_get_drvdata(pdev);
- thunderbolt_suspend(tb);
- return 0;
+
+ return tb_domain_suspend_noirq(tb);
}
static int nhi_resume_noirq(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct tb *tb = pci_get_drvdata(pdev);
- thunderbolt_resume(tb);
- return 0;
+
+ return tb_domain_resume_noirq(tb);
}
static void nhi_shutdown(struct tb_nhi *nhi)
@@ -715,12 +715,17 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
iowrite32(3906250 / 10000, nhi->iobase + 0x38c00);
dev_info(&nhi->pdev->dev, "NHI initialized, starting thunderbolt\n");
- tb = thunderbolt_alloc_and_start(nhi);
- if (!tb) {
+ tb = tb_probe(nhi);
+ if (!tb)
+ return -ENODEV;
+
+ res = tb_domain_add(tb);
+ if (res) {
/*
* At this point the RX/TX rings might already have been
* activated. Do a proper shutdown.
*/
+ tb_domain_put(tb);
nhi_shutdown(nhi);
return -EIO;
}
@@ -733,7 +738,8 @@ static void nhi_remove(struct pci_dev *pdev)
{
struct tb *tb = pci_get_drvdata(pdev);
struct tb_nhi *nhi = tb->nhi;
- thunderbolt_shutdown_and_free(tb);
+
+ tb_domain_remove(tb);
nhi_shutdown(nhi);
}
@@ -797,14 +803,23 @@ static struct pci_driver nhi_driver = {
static int __init nhi_init(void)
{
+ int ret;
+
if (!dmi_match(DMI_BOARD_VENDOR, "Apple Inc."))
return -ENOSYS;
- return pci_register_driver(&nhi_driver);
+ ret = tb_domain_init();
+ if (ret)
+ return ret;
+ ret = pci_register_driver(&nhi_driver);
+ if (ret)
+ tb_domain_exit();
+ return ret;
}
static void __exit nhi_unload(void)
{
pci_unregister_driver(&nhi_driver);
+ tb_domain_exit();
}
module_init(nhi_init);
diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
index 6b44076e1380..9f00a0f28d53 100644
--- a/drivers/thunderbolt/tb.c
+++ b/drivers/thunderbolt/tb.c
@@ -12,6 +12,18 @@
#include "tb_regs.h"
#include "tunnel_pci.h"
+/**
+ * struct tb_cm - Simple Thunderbolt connection manager
+ * @tunnel_list: List of active tunnels
+ * @hotplug_active: tb_handle_hotplug will stop progressing plug
+ * events and exit if this is not set (it needs to
+ * acquire the lock one more time). Used to drain wq
+ * after cfg has been paused.
+ */
+struct tb_cm {
+ struct list_head tunnel_list;
+ bool hotplug_active;
+};
/* enumeration & hot plug handling */
@@ -62,12 +74,14 @@ static void tb_scan_port(struct tb_port *port)
*/
static void tb_free_invalid_tunnels(struct tb *tb)
{
+ struct tb_cm *tcm = tb_priv(tb);
struct tb_pci_tunnel *tunnel;
struct tb_pci_tunnel *n;
- list_for_each_entry_safe(tunnel, n, &tb->tunnel_list, list)
- {
+
+ list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list) {
if (tb_pci_is_invalid(tunnel)) {
tb_pci_deactivate(tunnel);
+ list_del(&tunnel->list);
tb_pci_free(tunnel);
}
}
@@ -149,6 +163,8 @@ static void tb_activate_pcie_devices(struct tb *tb)
struct tb_port *up_port;
struct tb_port *down_port;
struct tb_pci_tunnel *tunnel;
+ struct tb_cm *tcm = tb_priv(tb);
+
/* scan for pcie devices at depth 1*/
for (i = 1; i <= tb->root_switch->config.max_port_number; i++) {
if (tb_is_upstream_port(&tb->root_switch->ports[i]))
@@ -195,6 +211,7 @@ static void tb_activate_pcie_devices(struct tb *tb)
tb_pci_free(tunnel);
}
+ list_add(&tunnel->list, &tcm->tunnel_list);
}
}
@@ -217,10 +234,11 @@ static void tb_handle_hotplug(struct work_struct *work)
{
struct tb_hotplug_event *ev = container_of(work, typeof(*ev), work);
struct tb *tb = ev->tb;
+ struct tb_cm *tcm = tb_priv(tb);
struct tb_switch *sw;
struct tb_port *port;
mutex_lock(&tb->lock);
- if (!tb->hotplug_active)
+ if (!tcm->hotplug_active)
goto out; /* during init, suspend or shutdown */
sw = get_switch_at_route(tb->root_switch, ev->route);
@@ -296,22 +314,14 @@ static void tb_schedule_hotplug_handler(void *data, u64 route, u8 port,
queue_work(tb->wq, &ev->work);
}
-/**
- * thunderbolt_shutdown_and_free() - shutdown everything
- *
- * Free all switches and the config channel.
- *
- * Used in the error path of thunderbolt_alloc_and_start.
- */
-void thunderbolt_shutdown_and_free(struct tb *tb)
+static void tb_stop(struct tb *tb)
{
+ struct tb_cm *tcm = tb_priv(tb);
struct tb_pci_tunnel *tunnel;
struct tb_pci_tunnel *n;
- mutex_lock(&tb->lock);
-
/* tunnels are only present after everything has been initialized */
- list_for_each_entry_safe(tunnel, n, &tb->tunnel_list, list) {
+ list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list) {
tb_pci_deactivate(tunnel);
tb_pci_free(tunnel);
}
@@ -320,98 +330,44 @@ void thunderbolt_shutdown_and_free(struct tb *tb)
tb_switch_free(tb->root_switch);
tb->root_switch = NULL;
- if (tb->ctl) {
- tb_ctl_stop(tb->ctl);
- tb_ctl_free(tb->ctl);
- }
- tb->ctl = NULL;
- tb->hotplug_active = false; /* signal tb_handle_hotplug to quit */
-
- /* allow tb_handle_hotplug to acquire the lock */
- mutex_unlock(&tb->lock);
- if (tb->wq) {
- flush_workqueue(tb->wq);
- destroy_workqueue(tb->wq);
- tb->wq = NULL;
- }
- mutex_destroy(&tb->lock);
- kfree(tb);
+ tcm->hotplug_active = false; /* signal tb_handle_hotplug to quit */
}
-/**
- * thunderbolt_alloc_and_start() - setup the thunderbolt bus
- *
- * Allocates a tb_cfg control channel, initializes the root switch, enables
- * plug events and activates pci devices.
- *
- * Return: Returns NULL on error.
- */
-struct tb *thunderbolt_alloc_and_start(struct tb_nhi *nhi)
+static int tb_start(struct tb *tb)
{
- struct tb *tb;
-
- BUILD_BUG_ON(sizeof(struct tb_regs_switch_header) != 5 * 4);
- BUILD_BUG_ON(sizeof(struct tb_regs_port_header) != 8 * 4);
- BUILD_BUG_ON(sizeof(struct tb_regs_hop) != 2 * 4);
-
- tb = kzalloc(sizeof(*tb), GFP_KERNEL);
- if (!tb)
- return NULL;
-
- tb->nhi = nhi;
- mutex_init(&tb->lock);
- mutex_lock(&tb->lock);
- INIT_LIST_HEAD(&tb->tunnel_list);
-
- tb->wq = alloc_ordered_workqueue("thunderbolt", 0);
- if (!tb->wq)
- goto err_locked;
-
- tb->ctl = tb_ctl_alloc(tb->nhi, tb_schedule_hotplug_handler, tb);
- if (!tb->ctl)
- goto err_locked;
- /*
- * tb_schedule_hotplug_handler may be called as soon as the config
- * channel is started. Thats why we have to hold the lock here.
- */
- tb_ctl_start(tb->ctl);
+ struct tb_cm *tcm = tb_priv(tb);
tb->root_switch = tb_switch_alloc(tb, 0);
if (!tb->root_switch)
- goto err_locked;
+ return -ENOMEM;
/* Full scan to discover devices added before the driver was loaded. */
tb_scan_switch(tb->root_switch);
tb_activate_pcie_devices(tb);
/* Allow tb_handle_hotplug to progress events */
- tb->hotplug_active = true;
- mutex_unlock(&tb->lock);
- return tb;
-
-err_locked:
- mutex_unlock(&tb->lock);
- thunderbolt_shutdown_and_free(tb);
- return NULL;
+ tcm->hotplug_active = true;
+ return 0;
}
-void thunderbolt_suspend(struct tb *tb)
+static int tb_suspend_noirq(struct tb *tb)
{
+ struct tb_cm *tcm = tb_priv(tb);
+
tb_info(tb, "suspending...\n");
- mutex_lock(&tb->lock);
tb_switch_suspend(tb->root_switch);
- tb_ctl_stop(tb->ctl);
- tb->hotplug_active = false; /* signal tb_handle_hotplug to quit */
- mutex_unlock(&tb->lock);
+ tcm->hotplug_active = false; /* signal tb_handle_hotplug to quit */
tb_info(tb, "suspend finished\n");
+
+ return 0;
}
-void thunderbolt_resume(struct tb *tb)
+static int tb_resume_noirq(struct tb *tb)
{
+ struct tb_cm *tcm = tb_priv(tb);
struct tb_pci_tunnel *tunnel, *n;
+
tb_info(tb, "resuming...\n");
- mutex_lock(&tb->lock);
- tb_ctl_start(tb->ctl);
/* remove any pci devices the firmware might have setup */
tb_switch_reset(tb, 0);
@@ -419,9 +375,9 @@ void thunderbolt_resume(struct tb *tb)
tb_switch_resume(tb->root_switch);
tb_free_invalid_tunnels(tb);
tb_free_unplugged_children(tb->root_switch);
- list_for_each_entry_safe(tunnel, n, &tb->tunnel_list, list)
+ list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list)
tb_pci_restart(tunnel);
- if (!list_empty(&tb->tunnel_list)) {
+ if (!list_empty(&tcm->tunnel_list)) {
/*
* the pcie links need some time to get going.
* 100ms works for me...
@@ -430,7 +386,33 @@ void thunderbolt_resume(struct tb *tb)
msleep(100);
}
/* Allow tb_handle_hotplug to progress events */
- tb->hotplug_active = true;
- mutex_unlock(&tb->lock);
+ tcm->hotplug_active = true;
tb_info(tb, "resume finished\n");
+
+ return 0;
+}
+
+static const struct tb_cm_ops tb_cm_ops = {
+ .start = tb_start,
+ .stop = tb_stop,
+ .suspend_noirq = tb_suspend_noirq,
+ .resume_noirq = tb_resume_noirq,
+ .hotplug = tb_schedule_hotplug_handler,
+};
+
+struct tb *tb_probe(struct tb_nhi *nhi)
+{
+ struct tb_cm *tcm;
+ struct tb *tb;
+
+ tb = tb_domain_alloc(nhi, sizeof(*tcm));
+ if (!tb)
+ return NULL;
+
+ tb->cm_ops = &tb_cm_ops;
+
+ tcm = tb_priv(tb);
+ INIT_LIST_HEAD(&tcm->tunnel_list);
+
+ return tb;
}
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
index 9b60e71562dc..ce9db64e3333 100644
--- a/drivers/thunderbolt/tb.h
+++ b/drivers/thunderbolt/tb.h
@@ -92,29 +92,52 @@ struct tb_path {
int path_length; /* number of hops */
};
+/**
+ * struct tb_cm_ops - Connection manager specific operations vector
+ * @start: Starts the domain
+ * @stop: Stops the domain
+ * @suspend_noirq: Connection manager specific suspend_noirq
+ * @resume_noirq: Connection manager specific resume_noirq
+ * @hotplug: Handle hotplug event
+ */
+struct tb_cm_ops {
+ int (*start)(struct tb *tb);
+ void (*stop)(struct tb *tb);
+ int (*suspend_noirq)(struct tb *tb);
+ int (*resume_noirq)(struct tb *tb);
+ hotplug_cb hotplug;
+};
/**
* struct tb - main thunderbolt bus structure
+ * @dev: Domain device
+ * @lock: Big lock. Must be held when accessing cfg or any struct
+ * tb_switch / struct tb_port.
+ * @nhi: Pointer to the NHI structure
+ * @ctl: Control channel for this domain
+ * @wq: Ordered workqueue for all domain specific work
+ * @root_switch: Root switch of this domain
+ * @cm_ops: Connection manager specific operations vector
+ * @index: Linux assigned domain number
+ * @privdata: Private connection manager specific data
*/
struct tb {
- struct mutex lock; /*
- * Big lock. Must be held when accessing cfg or
- * any struct tb_switch / struct tb_port.
- */
+ struct device dev;
+ struct mutex lock;
struct tb_nhi *nhi;
struct tb_ctl *ctl;
- struct workqueue_struct *wq; /* ordered workqueue for plug events */
+ struct workqueue_struct *wq;
struct tb_switch *root_switch;
- struct list_head tunnel_list; /* list of active PCIe tunnels */
- bool hotplug_active; /*
- * tb_handle_hotplug will stop progressing plug
- * events and exit if this is not set (it needs to
- * acquire the lock one more time). Used to drain
- * wq after cfg has been paused.
- */
-
+ const struct tb_cm_ops *cm_ops;
+ int index;
+ unsigned long privdata[0];
};
+static inline void *tb_priv(struct tb *tb)
+{
+ return (void *)tb->privdata;
+}
+
/* helper functions & macros */
/**
@@ -215,11 +238,24 @@ static inline int tb_port_write(struct tb_port *port, const void *buffer,
#define tb_port_info(port, fmt, arg...) \
__TB_PORT_PRINT(tb_info, port, fmt, ##arg)
+struct tb *tb_probe(struct tb_nhi *nhi);
+
+extern struct bus_type tb_bus_type;
+extern struct device_type tb_domain_type;
+
+int tb_domain_init(void);
+void tb_domain_exit(void);
-struct tb *thunderbolt_alloc_and_start(struct tb_nhi *nhi);
-void thunderbolt_shutdown_and_free(struct tb *tb);
-void thunderbolt_suspend(struct tb *tb);
-void thunderbolt_resume(struct tb *tb);
+struct tb *tb_domain_alloc(struct tb_nhi *nhi, size_t privsize);
+int tb_domain_add(struct tb *tb);
+void tb_domain_remove(struct tb *tb);
+int tb_domain_suspend_noirq(struct tb *tb);
+int tb_domain_resume_noirq(struct tb *tb);
+
+static inline void tb_domain_put(struct tb *tb)
+{
+ put_device(&tb->dev);
+}
struct tb_switch *tb_switch_alloc(struct tb *tb, u64 route);
void tb_switch_free(struct tb_switch *sw);
diff --git a/drivers/thunderbolt/tunnel_pci.c b/drivers/thunderbolt/tunnel_pci.c
index f4ce9845e42a..ca4475907d7a 100644
--- a/drivers/thunderbolt/tunnel_pci.c
+++ b/drivers/thunderbolt/tunnel_pci.c
@@ -194,19 +194,13 @@ int tb_pci_restart(struct tb_pci_tunnel *tunnel)
*/
int tb_pci_activate(struct tb_pci_tunnel *tunnel)
{
- int res;
if (tunnel->path_to_up->activated || tunnel->path_to_down->activated) {
tb_tunnel_WARN(tunnel,
"trying to activate an already activated tunnel\n");
return -EINVAL;
}
- res = tb_pci_restart(tunnel);
- if (res)
- return res;
-
- list_add(&tunnel->list, &tunnel->tb->tunnel_list);
- return 0;
+ return tb_pci_restart(tunnel);
}
@@ -227,6 +221,5 @@ void tb_pci_deactivate(struct tb_pci_tunnel *tunnel)
tb_path_deactivate(tunnel->path_to_down);
if (tunnel->path_to_up->activated)
tb_path_deactivate(tunnel->path_to_up);
- list_del_init(&tunnel->list);
}
--
2.11.0
[toc] | [prev] | [next] | [standalone]
| From | Andreas Noever <andreas.noever@gmail.com> |
|---|---|
| Date | 2017-06-05 17:20 +0200 |
| Subject | Re: [PATCH v3 08/27] thunderbolt: Introduce thunderbolt bus and connection manager |
| Message-ID | <tP1Xr-4zX-3@gated-at.bofh.it> |
| In reply to | #1656266 |
On Fri, Jun 2, 2017 at 4:05 PM, Mika Westerberg
<mika.westerberg@linux.intel.com> wrote:
> Thunderbolt fabric consists of one or more switches. This fabric is
> called domain and it is controlled by an entity called connection
> manager. The connection manager can be either internal (driven by a
> firmware running on the host controller) or external (software driver).
> This driver currently implements support for the latter.
>
> In order to manage switches and their properties more easily we model
> this domain structure as a Linux bus. Each host controller adds a domain
> device to this bus, and these devices are named as domainN where N
> stands for index or id of the current domain.
>
> We then abstract connection manager specific operations into a new
> structure tb_cm_ops and convert the existing tb.c to fill those
> accordingly. This makes it easier to add support for the internal
> connection manager in subsequent patches.
>
> Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
> Reviewed-by: Yehezkel Bernat <yehezkel.bernat@intel.com>
> Reviewed-by: Michael Jamet <michael.jamet@intel.com>
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
> drivers/thunderbolt/Makefile | 2 +-
> drivers/thunderbolt/domain.c | 229 +++++++++++++++++++++++++++++++++++++++
> drivers/thunderbolt/nhi.c | 31 ++++--
> drivers/thunderbolt/tb.c | 156 ++++++++++++--------------
> drivers/thunderbolt/tb.h | 70 +++++++++---
> drivers/thunderbolt/tunnel_pci.c | 9 +-
> 6 files changed, 376 insertions(+), 121 deletions(-)
> create mode 100644 drivers/thunderbolt/domain.c
>
> diff --git a/drivers/thunderbolt/Makefile b/drivers/thunderbolt/Makefile
> index 5d1053cdfa54..e276a9a62261 100644
> --- a/drivers/thunderbolt/Makefile
> +++ b/drivers/thunderbolt/Makefile
> @@ -1,3 +1,3 @@
> obj-${CONFIG_THUNDERBOLT} := thunderbolt.o
> thunderbolt-objs := nhi.o ctl.o tb.o switch.o cap.o path.o tunnel_pci.o eeprom.o
> -
> +thunderbolt-objs += domain.o
> diff --git a/drivers/thunderbolt/domain.c b/drivers/thunderbolt/domain.c
> new file mode 100644
> index 000000000000..e2f3777edee6
> --- /dev/null
> +++ b/drivers/thunderbolt/domain.c
> @@ -0,0 +1,229 @@
> +/*
> + * Thunderbolt bus support
> + *
> + * Copyright (C) 2017, Intel Corporation
> + * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/idr.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +
> +#include "tb.h"
> +
> +static DEFINE_IDA(tb_domain_ida);
> +
> +struct bus_type tb_bus_type = {
> + .name = "thunderbolt",
> +};
> +
> +static void tb_domain_release(struct device *dev)
> +{
> + struct tb *tb = container_of(dev, struct tb, dev);
> +
> + tb_ctl_free(tb->ctl);
> + destroy_workqueue(tb->wq);
> + ida_simple_remove(&tb_domain_ida, tb->index);
> + kfree(tb);
> +}
> +
> +struct device_type tb_domain_type = {
> + .name = "thunderbolt_domain",
> + .release = tb_domain_release,
> +};
> +
> +/**
> + * tb_domain_alloc() - Allocate a domain
> + * @nhi: Pointer to the host controller
> + * @privsize: Size of the connection manager private data
> + *
> + * Allocates and initializes a new Thunderbolt domain. Connection
> + * managers are expected to call this and then fill in @cm_ops
> + * accordingly.
> + *
> + * Call tb_domain_put() to release the domain before it has been added
> + * to the system.
> + *
> + * Return: allocated domain structure on %NULL in case of error
> + */
> +struct tb *tb_domain_alloc(struct tb_nhi *nhi, size_t privsize)
> +{
> + struct tb *tb;
> +
> + /*
> + * Make sure the structure sizes map with that the hardware
> + * expects because bit-fields are being used.
> + */
> + BUILD_BUG_ON(sizeof(struct tb_regs_switch_header) != 5 * 4);
> + BUILD_BUG_ON(sizeof(struct tb_regs_port_header) != 8 * 4);
> + BUILD_BUG_ON(sizeof(struct tb_regs_hop) != 2 * 4);
> +
> + tb = kzalloc(sizeof(*tb) + privsize, GFP_KERNEL);
> + if (!tb)
> + return NULL;
> +
> + tb->nhi = nhi;
> + mutex_init(&tb->lock);
> +
> + tb->index = ida_simple_get(&tb_domain_ida, 0, 0, GFP_KERNEL);
> + if (tb->index < 0)
> + goto err_free;
> +
> + tb->wq = alloc_ordered_workqueue("thunderbolt%d", 0, tb->index);
> + if (!tb->wq)
> + goto err_remove_ida;
> +
> + tb->dev.parent = &nhi->pdev->dev;
> + tb->dev.bus = &tb_bus_type;
> + tb->dev.type = &tb_domain_type;
> + dev_set_name(&tb->dev, "domain%d", tb->index);
> + device_initialize(&tb->dev);
> +
> + return tb;
> +
> +err_remove_ida:
> + ida_simple_remove(&tb_domain_ida, tb->index);
> +err_free:
> + kfree(tb);
> +
> + return NULL;
> +}
> +
> +/**
> + * tb_domain_add() - Add domain to the system
> + * @tb: Domain to add
> + *
> + * Starts the domain and adds it to the system. Hotplugging devices will
> + * work after this has been returned successfully. In order to remove
> + * and release the domain after this function has been called, call
> + * tb_domain_remove().
> + *
> + * Return: %0 in case of success and negative errno in case of error
> + */
> +int tb_domain_add(struct tb *tb)
> +{
> + int ret;
> +
> + if (WARN_ON(!tb->cm_ops))
> + return -EINVAL;
> +
> + mutex_lock(&tb->lock);
> +
> + tb->ctl = tb_ctl_alloc(tb->nhi, tb->cm_ops->hotplug, tb);
> + if (!tb->ctl) {
> + ret = -ENOMEM;
> + goto err_unlock;
> + }
> +
> + /*
> + * tb_schedule_hotplug_handler may be called as soon as the config
> + * channel is started. Thats why we have to hold the lock here.
> + */
> + tb_ctl_start(tb->ctl);
> +
> + ret = device_add(&tb->dev);
> + if (ret)
> + goto err_ctl_stop;
> +
> + /* Start the domain */
> + if (tb->cm_ops->start) {
> + ret = tb->cm_ops->start(tb);
> + if (ret)
> + goto err_domain_del;
> + }
> +
> + /* This starts event processing */
> + mutex_unlock(&tb->lock);
> +
> + return 0;
> +
> +err_domain_del:
> + device_del(&tb->dev);
> +err_ctl_stop:
> + tb_ctl_stop(tb->ctl);
> +err_unlock:
> + mutex_unlock(&tb->lock);
> +
> + return ret;
> +}
> +
> +/**
> + * tb_domain_remove() - Removes and releases a domain
> + * @tb: Domain to remove
> + *
> + * Stops the domain, removes it from the system and releases all
> + * resources once the last reference has been released.
> + */
> +void tb_domain_remove(struct tb *tb)
> +{
> + mutex_lock(&tb->lock);
> + if (tb->cm_ops->stop)
> + tb->cm_ops->stop(tb);
> + /* Stop the domain control traffic */
> + tb_ctl_stop(tb->ctl);
> + mutex_unlock(&tb->lock);
> +
> + flush_workqueue(tb->wq);
> + device_unregister(&tb->dev);
> +}
> +
> +/**
> + * tb_domain_suspend_noirq() - Suspend a domain
> + * @tb: Domain to suspend
> + *
> + * Suspends all devices in the domain and stops the control channel.
> + */
> +int tb_domain_suspend_noirq(struct tb *tb)
> +{
> + int ret = 0;
> +
> + /*
> + * The control channel interrupt is left enabled during suspend
> + * and taking the lock here prevents any events happening before
> + * we actually have stopped the domain and the control channel.
> + */
> + mutex_lock(&tb->lock);
> + if (tb->cm_ops->suspend_noirq)
> + ret = tb->cm_ops->suspend_noirq(tb);
> + if (!ret)
> + tb_ctl_stop(tb->ctl);
> + mutex_unlock(&tb->lock);
> +
> + return ret;
> +}
> +
> +/**
> + * tb_domain_resume_noirq() - Resume a domain
> + * @tb: Domain to resume
> + *
> + * Re-starts the control channel, and resumes all devices connected to
> + * the domain.
> + */
> +int tb_domain_resume_noirq(struct tb *tb)
> +{
> + int ret = 0;
> +
> + mutex_lock(&tb->lock);
> + tb_ctl_start(tb->ctl);
> + if (tb->cm_ops->resume_noirq)
> + ret = tb->cm_ops->resume_noirq(tb);
> + mutex_unlock(&tb->lock);
> +
> + return ret;
> +}
> +
> +int tb_domain_init(void)
> +{
> + return bus_register(&tb_bus_type);
> +}
> +
> +void tb_domain_exit(void)
> +{
> + bus_unregister(&tb_bus_type);
> + ida_destroy(&tb_domain_ida);
> +}
> diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c
> index ed75c49748f5..c1113a3c4128 100644
> --- a/drivers/thunderbolt/nhi.c
> +++ b/drivers/thunderbolt/nhi.c
> @@ -586,16 +586,16 @@ static int nhi_suspend_noirq(struct device *dev)
> {
> struct pci_dev *pdev = to_pci_dev(dev);
> struct tb *tb = pci_get_drvdata(pdev);
> - thunderbolt_suspend(tb);
> - return 0;
> +
> + return tb_domain_suspend_noirq(tb);
> }
>
> static int nhi_resume_noirq(struct device *dev)
> {
> struct pci_dev *pdev = to_pci_dev(dev);
> struct tb *tb = pci_get_drvdata(pdev);
> - thunderbolt_resume(tb);
> - return 0;
> +
> + return tb_domain_resume_noirq(tb);
> }
>
> static void nhi_shutdown(struct tb_nhi *nhi)
> @@ -715,12 +715,17 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> iowrite32(3906250 / 10000, nhi->iobase + 0x38c00);
>
> dev_info(&nhi->pdev->dev, "NHI initialized, starting thunderbolt\n");
> - tb = thunderbolt_alloc_and_start(nhi);
> - if (!tb) {
> + tb = tb_probe(nhi);
> + if (!tb)
> + return -ENODEV;
> +
> + res = tb_domain_add(tb);
> + if (res) {
> /*
> * At this point the RX/TX rings might already have been
> * activated. Do a proper shutdown.
> */
> + tb_domain_put(tb);
> nhi_shutdown(nhi);
> return -EIO;
> }
> @@ -733,7 +738,8 @@ static void nhi_remove(struct pci_dev *pdev)
> {
> struct tb *tb = pci_get_drvdata(pdev);
> struct tb_nhi *nhi = tb->nhi;
> - thunderbolt_shutdown_and_free(tb);
> +
> + tb_domain_remove(tb);
> nhi_shutdown(nhi);
> }
>
> @@ -797,14 +803,23 @@ static struct pci_driver nhi_driver = {
>
> static int __init nhi_init(void)
> {
> + int ret;
> +
> if (!dmi_match(DMI_BOARD_VENDOR, "Apple Inc."))
> return -ENOSYS;
> - return pci_register_driver(&nhi_driver);
> + ret = tb_domain_init();
> + if (ret)
> + return ret;
> + ret = pci_register_driver(&nhi_driver);
> + if (ret)
> + tb_domain_exit();
> + return ret;
> }
>
> static void __exit nhi_unload(void)
> {
> pci_unregister_driver(&nhi_driver);
> + tb_domain_exit();
> }
>
> module_init(nhi_init);
> diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
> index 6b44076e1380..9f00a0f28d53 100644
> --- a/drivers/thunderbolt/tb.c
> +++ b/drivers/thunderbolt/tb.c
> @@ -12,6 +12,18 @@
> #include "tb_regs.h"
> #include "tunnel_pci.h"
>
> +/**
> + * struct tb_cm - Simple Thunderbolt connection manager
> + * @tunnel_list: List of active tunnels
> + * @hotplug_active: tb_handle_hotplug will stop progressing plug
> + * events and exit if this is not set (it needs to
> + * acquire the lock one more time). Used to drain wq
> + * after cfg has been paused.
> + */
> +struct tb_cm {
> + struct list_head tunnel_list;
> + bool hotplug_active;
> +};
>
> /* enumeration & hot plug handling */
>
> @@ -62,12 +74,14 @@ static void tb_scan_port(struct tb_port *port)
> */
> static void tb_free_invalid_tunnels(struct tb *tb)
> {
> + struct tb_cm *tcm = tb_priv(tb);
> struct tb_pci_tunnel *tunnel;
> struct tb_pci_tunnel *n;
> - list_for_each_entry_safe(tunnel, n, &tb->tunnel_list, list)
> - {
> +
> + list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list) {
> if (tb_pci_is_invalid(tunnel)) {
> tb_pci_deactivate(tunnel);
> + list_del(&tunnel->list);
> tb_pci_free(tunnel);
> }
> }
> @@ -149,6 +163,8 @@ static void tb_activate_pcie_devices(struct tb *tb)
> struct tb_port *up_port;
> struct tb_port *down_port;
> struct tb_pci_tunnel *tunnel;
> + struct tb_cm *tcm = tb_priv(tb);
> +
> /* scan for pcie devices at depth 1*/
> for (i = 1; i <= tb->root_switch->config.max_port_number; i++) {
> if (tb_is_upstream_port(&tb->root_switch->ports[i]))
> @@ -195,6 +211,7 @@ static void tb_activate_pcie_devices(struct tb *tb)
> tb_pci_free(tunnel);
> }
>
> + list_add(&tunnel->list, &tcm->tunnel_list);
> }
> }
>
> @@ -217,10 +234,11 @@ static void tb_handle_hotplug(struct work_struct *work)
> {
> struct tb_hotplug_event *ev = container_of(work, typeof(*ev), work);
> struct tb *tb = ev->tb;
> + struct tb_cm *tcm = tb_priv(tb);
> struct tb_switch *sw;
> struct tb_port *port;
> mutex_lock(&tb->lock);
> - if (!tb->hotplug_active)
> + if (!tcm->hotplug_active)
> goto out; /* during init, suspend or shutdown */
>
> sw = get_switch_at_route(tb->root_switch, ev->route);
> @@ -296,22 +314,14 @@ static void tb_schedule_hotplug_handler(void *data, u64 route, u8 port,
> queue_work(tb->wq, &ev->work);
> }
>
> -/**
> - * thunderbolt_shutdown_and_free() - shutdown everything
> - *
> - * Free all switches and the config channel.
> - *
> - * Used in the error path of thunderbolt_alloc_and_start.
> - */
> -void thunderbolt_shutdown_and_free(struct tb *tb)
> +static void tb_stop(struct tb *tb)
> {
> + struct tb_cm *tcm = tb_priv(tb);
> struct tb_pci_tunnel *tunnel;
> struct tb_pci_tunnel *n;
>
> - mutex_lock(&tb->lock);
> -
> /* tunnels are only present after everything has been initialized */
> - list_for_each_entry_safe(tunnel, n, &tb->tunnel_list, list) {
> + list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list) {
> tb_pci_deactivate(tunnel);
> tb_pci_free(tunnel);
> }
> @@ -320,98 +330,44 @@ void thunderbolt_shutdown_and_free(struct tb *tb)
> tb_switch_free(tb->root_switch);
> tb->root_switch = NULL;
>
> - if (tb->ctl) {
> - tb_ctl_stop(tb->ctl);
> - tb_ctl_free(tb->ctl);
> - }
> - tb->ctl = NULL;
> - tb->hotplug_active = false; /* signal tb_handle_hotplug to quit */
> -
> - /* allow tb_handle_hotplug to acquire the lock */
> - mutex_unlock(&tb->lock);
> - if (tb->wq) {
> - flush_workqueue(tb->wq);
> - destroy_workqueue(tb->wq);
> - tb->wq = NULL;
> - }
> - mutex_destroy(&tb->lock);
This seems to have been lost.
> - kfree(tb);
> + tcm->hotplug_active = false; /* signal tb_handle_hotplug to quit */
> }
>
> -/**
> - * thunderbolt_alloc_and_start() - setup the thunderbolt bus
> - *
> - * Allocates a tb_cfg control channel, initializes the root switch, enables
> - * plug events and activates pci devices.
> - *
> - * Return: Returns NULL on error.
> - */
> -struct tb *thunderbolt_alloc_and_start(struct tb_nhi *nhi)
> +static int tb_start(struct tb *tb)
> {
> - struct tb *tb;
> -
> - BUILD_BUG_ON(sizeof(struct tb_regs_switch_header) != 5 * 4);
> - BUILD_BUG_ON(sizeof(struct tb_regs_port_header) != 8 * 4);
> - BUILD_BUG_ON(sizeof(struct tb_regs_hop) != 2 * 4);
> -
> - tb = kzalloc(sizeof(*tb), GFP_KERNEL);
> - if (!tb)
> - return NULL;
> -
> - tb->nhi = nhi;
> - mutex_init(&tb->lock);
> - mutex_lock(&tb->lock);
> - INIT_LIST_HEAD(&tb->tunnel_list);
> -
> - tb->wq = alloc_ordered_workqueue("thunderbolt", 0);
> - if (!tb->wq)
> - goto err_locked;
> -
> - tb->ctl = tb_ctl_alloc(tb->nhi, tb_schedule_hotplug_handler, tb);
> - if (!tb->ctl)
> - goto err_locked;
> - /*
> - * tb_schedule_hotplug_handler may be called as soon as the config
> - * channel is started. Thats why we have to hold the lock here.
> - */
> - tb_ctl_start(tb->ctl);
> + struct tb_cm *tcm = tb_priv(tb);
>
> tb->root_switch = tb_switch_alloc(tb, 0);
> if (!tb->root_switch)
> - goto err_locked;
> + return -ENOMEM;
>
> /* Full scan to discover devices added before the driver was loaded. */
> tb_scan_switch(tb->root_switch);
> tb_activate_pcie_devices(tb);
>
> /* Allow tb_handle_hotplug to progress events */
> - tb->hotplug_active = true;
> - mutex_unlock(&tb->lock);
> - return tb;
> -
> -err_locked:
> - mutex_unlock(&tb->lock);
> - thunderbolt_shutdown_and_free(tb);
> - return NULL;
> + tcm->hotplug_active = true;
> + return 0;
> }
>
> -void thunderbolt_suspend(struct tb *tb)
> +static int tb_suspend_noirq(struct tb *tb)
> {
> + struct tb_cm *tcm = tb_priv(tb);
> +
> tb_info(tb, "suspending...\n");
> - mutex_lock(&tb->lock);
> tb_switch_suspend(tb->root_switch);
> - tb_ctl_stop(tb->ctl);
> - tb->hotplug_active = false; /* signal tb_handle_hotplug to quit */
> - mutex_unlock(&tb->lock);
> + tcm->hotplug_active = false; /* signal tb_handle_hotplug to quit */
> tb_info(tb, "suspend finished\n");
> +
> + return 0;
> }
>
> -void thunderbolt_resume(struct tb *tb)
> +static int tb_resume_noirq(struct tb *tb)
> {
> + struct tb_cm *tcm = tb_priv(tb);
> struct tb_pci_tunnel *tunnel, *n;
> +
> tb_info(tb, "resuming...\n");
> - mutex_lock(&tb->lock);
> - tb_ctl_start(tb->ctl);
>
> /* remove any pci devices the firmware might have setup */
> tb_switch_reset(tb, 0);
> @@ -419,9 +375,9 @@ void thunderbolt_resume(struct tb *tb)
> tb_switch_resume(tb->root_switch);
> tb_free_invalid_tunnels(tb);
> tb_free_unplugged_children(tb->root_switch);
> - list_for_each_entry_safe(tunnel, n, &tb->tunnel_list, list)
> + list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list)
> tb_pci_restart(tunnel);
> - if (!list_empty(&tb->tunnel_list)) {
> + if (!list_empty(&tcm->tunnel_list)) {
> /*
> * the pcie links need some time to get going.
> * 100ms works for me...
> @@ -430,7 +386,33 @@ void thunderbolt_resume(struct tb *tb)
> msleep(100);
> }
> /* Allow tb_handle_hotplug to progress events */
> - tb->hotplug_active = true;
> - mutex_unlock(&tb->lock);
> + tcm->hotplug_active = true;
> tb_info(tb, "resume finished\n");
> +
> + return 0;
> +}
> +
> +static const struct tb_cm_ops tb_cm_ops = {
> + .start = tb_start,
> + .stop = tb_stop,
> + .suspend_noirq = tb_suspend_noirq,
> + .resume_noirq = tb_resume_noirq,
> + .hotplug = tb_schedule_hotplug_handler,
> +};
> +
> +struct tb *tb_probe(struct tb_nhi *nhi)
> +{
> + struct tb_cm *tcm;
> + struct tb *tb;
> +
> + tb = tb_domain_alloc(nhi, sizeof(*tcm));
> + if (!tb)
> + return NULL;
> +
> + tb->cm_ops = &tb_cm_ops;
> +
> + tcm = tb_priv(tb);
> + INIT_LIST_HEAD(&tcm->tunnel_list);
> +
> + return tb;
> }
> diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
> index 9b60e71562dc..ce9db64e3333 100644
> --- a/drivers/thunderbolt/tb.h
> +++ b/drivers/thunderbolt/tb.h
> @@ -92,29 +92,52 @@ struct tb_path {
> int path_length; /* number of hops */
> };
>
> +/**
> + * struct tb_cm_ops - Connection manager specific operations vector
> + * @start: Starts the domain
> + * @stop: Stops the domain
> + * @suspend_noirq: Connection manager specific suspend_noirq
> + * @resume_noirq: Connection manager specific resume_noirq
> + * @hotplug: Handle hotplug event
> + */
> +struct tb_cm_ops {
> + int (*start)(struct tb *tb);
> + void (*stop)(struct tb *tb);
> + int (*suspend_noirq)(struct tb *tb);
> + int (*resume_noirq)(struct tb *tb);
> + hotplug_cb hotplug;
> +};
>
> /**
> * struct tb - main thunderbolt bus structure
> + * @dev: Domain device
> + * @lock: Big lock. Must be held when accessing cfg or any struct
> + * tb_switch / struct tb_port.
> + * @nhi: Pointer to the NHI structure
> + * @ctl: Control channel for this domain
> + * @wq: Ordered workqueue for all domain specific work
> + * @root_switch: Root switch of this domain
> + * @cm_ops: Connection manager specific operations vector
> + * @index: Linux assigned domain number
> + * @privdata: Private connection manager specific data
> */
> struct tb {
> - struct mutex lock; /*
> - * Big lock. Must be held when accessing cfg or
> - * any struct tb_switch / struct tb_port.
> - */
> + struct device dev;
> + struct mutex lock;
> struct tb_nhi *nhi;
> struct tb_ctl *ctl;
> - struct workqueue_struct *wq; /* ordered workqueue for plug events */
> + struct workqueue_struct *wq;
> struct tb_switch *root_switch;
> - struct list_head tunnel_list; /* list of active PCIe tunnels */
> - bool hotplug_active; /*
> - * tb_handle_hotplug will stop progressing plug
> - * events and exit if this is not set (it needs to
> - * acquire the lock one more time). Used to drain
> - * wq after cfg has been paused.
> - */
> -
> + const struct tb_cm_ops *cm_ops;
> + int index;
> + unsigned long privdata[0];
> };
>
> +static inline void *tb_priv(struct tb *tb)
> +{
> + return (void *)tb->privdata;
> +}
> +
> /* helper functions & macros */
>
> /**
> @@ -215,11 +238,24 @@ static inline int tb_port_write(struct tb_port *port, const void *buffer,
> #define tb_port_info(port, fmt, arg...) \
> __TB_PORT_PRINT(tb_info, port, fmt, ##arg)
>
> +struct tb *tb_probe(struct tb_nhi *nhi);
> +
> +extern struct bus_type tb_bus_type;
> +extern struct device_type tb_domain_type;
> +
> +int tb_domain_init(void);
> +void tb_domain_exit(void);
>
> -struct tb *thunderbolt_alloc_and_start(struct tb_nhi *nhi);
> -void thunderbolt_shutdown_and_free(struct tb *tb);
> -void thunderbolt_suspend(struct tb *tb);
> -void thunderbolt_resume(struct tb *tb);
> +struct tb *tb_domain_alloc(struct tb_nhi *nhi, size_t privsize);
> +int tb_domain_add(struct tb *tb);
> +void tb_domain_remove(struct tb *tb);
> +int tb_domain_suspend_noirq(struct tb *tb);
> +int tb_domain_resume_noirq(struct tb *tb);
> +
> +static inline void tb_domain_put(struct tb *tb)
> +{
> + put_device(&tb->dev);
> +}
>
> struct tb_switch *tb_switch_alloc(struct tb *tb, u64 route);
> void tb_switch_free(struct tb_switch *sw);
> diff --git a/drivers/thunderbolt/tunnel_pci.c b/drivers/thunderbolt/tunnel_pci.c
> index f4ce9845e42a..ca4475907d7a 100644
> --- a/drivers/thunderbolt/tunnel_pci.c
> +++ b/drivers/thunderbolt/tunnel_pci.c
> @@ -194,19 +194,13 @@ int tb_pci_restart(struct tb_pci_tunnel *tunnel)
> */
> int tb_pci_activate(struct tb_pci_tunnel *tunnel)
> {
> - int res;
> if (tunnel->path_to_up->activated || tunnel->path_to_down->activated) {
> tb_tunnel_WARN(tunnel,
> "trying to activate an already activated tunnel\n");
> return -EINVAL;
> }
>
> - res = tb_pci_restart(tunnel);
> - if (res)
> - return res;
> -
> - list_add(&tunnel->list, &tunnel->tb->tunnel_list);
> - return 0;
> + return tb_pci_restart(tunnel);
> }
>
>
> @@ -227,6 +221,5 @@ void tb_pci_deactivate(struct tb_pci_tunnel *tunnel)
> tb_path_deactivate(tunnel->path_to_down);
> if (tunnel->path_to_up->activated)
> tb_path_deactivate(tunnel->path_to_up);
> - list_del_init(&tunnel->list);
> }
>
> --
> 2.11.0
>
[toc] | [prev] | [next] | [standalone]
| From | Mika Westerberg <mika.westerberg@linux.intel.com> |
|---|---|
| Date | 2017-06-02 16:20 +0200 |
| Subject | [PATCH v3 02/27] thunderbolt: No need to read UID of the root switch on resume |
| Message-ID | <tNVAK-2ht-7@gated-at.bofh.it> |
| In reply to | #1656243 |
The root switch is part of the host controller and cannot be physically
removed, so there is no point of reading UID again on resume in order to
check if the root switch is still the same.
Suggested-by: Andreas Noever <andreas.noever@gmail.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
drivers/thunderbolt/switch.c | 29 ++++++++++++++++++-----------
1 file changed, 18 insertions(+), 11 deletions(-)
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index c6f30b1695a9..81f5164a6364 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -452,19 +452,26 @@ void tb_sw_set_unplugged(struct tb_switch *sw)
int tb_switch_resume(struct tb_switch *sw)
{
int i, err;
- u64 uid;
tb_sw_info(sw, "resuming switch\n");
- err = tb_drom_read_uid_only(sw, &uid);
- if (err) {
- tb_sw_warn(sw, "uid read failed\n");
- return err;
- }
- if (sw != sw->tb->root_switch && sw->uid != uid) {
- tb_sw_info(sw,
- "changed while suspended (uid %#llx -> %#llx)\n",
- sw->uid, uid);
- return -ENODEV;
+ /*
+ * Check for UID of the connected switches except for root
+ * switch which we assume cannot be removed.
+ */
+ if (tb_route(sw)) {
+ u64 uid;
+
+ err = tb_drom_read_uid_only(sw, &uid);
+ if (err) {
+ tb_sw_warn(sw, "uid read failed\n");
+ return err;
+ }
+ if (sw->uid != uid) {
+ tb_sw_info(sw,
+ "changed while suspended (uid %#llx -> %#llx)\n",
+ sw->uid, uid);
+ return -ENODEV;
+ }
}
/* upload configuration */
--
2.11.0
[toc] | [prev] | [next] | [standalone]
| From | Mika Westerberg <mika.westerberg@linux.intel.com> |
|---|---|
| Date | 2017-06-02 16:20 +0200 |
| Subject | [PATCH v3 14/27] thunderbolt: Move control channel messages to tb_msgs.h |
| Message-ID | <tNVAK-2ht-11@gated-at.bofh.it> |
| In reply to | #1656243 |
We will be forwarding notifications received from the control channel to
the connection manager implementations. This way they can decide what to
do if anything when a notification is received.
To be able to use control channel messages from other files, move them
to tb_msgs.h.
No functional changes intended.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Yehezkel Bernat <yehezkel.bernat@intel.com>
Reviewed-by: Michael Jamet <michael.jamet@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
drivers/thunderbolt/ctl.c | 76 -----------------------------
drivers/thunderbolt/ctl.h | 16 +------
drivers/thunderbolt/tb_msgs.h | 108 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 109 insertions(+), 91 deletions(-)
create mode 100644 drivers/thunderbolt/tb_msgs.h
diff --git a/drivers/thunderbolt/ctl.c b/drivers/thunderbolt/ctl.c
index f8290a577b2b..24118c60b062 100644
--- a/drivers/thunderbolt/ctl.c
+++ b/drivers/thunderbolt/ctl.c
@@ -52,82 +52,6 @@ struct tb_ctl {
#define tb_ctl_info(ctl, format, arg...) \
dev_info(&(ctl)->nhi->pdev->dev, format, ## arg)
-
-/* configuration packets definitions */
-
-enum tb_cfg_pkg_type {
- TB_CFG_PKG_READ = 1,
- TB_CFG_PKG_WRITE = 2,
- TB_CFG_PKG_ERROR = 3,
- TB_CFG_PKG_NOTIFY_ACK = 4,
- TB_CFG_PKG_EVENT = 5,
- TB_CFG_PKG_XDOMAIN_REQ = 6,
- TB_CFG_PKG_XDOMAIN_RESP = 7,
- TB_CFG_PKG_OVERRIDE = 8,
- TB_CFG_PKG_RESET = 9,
- TB_CFG_PKG_PREPARE_TO_SLEEP = 0xd,
-};
-
-/* common header */
-struct tb_cfg_header {
- u32 route_hi:22;
- u32 unknown:10; /* highest order bit is set on replies */
- u32 route_lo;
-} __packed;
-
-/* additional header for read/write packets */
-struct tb_cfg_address {
- u32 offset:13; /* in dwords */
- u32 length:6; /* in dwords */
- u32 port:6;
- enum tb_cfg_space space:2;
- u32 seq:2; /* sequence number */
- u32 zero:3;
-} __packed;
-
-/* TB_CFG_PKG_READ, response for TB_CFG_PKG_WRITE */
-struct cfg_read_pkg {
- struct tb_cfg_header header;
- struct tb_cfg_address addr;
-} __packed;
-
-/* TB_CFG_PKG_WRITE, response for TB_CFG_PKG_READ */
-struct cfg_write_pkg {
- struct tb_cfg_header header;
- struct tb_cfg_address addr;
- u32 data[64]; /* maximum size, tb_cfg_address.length has 6 bits */
-} __packed;
-
-/* TB_CFG_PKG_ERROR */
-struct cfg_error_pkg {
- struct tb_cfg_header header;
- enum tb_cfg_error error:4;
- u32 zero1:4;
- u32 port:6;
- u32 zero2:2; /* Both should be zero, still they are different fields. */
- u32 zero3:16;
-} __packed;
-
-/* TB_CFG_PKG_EVENT */
-struct cfg_event_pkg {
- struct tb_cfg_header header;
- u32 port:6;
- u32 zero:25;
- bool unplug:1;
-} __packed;
-
-/* TB_CFG_PKG_RESET */
-struct cfg_reset_pkg {
- struct tb_cfg_header header;
-} __packed;
-
-/* TB_CFG_PKG_PREPARE_TO_SLEEP */
-struct cfg_pts_pkg {
- struct tb_cfg_header header;
- u32 data;
-} __packed;
-
-
/* utility functions */
static u64 get_route(struct tb_cfg_header header)
diff --git a/drivers/thunderbolt/ctl.h b/drivers/thunderbolt/ctl.h
index 83ae54947082..610980e3232f 100644
--- a/drivers/thunderbolt/ctl.h
+++ b/drivers/thunderbolt/ctl.h
@@ -8,6 +8,7 @@
#define _TB_CFG
#include "nhi.h"
+#include "tb_msgs.h"
/* control channel */
struct tb_ctl;
@@ -23,21 +24,6 @@ void tb_ctl_free(struct tb_ctl *ctl);
#define TB_CFG_DEFAULT_TIMEOUT 5000 /* msec */
-enum tb_cfg_space {
- TB_CFG_HOPS = 0,
- TB_CFG_PORT = 1,
- TB_CFG_SWITCH = 2,
- TB_CFG_COUNTERS = 3,
-};
-
-enum tb_cfg_error {
- TB_CFG_ERROR_PORT_NOT_CONNECTED = 0,
- TB_CFG_ERROR_INVALID_CONFIG_SPACE = 2,
- TB_CFG_ERROR_NO_SUCH_PORT = 4,
- TB_CFG_ERROR_ACK_PLUG_EVENT = 7, /* send as reply to TB_CFG_PKG_EVENT */
- TB_CFG_ERROR_LOOP = 8,
-};
-
struct tb_cfg_result {
u64 response_route;
u32 response_port; /*
diff --git a/drivers/thunderbolt/tb_msgs.h b/drivers/thunderbolt/tb_msgs.h
new file mode 100644
index 000000000000..761d56287149
--- /dev/null
+++ b/drivers/thunderbolt/tb_msgs.h
@@ -0,0 +1,108 @@
+/*
+ * Thunderbolt control channel messages
+ *
+ * Copyright (C) 2014 Andreas Noever <andreas.noever@gmail.com>
+ * Copyright (C) 2017, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _TB_MSGS
+#define _TB_MSGS
+
+#include <linux/types.h>
+
+enum tb_cfg_pkg_type {
+ TB_CFG_PKG_READ = 1,
+ TB_CFG_PKG_WRITE = 2,
+ TB_CFG_PKG_ERROR = 3,
+ TB_CFG_PKG_NOTIFY_ACK = 4,
+ TB_CFG_PKG_EVENT = 5,
+ TB_CFG_PKG_XDOMAIN_REQ = 6,
+ TB_CFG_PKG_XDOMAIN_RESP = 7,
+ TB_CFG_PKG_OVERRIDE = 8,
+ TB_CFG_PKG_RESET = 9,
+ TB_CFG_PKG_PREPARE_TO_SLEEP = 0xd,
+
+};
+
+enum tb_cfg_space {
+ TB_CFG_HOPS = 0,
+ TB_CFG_PORT = 1,
+ TB_CFG_SWITCH = 2,
+ TB_CFG_COUNTERS = 3,
+};
+
+enum tb_cfg_error {
+ TB_CFG_ERROR_PORT_NOT_CONNECTED = 0,
+ TB_CFG_ERROR_LINK_ERROR = 1,
+ TB_CFG_ERROR_INVALID_CONFIG_SPACE = 2,
+ TB_CFG_ERROR_NO_SUCH_PORT = 4,
+ TB_CFG_ERROR_ACK_PLUG_EVENT = 7, /* send as reply to TB_CFG_PKG_EVENT */
+ TB_CFG_ERROR_LOOP = 8,
+ TB_CFG_ERROR_HEC_ERROR_DETECTED = 12,
+ TB_CFG_ERROR_FLOW_CONTROL_ERROR = 13,
+};
+
+/* common header */
+struct tb_cfg_header {
+ u32 route_hi:22;
+ u32 unknown:10; /* highest order bit is set on replies */
+ u32 route_lo;
+} __packed;
+
+/* additional header for read/write packets */
+struct tb_cfg_address {
+ u32 offset:13; /* in dwords */
+ u32 length:6; /* in dwords */
+ u32 port:6;
+ enum tb_cfg_space space:2;
+ u32 seq:2; /* sequence number */
+ u32 zero:3;
+} __packed;
+
+/* TB_CFG_PKG_READ, response for TB_CFG_PKG_WRITE */
+struct cfg_read_pkg {
+ struct tb_cfg_header header;
+ struct tb_cfg_address addr;
+} __packed;
+
+/* TB_CFG_PKG_WRITE, response for TB_CFG_PKG_READ */
+struct cfg_write_pkg {
+ struct tb_cfg_header header;
+ struct tb_cfg_address addr;
+ u32 data[64]; /* maximum size, tb_cfg_address.length has 6 bits */
+} __packed;
+
+/* TB_CFG_PKG_ERROR */
+struct cfg_error_pkg {
+ struct tb_cfg_header header;
+ enum tb_cfg_error error:4;
+ u32 zero1:4;
+ u32 port:6;
+ u32 zero2:2; /* Both should be zero, still they are different fields. */
+ u32 zero3:16;
+} __packed;
+
+/* TB_CFG_PKG_EVENT */
+struct cfg_event_pkg {
+ struct tb_cfg_header header;
+ u32 port:6;
+ u32 zero:25;
+ bool unplug:1;
+} __packed;
+
+/* TB_CFG_PKG_RESET */
+struct cfg_reset_pkg {
+ struct tb_cfg_header header;
+} __packed;
+
+/* TB_CFG_PKG_PREPARE_TO_SLEEP */
+struct cfg_pts_pkg {
+ struct tb_cfg_header header;
+ u32 data;
+} __packed;
+
+#endif
--
2.11.0
[toc] | [prev] | [next] | [standalone]
Page 2 of 3 — ← Prev page 1 [2] 3 Next page →
Back to top | Article view | linux.kernel
csiph-web