Skip to content

Commit

Permalink
PCI: Set PCIE maxpayload for card during hotplug insertion
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Jordan_Hargrave@Dell.com authored and Jesse Barnes committed May 10, 2011
1 parent a246670 commit e522a71
Showing 1 changed file with 45 additions and 0 deletions.
45 changes: 45 additions & 0 deletions drivers/pci/hotplug/pcihp_slot.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)
Expand Down

0 comments on commit e522a71

Please sign in to comment.