Commit e522a7126c7c144a1dd14c6f217ac31e71082b1d

Authored by Jordan_Hargrave@Dell.com
Committed by Jesse Barnes
1 parent a246670dde

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>

Showing 1 changed file with 45 additions and 0 deletions Side-by-side Diff

drivers/pci/hotplug/pcihp_slot.c
... ... @@ -158,6 +158,47 @@
158 158 */
159 159 }
160 160  
  161 +/* Program PCIE MaxPayload setting on device: ensure parent maxpayload <= device */
  162 +static int pci_set_payload(struct pci_dev *dev)
  163 +{
  164 + int pos, ppos;
  165 + u16 pctl, psz;
  166 + u16 dctl, dsz, dcap, dmax;
  167 + struct pci_dev *parent;
  168 +
  169 + parent = dev->bus->self;
  170 + pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
  171 + if (!pos)
  172 + return 0;
  173 +
  174 + /* Read Device MaxPayload capability and setting */
  175 + pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &dctl);
  176 + pci_read_config_word(dev, pos + PCI_EXP_DEVCAP, &dcap);
  177 + dsz = (dctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5;
  178 + dmax = (dcap & PCI_EXP_DEVCAP_PAYLOAD);
  179 +
  180 + /* Read Parent MaxPayload setting */
  181 + ppos = pci_find_capability(parent, PCI_CAP_ID_EXP);
  182 + if (!ppos)
  183 + return 0;
  184 + pci_read_config_word(parent, ppos + PCI_EXP_DEVCTL, &pctl);
  185 + psz = (pctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5;
  186 +
  187 + /* If parent payload > device max payload -> error
  188 + * If parent payload > device payload -> set speed
  189 + * If parent payload <= device payload -> do nothing
  190 + */
  191 + if (psz > dmax)
  192 + return -1;
  193 + else if (psz > dsz) {
  194 + dev_info(&dev->dev, "Setting MaxPayload to %d\n", 128 << psz);
  195 + pci_write_config_word(dev, pos + PCI_EXP_DEVCTL,
  196 + (dctl & ~PCI_EXP_DEVCTL_PAYLOAD) +
  197 + (psz << 5));
  198 + }
  199 + return 0;
  200 +}
  201 +
161 202 void pci_configure_slot(struct pci_dev *dev)
162 203 {
163 204 struct pci_dev *cdev;
... ... @@ -168,6 +209,10 @@
168 209 (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE &&
169 210 (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)))
170 211 return;
  212 +
  213 + ret = pci_set_payload(dev);
  214 + if (ret)
  215 + dev_warn(&dev->dev, "could not set device max payload\n");
171 216  
172 217 memset(&hpp, 0, sizeof(hpp));
173 218 ret = pci_get_hp_params(dev, &hpp);