PCI: Set PCIE maxpayload for card during hotplug insertion
The following patch sets the MaxPayload setting to match the parent reading when inserting a PCIE card into a hotplug slot. On our system, the upstream bridge is set to 256, but when inserting a card, the card setting defaults to 128. As soon as I/O is performed to the card it starts receiving errors since the payload size is too small. Reviewed-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Signed-off-by: Jordan Hargrave <jordan_hargrave@dell.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
This commit is contained in:
parent
a246670dde
commit
e522a7126c
1 changed files with 45 additions and 0 deletions
|
@ -158,6 +158,47 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp)
|
|||
*/
|
||||
}
|
||||
|
||||
/* Program PCIE MaxPayload setting on device: ensure parent maxpayload <= device */
|
||||
static int pci_set_payload(struct pci_dev *dev)
|
||||
{
|
||||
int pos, ppos;
|
||||
u16 pctl, psz;
|
||||
u16 dctl, dsz, dcap, dmax;
|
||||
struct pci_dev *parent;
|
||||
|
||||
parent = dev->bus->self;
|
||||
pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
|
||||
if (!pos)
|
||||
return 0;
|
||||
|
||||
/* Read Device MaxPayload capability and setting */
|
||||
pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &dctl);
|
||||
pci_read_config_word(dev, pos + PCI_EXP_DEVCAP, &dcap);
|
||||
dsz = (dctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5;
|
||||
dmax = (dcap & PCI_EXP_DEVCAP_PAYLOAD);
|
||||
|
||||
/* Read Parent MaxPayload setting */
|
||||
ppos = pci_find_capability(parent, PCI_CAP_ID_EXP);
|
||||
if (!ppos)
|
||||
return 0;
|
||||
pci_read_config_word(parent, ppos + PCI_EXP_DEVCTL, &pctl);
|
||||
psz = (pctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5;
|
||||
|
||||
/* If parent payload > device max payload -> error
|
||||
* If parent payload > device payload -> set speed
|
||||
* If parent payload <= device payload -> do nothing
|
||||
*/
|
||||
if (psz > dmax)
|
||||
return -1;
|
||||
else if (psz > dsz) {
|
||||
dev_info(&dev->dev, "Setting MaxPayload to %d\n", 128 << psz);
|
||||
pci_write_config_word(dev, pos + PCI_EXP_DEVCTL,
|
||||
(dctl & ~PCI_EXP_DEVCTL_PAYLOAD) +
|
||||
(psz << 5));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pci_configure_slot(struct pci_dev *dev)
|
||||
{
|
||||
struct pci_dev *cdev;
|
||||
|
@ -169,6 +210,10 @@ void pci_configure_slot(struct pci_dev *dev)
|
|||
(dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)))
|
||||
return;
|
||||
|
||||
ret = pci_set_payload(dev);
|
||||
if (ret)
|
||||
dev_warn(&dev->dev, "could not set device max payload\n");
|
||||
|
||||
memset(&hpp, 0, sizeof(hpp));
|
||||
ret = pci_get_hp_params(dev, &hpp);
|
||||
if (ret)
|
||||
|
|
Loading…
Reference in a new issue