Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1458721 > unrolled thread
| Started by | Alexey Kardashevskiy <aik@ozlabs.ru> |
|---|---|
| First post | 2016-08-09 15:00 +0200 |
| Last post | 2016-08-10 02:10 +0200 |
| Articles | 6 — 4 participants |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
Re: [PATCHv2 3/4] pci: Determine actual VPD size on first access Alexey Kardashevskiy <aik@ozlabs.ru> - 2016-08-09 15:00 +0200
Re: [PATCHv2 3/4] pci: Determine actual VPD size on first access Alexander Duyck <alexander.duyck@gmail.com> - 2016-08-09 20:20 +0200
Re: [PATCHv2 3/4] pci: Determine actual VPD size on first access Benjamin Herrenschmidt <benh@kernel.crashing.org> - 2016-08-10 02:10 +0200
Re: [PATCHv2 3/4] pci: Determine actual VPD size on first access Alexander Duyck <alexander.duyck@gmail.com> - 2016-08-10 20:30 +0200
Re: [PATCHv2 3/4] pci: Determine actual VPD size on first access Hannes Reinecke <hare@suse.de> - 2016-08-10 22:50 +0200
Re: [PATCHv2 3/4] pci: Determine actual VPD size on first access Benjamin Herrenschmidt <benh@kernel.crashing.org> - 2016-08-10 02:10 +0200
| From | Alexey Kardashevskiy <aik@ozlabs.ru> |
|---|---|
| Date | 2016-08-09 15:00 +0200 |
| Subject | Re: [PATCHv2 3/4] pci: Determine actual VPD size on first access |
| Message-ID | <s4eNs-7FJ-45@gated-at.bofh.it> |
On 10/02/16 08:04, Bjorn Helgaas wrote:
> On Wed, Jan 13, 2016 at 12:25:34PM +0100, Hannes Reinecke wrote:
>> PCI-2.2 VPD entries have a maximum size of 32k, but might actually
>> be smaller than that. To figure out the actual size one has to read
>> the VPD area until the 'end marker' is reached.
>> Trying to read VPD data beyond that marker results in 'interesting'
>> effects, from simple read errors to crashing the card. And to make
>> matters worse not every PCI card implements this properly, leaving
>> us with no 'end' marker or even completely invalid data.
>> This path tries to determine the size of the VPD data.
>> If no valid data can be read an I/O error will be returned when
>> reading the sysfs attribute.
I have a problem with this particular feature as today VFIO uses this
pci_vpd_xxxx API to virtualize access to VPD and the existing code assumes
there is just one VPD block with 0x2 start and 0xf end. However I have at
least one device where this is not true - "10 Gigabit Ethernet-SR PCI
Express Adapter" - it has 2 blocks (made a script to read/parse it as
/sys/bus/pci/devices/0001\:03\:00.0/vpd shows it wrong):
#0000 Large item 42 bytes; name 0x2 Identifier String
#002d Large item 74 bytes; name 0x10
#007a Small item 1 bytes; name 0xf End Tag
---
#0c00 Large item 16 bytes; name 0x2 Identifier String
#0c13 Large item 234 bytes; name 0x10
#0d00 Large item 252 bytes; name 0x11
#0dff Small item 0 bytes; name 0xf End Tag
The cxgb3 driver is reading the second bit starting from 0xc00 but since
the size is wrongly detected as 0x7c, VFIO blocks access beyond it and the
guest driver fails to probe.
I also cannot find a clause in the PCI 3.0 spec saying that there must be
just a single block, is it there?
What would the correct fix be? Scanning all 32k of VPD is not an option I
suppose as this is what this patch is trying to avoid. Thanks.
This is the device:
[aik@p81-p9 ~]$ sudo lspci -vvnns 0001:03:00.0
0001:03:00.0 Ethernet controller [0200]: Chelsio Communications Inc T310
10GbE Single Port Adapter [1425:0030]
Subsystem: IBM Device [1014:038c]
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx+
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort-
<MAbort- >SERR- <PERR- INTx-
Latency: 0
Interrupt: pin A routed to IRQ 494
Region 0: Memory at 3fe080880000 (64-bit, non-prefetchable) [size=4K]
Region 2: Memory at 3fe080000000 (64-bit, non-prefetchable) [size=8M]
Region 4: Memory at 3fe080881000 (64-bit, non-prefetchable) [size=4K]
[virtual] Expansion ROM at 3fe080800000 [disabled] [size=512K]
Capabilities: [40] Power Management version 3
Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold-)
Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [48] MSI: Enable- Count=1/32 Maskable- 64bit+
Address: 0000000000000000 Data: 0000
Capabilities: [58] Express (v2) Endpoint, MSI 00
DevCap: MaxPayload 4096 bytes, PhantFunc 0, Latency L0s <64ns, L1 <1us
ExtTag+ AttnBtn- AttnInd- PwrInd- RBE+ FLReset-
DevCtl: Report errors: Correctable- Non-Fatal+ Fatal+ Unsupported+
RlxdOrd+ ExtTag- PhantFunc- AuxPwr- NoSnoop+
MaxPayload 256 bytes, MaxReadReq 512 bytes
DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr- TransPend-
LnkCap: Port #0, Speed 2.5GT/s, Width x8, ASPM L0s L1, Exit Latency L0s
unlimited, L1 unlimited
ClockPM- Surprise- LLActRep- BwNot- ASPMOptComp-
LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- CommClk-
ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
LnkSta: Speed 2.5GT/s, Width x8, TrErr- Train- SlotClk+ DLActive- BWMgmt-
ABWMgmt-
DevCap2: Completion Timeout: Range ABC, TimeoutDis-, LTR-, OBFF Not Supported
DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-, LTR-, OBFF Disabled
LnkCtl2: Target Link Speed: 2.5GT/s, EnterCompliance- SpeedDis-
Transmit Margin: Normal Operating Range, EnterModifiedCompliance-
ComplianceSOS-
Compliance De-emphasis: -6dB
LnkSta2: Current De-emphasis Level: -6dB, EqualizationComplete-,
EqualizationPhase1-
EqualizationPhase2-, EqualizationPhase3-, LinkEqualizationRequest-
Capabilities: [94] Vital Product Data
Product Name: 10 Gigabit Ethernet-SR PCI Express Adapter
Read-only fields:
[EC] Engineering changes: D76809
[FN] Unknown: 34 36 4b 37 38 39 37
[PN] Part number: 46K7897
[MN] Manufacture ID: 31 30 33 37
[FC] Unknown: 35 37 36 39
[SN] Serial number: YL102035603V
[NA] Unknown: 30 30 31 34 35 45 39 39 32 45 44 31
End
Capabilities: [9c] MSI-X: Enable+ Count=32 Masked-
Vector table: BAR=4 offset=00000000
PBA: BAR=4 offset=00000800
Capabilities: [100 v1] Device Serial Number 00-00-00-01-00-00-00-01
Capabilities: [300 v1] Advanced Error Reporting
UESta: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP-
ECRC- UnsupReq- ACSViol-
UEMsk: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP-
ECRC- UnsupReq- ACSViol-
UESvrt: DLP+ SDES+ TLP- FCP+ CmpltTO- CmpltAbrt- UnxCmplt- RxOF+ MalfTLP+
ECRC- UnsupReq- ACSViol-
CESta: RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr-
CEMsk: RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr+
AERCap: First Error Pointer: 00, GenCap+ CGenEn- ChkCap+ ChkEn-
Kernel driver in use: cxgb3
Kernel modules: cxgb3
>>
>> Cc: Alexander Duyck <alexander.duyck@gmail.com>
>> Cc: Bjorn Helgaas <helgaas@kernel.org>
>> Signed-off-by: Hannes Reinecke <hare@suse.de>
>> ---
>> drivers/pci/access.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++-
>> drivers/pci/pci-sysfs.c | 2 +-
>> 2 files changed, 76 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/pci/access.c b/drivers/pci/access.c
>> index 59ac36f..914e023 100644
>> --- a/drivers/pci/access.c
>> +++ b/drivers/pci/access.c
>> @@ -284,9 +284,65 @@ struct pci_vpd_pci22 {
>> struct mutex lock;
>> u16 flag;
>> bool busy;
>> + bool valid;
>
> You're just following the precedent here, but I think using "bool" in
> structures like this is pointless: it takes more space than a :1 field
> and doesn't really add any safety.
>
>> u8 cap;
>> };
>>
>> +/**
>> + * pci_vpd_size - determine actual size of Vital Product Data
>> + * @dev: pci device struct
>> + * @old_size: current assumed size, also maximum allowed size
>> + *
>
> Superfluous empty line.
>
>> + */
>> +static size_t
>> +pci_vpd_pci22_size(struct pci_dev *dev)
>
> Please follow indentation style of the file (all on one line).
>
>> +{
>> + size_t off = 0;
>> + unsigned char header[1+2]; /* 1 byte tag, 2 bytes length */
>> +
>> + while (off < PCI_VPD_PCI22_SIZE &&
>> + pci_read_vpd(dev, off, 1, header) == 1) {
>> + unsigned char tag;
>> +
>> + if (header[0] & PCI_VPD_LRDT) {
>> + /* Large Resource Data Type Tag */
>> + tag = pci_vpd_lrdt_tag(header);
>> + /* Only read length from known tag items */
>> + if ((tag == PCI_VPD_LTIN_ID_STRING) ||
>> + (tag == PCI_VPD_LTIN_RO_DATA) ||
>> + (tag == PCI_VPD_LTIN_RW_DATA)) {
>> + if (pci_read_vpd(dev, off+1, 2,
>> + &header[1]) != 2) {
>> + dev_dbg(&dev->dev,
>> + "invalid large vpd tag %02x "
>> + "size at offset %zu",
>> + tag, off + 1);
>
> The effect of this is that we set vpd->base.len to 0, which will cause
> all VPD accesses to fail, right? If so, I'd make this at least a
> dev_info(), maybe even a dev_warn(). The dev_dbg() may not appear in
> dmesg at all, depending on config options.
>
> Capitalize "VPD" and concatenate all the strings, even if it exceeds
> 80 columns.
>
>> + break;
>
> I think this leads to "return 0" below; I'd just return directly here
> so the reader doesn't have to figure out what we're breaking from.
>
>> + }
>> + off += PCI_VPD_LRDT_TAG_SIZE +
>> + pci_vpd_lrdt_size(header);
>> + }
>> + } else {
>> + /* Short Resource Data Type Tag */
>> + off += PCI_VPD_SRDT_TAG_SIZE +
>> + pci_vpd_srdt_size(header);
>> + tag = pci_vpd_srdt_tag(header);
>> + }
>> + if (tag == PCI_VPD_STIN_END) /* End tag descriptor */
>> + return off;
>> + if ((tag != PCI_VPD_LTIN_ID_STRING) &&
>> + (tag != PCI_VPD_LTIN_RO_DATA) &&
>> + (tag != PCI_VPD_LTIN_RW_DATA)) {
>> + dev_dbg(&dev->dev,
>> + "invalid %s vpd tag %02x at offset %zu",
>> + (header[0] & PCI_VPD_LRDT) ? "large" : "short",
>> + tag, off);
>> + break;
>
> Same dev_dbg() and break comment here.
>
>> + }
>> + }
>> + return 0;
>> +}
>> +
>> /*
>> * Wait for last operation to complete.
>> * This code has to spin since there is no other notification from the PCI
>> @@ -337,9 +393,23 @@ static ssize_t pci_vpd_pci22_read(struct pci_dev *dev, loff_t pos, size_t count,
>> loff_t end = pos + count;
>> u8 *buf = arg;
>>
>> - if (pos < 0 || pos > vpd->base.len || end > vpd->base.len)
>> + if (pos < 0)
>> return -EINVAL;
>>
>> + if (!vpd->valid) {
>> + vpd->valid = true;
>> + vpd->base.len = pci_vpd_pci22_size(dev);
>> + }
>> + if (vpd->base.len == 0)
>> + return -EIO;
>> +
>> + if (end > vpd->base.len) {
>> + if (pos > vpd->base.len)
>> + return 0;
>> + end = vpd->base.len;
>> + count = end - pos;
>> + }
>> +
>> if (mutex_lock_killable(&vpd->lock))
>> return -EINTR;
>>
>> @@ -389,6 +459,9 @@ static ssize_t pci_vpd_pci22_write(struct pci_dev *dev, loff_t pos, size_t count
>> loff_t end = pos + count;
>> int ret = 0;
>>
>> + if (!vpd->valid)
>> + return -EAGAIN;
>
> Does this mean we now have to do a VPD read before a VPD write? That
> sounds like a new requirement that is non-obvious.
>
>> +
>> if (pos < 0 || (pos & 3) || (count & 3) || end > vpd->base.len)
>> return -EINVAL;
>>
>> @@ -496,6 +569,7 @@ int pci_vpd_pci22_init(struct pci_dev *dev)
>> mutex_init(&vpd->lock);
>> vpd->cap = cap;
>> vpd->busy = false;
>> + vpd->valid = false;
>> dev->vpd = &vpd->base;
>> return 0;
>> }
>> diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
>> index de327c3..31a1f35 100644
>> --- a/drivers/pci/pci-sysfs.c
>> +++ b/drivers/pci/pci-sysfs.c
>> @@ -1333,7 +1333,7 @@ static int pci_create_capabilities_sysfs(struct pci_dev *dev)
>> return -ENOMEM;
>>
>> sysfs_bin_attr_init(attr);
>> - attr->size = dev->vpd->len;
>> + attr->size = 0;
>
> I'm still puzzled about how we're using attr->size. I don't really
> want that size to change at run-time, i.e., I don't want it to be zero
> immediately after boot, then change to something else after the first
> VPD read. I don't think it's important that this reflect the size
> computed based on the VPD contents. I think it would be fine if it
> were set to 32K all the time and possibly set to zero by quirks on
> devices where VPD is completely broken.
>
>> attr->attr.name = "vpd";
>> attr->attr.mode = S_IRUSR | S_IWUSR;
>> attr->read = read_vpd_attr;
>> --
>> 1.8.5.6
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-pci" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pci" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Alexey
[toc] | [next] | [standalone]
| From | Alexander Duyck <alexander.duyck@gmail.com> |
|---|---|
| Date | 2016-08-09 20:20 +0200 |
| Message-ID | <s4jN8-2G0-19@gated-at.bofh.it> |
| In reply to | #1458721 |
On Tue, Aug 9, 2016 at 5:54 AM, Alexey Kardashevskiy <aik@ozlabs.ru> wrote: > On 10/02/16 08:04, Bjorn Helgaas wrote: >> On Wed, Jan 13, 2016 at 12:25:34PM +0100, Hannes Reinecke wrote: >>> PCI-2.2 VPD entries have a maximum size of 32k, but might actually >>> be smaller than that. To figure out the actual size one has to read >>> the VPD area until the 'end marker' is reached. >>> Trying to read VPD data beyond that marker results in 'interesting' >>> effects, from simple read errors to crashing the card. And to make >>> matters worse not every PCI card implements this properly, leaving >>> us with no 'end' marker or even completely invalid data. >>> This path tries to determine the size of the VPD data. >>> If no valid data can be read an I/O error will be returned when >>> reading the sysfs attribute. > > > I have a problem with this particular feature as today VFIO uses this > pci_vpd_xxxx API to virtualize access to VPD and the existing code assumes > there is just one VPD block with 0x2 start and 0xf end. However I have at > least one device where this is not true - "10 Gigabit Ethernet-SR PCI > Express Adapter" - it has 2 blocks (made a script to read/parse it as > /sys/bus/pci/devices/0001\:03\:00.0/vpd shows it wrong): The PCI spec is what essentially assumes that there is only one block. If I am not mistaken in the case of this device the second block here actually contains device configuration data, not actual VPD data. The issue here is that the second block is being accessed as VPD when it isn't. > #0000 Large item 42 bytes; name 0x2 Identifier String > #002d Large item 74 bytes; name 0x10 > #007a Small item 1 bytes; name 0xf End Tag > --- > #0c00 Large item 16 bytes; name 0x2 Identifier String > #0c13 Large item 234 bytes; name 0x10 > #0d00 Large item 252 bytes; name 0x11 > #0dff Small item 0 bytes; name 0xf End Tag The second block here is driver proprietary setup bits. > The cxgb3 driver is reading the second bit starting from 0xc00 but since > the size is wrongly detected as 0x7c, VFIO blocks access beyond it and the > guest driver fails to probe. > > I also cannot find a clause in the PCI 3.0 spec saying that there must be > just a single block, is it there? The problem is we need to be able to parse it. The spec defines a series of tags that can be used starting at offset 0. That is how we are supposed to get around through the VPD data. The problem is we can't have more than one end tag and what appears to be happening here is that we are defining a second block of data which uses the same formatting as VPD but is not VPD. > What would the correct fix be? Scanning all 32k of VPD is not an option I > suppose as this is what this patch is trying to avoid. Thanks. I adding the current cxgb3 maintainer and netdev list to the Cc. This is something that can probably be addressed via a PCI quirk as what needs to happen is that we need to extend the VPD in the case of this part in order to include this second block. As long as we can read the VPD data all the way out to 0xdff odds are we could probably just have the size arbitrarily increased to 0xe00 via the quirk and then you would be able to access all of the VPD for the device. We already have code making other modifications to drivers/pci/quirks.c for several Broadcom devices and probably just need something similar to allow extended access in the case of these devices. > > > > This is the device: > > [aik@p81-p9 ~]$ sudo lspci -vvnns 0001:03:00.0 > 0001:03:00.0 Ethernet controller [0200]: Chelsio Communications Inc T310 > 10GbE Single Port Adapter [1425:0030] > Subsystem: IBM Device [1014:038c] > Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- > Stepping- SERR- FastB2B- DisINTx+ > Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- > <MAbort- >SERR- <PERR- INTx- > Latency: 0 > Interrupt: pin A routed to IRQ 494 > Region 0: Memory at 3fe080880000 (64-bit, non-prefetchable) [size=4K] > Region 2: Memory at 3fe080000000 (64-bit, non-prefetchable) [size=8M] > Region 4: Memory at 3fe080881000 (64-bit, non-prefetchable) [size=4K] > [virtual] Expansion ROM at 3fe080800000 [disabled] [size=512K] > Capabilities: [40] Power Management version 3 > Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold-) > Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME- > Capabilities: [48] MSI: Enable- Count=1/32 Maskable- 64bit+ > Address: 0000000000000000 Data: 0000 > Capabilities: [58] Express (v2) Endpoint, MSI 00 > DevCap: MaxPayload 4096 bytes, PhantFunc 0, Latency L0s <64ns, L1 <1us > ExtTag+ AttnBtn- AttnInd- PwrInd- RBE+ FLReset- > DevCtl: Report errors: Correctable- Non-Fatal+ Fatal+ Unsupported+ > RlxdOrd+ ExtTag- PhantFunc- AuxPwr- NoSnoop+ > MaxPayload 256 bytes, MaxReadReq 512 bytes > DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr- TransPend- > LnkCap: Port #0, Speed 2.5GT/s, Width x8, ASPM L0s L1, Exit Latency L0s > unlimited, L1 unlimited > ClockPM- Surprise- LLActRep- BwNot- ASPMOptComp- > LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- CommClk- > ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt- > LnkSta: Speed 2.5GT/s, Width x8, TrErr- Train- SlotClk+ DLActive- BWMgmt- > ABWMgmt- > DevCap2: Completion Timeout: Range ABC, TimeoutDis-, LTR-, OBFF Not Supported > DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-, LTR-, OBFF Disabled > LnkCtl2: Target Link Speed: 2.5GT/s, EnterCompliance- SpeedDis- > Transmit Margin: Normal Operating Range, EnterModifiedCompliance- > ComplianceSOS- > Compliance De-emphasis: -6dB > LnkSta2: Current De-emphasis Level: -6dB, EqualizationComplete-, > EqualizationPhase1- > EqualizationPhase2-, EqualizationPhase3-, LinkEqualizationRequest- > Capabilities: [94] Vital Product Data > Product Name: 10 Gigabit Ethernet-SR PCI Express Adapter > Read-only fields: > [EC] Engineering changes: D76809 > [FN] Unknown: 34 36 4b 37 38 39 37 > [PN] Part number: 46K7897 > [MN] Manufacture ID: 31 30 33 37 > [FC] Unknown: 35 37 36 39 > [SN] Serial number: YL102035603V > [NA] Unknown: 30 30 31 34 35 45 39 39 32 45 44 31 > End > Capabilities: [9c] MSI-X: Enable+ Count=32 Masked- > Vector table: BAR=4 offset=00000000 > PBA: BAR=4 offset=00000800 > Capabilities: [100 v1] Device Serial Number 00-00-00-01-00-00-00-01 > Capabilities: [300 v1] Advanced Error Reporting > UESta: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP- > ECRC- UnsupReq- ACSViol- > UEMsk: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP- > ECRC- UnsupReq- ACSViol- > UESvrt: DLP+ SDES+ TLP- FCP+ CmpltTO- CmpltAbrt- UnxCmplt- RxOF+ MalfTLP+ > ECRC- UnsupReq- ACSViol- > CESta: RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr- > CEMsk: RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr+ > AERCap: First Error Pointer: 00, GenCap+ CGenEn- ChkCap+ ChkEn- > Kernel driver in use: cxgb3 > Kernel modules: cxgb3 > >
[toc] | [prev] | [next] | [standalone]
| From | Benjamin Herrenschmidt <benh@kernel.crashing.org> |
|---|---|
| Date | 2016-08-10 02:10 +0200 |
| Message-ID | <s4pfP-690-5@gated-at.bofh.it> |
| In reply to | #1459045 |
On Tue, 2016-08-09 at 11:12 -0700, Alexander Duyck wrote: > > The PCI spec is what essentially assumes that there is only one block. > If I am not mistaken in the case of this device the second block here > actually contains device configuration data, not actual VPD data. The > issue here is that the second block is being accessed as VPD when it > isn't. Devices do funny things with config space, film at 11. VFIO trying to be the middle man and intercept/interpret things is broken, cannot work, will never work, will just results in lots and lots of useless code, but I've been singing that song for too long and nobody seems to care... > > > #0000 Large item 42 bytes; name 0x2 Identifier String > > #002d Large item 74 bytes; name 0x10 > > #007a Small item 1 bytes; name 0xf End Tag > > --- > > #0c00 Large item 16 bytes; name 0x2 Identifier String > > #0c13 Large item 234 bytes; name 0x10 > > #0d00 Large item 252 bytes; name 0x11 > > #0dff Small item 0 bytes; name 0xf End Tag > > The second block here is driver proprietary setup bits. Right. They happen to be in VPD on this device. They an be elsewhere on other devices. In between capabilities on some, in vendor caps on others... > > > The cxgb3 driver is reading the second bit starting from 0xc00 but since > > the size is wrongly detected as 0x7c, VFIO blocks access beyond it and the > > guest driver fails to probe. > > > > I also cannot find a clause in the PCI 3.0 spec saying that there must be > > just a single block, is it there? > > > The problem is we need to be able to parse it. We can parse the standard part for generic stuff like inventory tools or lsvpd, but we shouldn't get in the way of the driver poking at its device. > The spec defines a > series of tags that can be used starting at offset 0. That is how we > are supposed to get around through the VPD data. The problem is we > can't have more than one end tag and what appears to be happening here > is that we are defining a second block of data which uses the same > formatting as VPD but is not VPD. > > > What would the correct fix be? Scanning all 32k of VPD is not an option I > > suppose as this is what this patch is trying to avoid. Thanks. > > I adding the current cxgb3 maintainer and netdev list to the Cc. This > is something that can probably be addressed via a PCI quirk as what > needs to happen is that we need to extend the VPD in the case of this > part in order to include this second block. As long as we can read > the VPD data all the way out to 0xdff odds are we could probably just > have the size arbitrarily increased to 0xe00 via the quirk and then > you would be able to access all of the VPD for the device. We already > have code making other modifications to drivers/pci/quirks.c for > several Broadcom devices and probably just need something similar to > allow extended access in the case of these devices. > > > > > > > > > This is the device: > > > > > [aik@p81-p9 ~]$ sudo lspci -vvnns 0001:03:00.0 > > 0001:03:00.0 Ethernet controller [0200]: Chelsio Communications Inc T310 > > 10GbE Single Port Adapter [1425:0030] > > Subsystem: IBM Device [1014:038c] > > Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- > > Stepping- SERR- FastB2B- DisINTx+ > > Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- > > <MAbort- >SERR- <PERR- INTx- > > Latency: 0 > > Interrupt: pin A routed to IRQ 494 > > Region 0: Memory at 3fe080880000 (64-bit, non-prefetchable) [size=4K] > > Region 2: Memory at 3fe080000000 (64-bit, non-prefetchable) [size=8M] > > Region 4: Memory at 3fe080881000 (64-bit, non-prefetchable) [size=4K] > > [virtual] Expansion ROM at 3fe080800000 [disabled] [size=512K] > > Capabilities: [40] Power Management version 3 > > Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold-) > > Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME- > > Capabilities: [48] MSI: Enable- Count=1/32 Maskable- 64bit+ > > Address: 0000000000000000 Data: 0000 > > Capabilities: [58] Express (v2) Endpoint, MSI 00 > > DevCap: MaxPayload 4096 bytes, PhantFunc 0, Latency L0s <64ns, L1 <1us > > ExtTag+ AttnBtn- AttnInd- PwrInd- RBE+ FLReset- > > DevCtl: Report errors: Correctable- Non-Fatal+ Fatal+ Unsupported+ > > RlxdOrd+ ExtTag- PhantFunc- AuxPwr- NoSnoop+ > > MaxPayload 256 bytes, MaxReadReq 512 bytes > > DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr- TransPend- > > LnkCap: Port #0, Speed 2.5GT/s, Width x8, ASPM L0s L1, Exit Latency L0s > > unlimited, L1 unlimited > > ClockPM- Surprise- LLActRep- BwNot- ASPMOptComp- > > LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- CommClk- > > ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt- > > LnkSta: Speed 2.5GT/s, Width x8, TrErr- Train- SlotClk+ DLActive- BWMgmt- > > ABWMgmt- > > DevCap2: Completion Timeout: Range ABC, TimeoutDis-, LTR-, OBFF Not Supported > > DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-, LTR-, OBFF Disabled > > LnkCtl2: Target Link Speed: 2.5GT/s, EnterCompliance- SpeedDis- > > Transmit Margin: Normal Operating Range, EnterModifiedCompliance- > > ComplianceSOS- > > Compliance De-emphasis: -6dB > > LnkSta2: Current De-emphasis Level: -6dB, EqualizationComplete-, > > EqualizationPhase1- > > EqualizationPhase2-, EqualizationPhase3-, LinkEqualizationRequest- > > Capabilities: [94] Vital Product Data > > Product Name: 10 Gigabit Ethernet-SR PCI Express Adapter > > Read-only fields: > > [EC] Engineering changes: D76809 > > [FN] Unknown: 34 36 4b 37 38 39 37 > > [PN] Part number: 46K7897 > > [MN] Manufacture ID: 31 30 33 37 > > [FC] Unknown: 35 37 36 39 > > [SN] Serial number: YL102035603V > > [NA] Unknown: 30 30 31 34 35 45 39 39 32 45 44 31 > > End > > Capabilities: [9c] MSI-X: Enable+ Count=32 Masked- > > Vector table: BAR=4 offset=00000000 > > PBA: BAR=4 offset=00000800 > > Capabilities: [100 v1] Device Serial Number 00-00-00-01-00-00-00-01 > > Capabilities: [300 v1] Advanced Error Reporting > > UESta: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP- > > ECRC- UnsupReq- ACSViol- > > UEMsk: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP- > > ECRC- UnsupReq- ACSViol- > > UESvrt: DLP+ SDES+ TLP- FCP+ CmpltTO- CmpltAbrt- UnxCmplt- RxOF+ MalfTLP+ > > ECRC- UnsupReq- ACSViol- > > CESta: RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr- > > CEMsk: RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr+ > > AERCap: First Error Pointer: 00, GenCap+ CGenEn- ChkCap+ ChkEn- > > Kernel driver in use: cxgb3 > > Kernel modules: cxgb3 > > > >
[toc] | [prev] | [next] | [standalone]
| From | Alexander Duyck <alexander.duyck@gmail.com> |
|---|---|
| Date | 2016-08-10 20:30 +0200 |
| Message-ID | <s4Gqo-b4-123@gated-at.bofh.it> |
| In reply to | #1459208 |
On Tue, Aug 9, 2016 at 5:03 PM, Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote: > On Tue, 2016-08-09 at 11:12 -0700, Alexander Duyck wrote: >> >> The PCI spec is what essentially assumes that there is only one block. >> If I am not mistaken in the case of this device the second block here >> actually contains device configuration data, not actual VPD data. The >> issue here is that the second block is being accessed as VPD when it >> isn't. > > Devices do funny things with config space, film at 11. VFIO trying to > be the middle man and intercept/interpret things is broken, cannot work, > will never work, will just results in lots and lots of useless code, but > I've been singing that song for too long and nobody seems to care... > >> > > #0000 Large item 42 bytes; name 0x2 Identifier String >> > #002d Large item 74 bytes; name 0x10 >> > #007a Small item 1 bytes; name 0xf End Tag >> > --- >> > #0c00 Large item 16 bytes; name 0x2 Identifier String >> > #0c13 Large item 234 bytes; name 0x10 >> > #0d00 Large item 252 bytes; name 0x11 >> > #0dff Small item 0 bytes; name 0xf End Tag >> >> The second block here is driver proprietary setup bits. > > Right. They happen to be in VPD on this device. They an be elsewhere on > other devices. In between capabilities on some, in vendor caps on others... > >> > > The cxgb3 driver is reading the second bit starting from 0xc00 but since >> > the size is wrongly detected as 0x7c, VFIO blocks access beyond it and the >> > guest driver fails to probe. >> > >> > I also cannot find a clause in the PCI 3.0 spec saying that there must be >> > just a single block, is it there? >> >> > The problem is we need to be able to parse it. > > We can parse the standard part for generic stuff like inventory tools > or lsvpd, but we shouldn't get in the way of the driver poking at its > device. If we add the quirk to the kernel that reports the VPD for this device is the actual size of both blocks then we wouldn't be blocking the VPD access like we currently are. The problem is if we don't do this it becomes possible for a guest to essentially cripple a device on the host by just accessing VPD regions that aren't actually viable on many devices. We are much better off in terms of security and stability if we restrict access to what should be accessible. In this case what has happened is that the vendor threw in an extra out-of-spec block and just expected it to work. In order to work around it we just need to add a small function to drivers/pci/quirks.c that would update the VPD size reported so that it matches what the hardware is actually providing instead of what we can determine based on the VPD layout. Really working around something like this is not much different than what we would have to do if the vendor had stuffed the data in some reserved section of their PCI configuration space. We end up needing to add special quirks any time a vendor goes out-of-spec for some one-off configuration interface that only they are ever going to use. - Alex
[toc] | [prev] | [next] | [standalone]
| From | Hannes Reinecke <hare@suse.de> |
|---|---|
| Date | 2016-08-10 22:50 +0200 |
| Message-ID | <s4IBR-1DK-63@gated-at.bofh.it> |
| In reply to | #1459045 |
On 08/09/2016 08:12 PM, Alexander Duyck wrote: > On Tue, Aug 9, 2016 at 5:54 AM, Alexey Kardashevskiy <aik@ozlabs.ru> wrote: >> On 10/02/16 08:04, Bjorn Helgaas wrote: >>> On Wed, Jan 13, 2016 at 12:25:34PM +0100, Hannes Reinecke wrote: >>>> PCI-2.2 VPD entries have a maximum size of 32k, but might actually >>>> be smaller than that. To figure out the actual size one has to read >>>> the VPD area until the 'end marker' is reached. >>>> Trying to read VPD data beyond that marker results in 'interesting' >>>> effects, from simple read errors to crashing the card. And to make >>>> matters worse not every PCI card implements this properly, leaving >>>> us with no 'end' marker or even completely invalid data. >>>> This path tries to determine the size of the VPD data. >>>> If no valid data can be read an I/O error will be returned when >>>> reading the sysfs attribute. >> >> >> I have a problem with this particular feature as today VFIO uses this >> pci_vpd_xxxx API to virtualize access to VPD and the existing code assumes >> there is just one VPD block with 0x2 start and 0xf end. However I have at >> least one device where this is not true - "10 Gigabit Ethernet-SR PCI >> Express Adapter" - it has 2 blocks (made a script to read/parse it as >> /sys/bus/pci/devices/0001\:03\:00.0/vpd shows it wrong): > > The PCI spec is what essentially assumes that there is only one block. > If I am not mistaken in the case of this device the second block here > actually contains device configuration data, not actual VPD data. The > issue here is that the second block is being accessed as VPD when it > isn't. > >> #0000 Large item 42 bytes; name 0x2 Identifier String >> #002d Large item 74 bytes; name 0x10 >> #007a Small item 1 bytes; name 0xf End Tag >> --- >> #0c00 Large item 16 bytes; name 0x2 Identifier String >> #0c13 Large item 234 bytes; name 0x10 >> #0d00 Large item 252 bytes; name 0x11 >> #0dff Small item 0 bytes; name 0xf End Tag > > The second block here is driver proprietary setup bits. > >> The cxgb3 driver is reading the second bit starting from 0xc00 but since >> the size is wrongly detected as 0x7c, VFIO blocks access beyond it and the >> guest driver fails to probe. >> >> I also cannot find a clause in the PCI 3.0 spec saying that there must be >> just a single block, is it there? > > The problem is we need to be able to parse it. The spec defines a > series of tags that can be used starting at offset 0. That is how we > are supposed to get around through the VPD data. The problem is we > can't have more than one end tag and what appears to be happening here > is that we are defining a second block of data which uses the same > formatting as VPD but is not VPD. > >> What would the correct fix be? Scanning all 32k of VPD is not an option I >> suppose as this is what this patch is trying to avoid. Thanks. > > I adding the current cxgb3 maintainer and netdev list to the Cc. This > is something that can probably be addressed via a PCI quirk as what > needs to happen is that we need to extend the VPD in the case of this > part in order to include this second block. As long as we can read > the VPD data all the way out to 0xdff odds are we could probably just > have the size arbitrarily increased to 0xe00 via the quirk and then > you would be able to access all of the VPD for the device. We already > have code making other modifications to drivers/pci/quirks.c for > several Broadcom devices and probably just need something similar to > allow extended access in the case of these devices. > Yes, that's what I think, too. The Broadcom quirk should work here, too. (Didn't we do that already?) Cheers, Hannes -- Dr. Hannes Reinecke Teamlead Storage & Networking hare@suse.de +49 911 74053 688 SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton HRB 21284 (AG Nürnberg)
[toc] | [prev] | [next] | [standalone]
| From | Benjamin Herrenschmidt <benh@kernel.crashing.org> |
|---|---|
| Date | 2016-08-10 02:10 +0200 |
| Message-ID | <s4pfP-690-7@gated-at.bofh.it> |
| In reply to | #1458721 |
> On Tue, 2016-08-09 at 22:54 +1000, Alexey Kardashevskiy wrote: > The cxgb3 driver is reading the second bit starting from 0xc00 but since > the size is wrongly detected as 0x7c, VFIO blocks access beyond it and the > guest driver fails to probe. > > I also cannot find a clause in the PCI 3.0 spec saying that there must be > just a single block, is it there? > > What would the correct fix be? Scanning all 32k of VPD is not an option I > suppose as this is what this patch is trying to avoid. Thanks. Additionally, Hannes, Alex, I argue that for platforms with proper HW isolation (such as ppc with EEH), we shouldn't have VFIO try to virtualize that stuff. It's the same problem with the bloody MSIs. Just let the guest config space accesses go straight through. Its drivers knows better what the HW needs and if it crashes the card, too bad for that guest. That being said, we don't have fine grained per-device PERST control on all systems so there may not be recovery from that but on the other hand, our constant attempts at "filtering" what the guest does to the HW is imho, doomed. Cheers, Ben.
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web