aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug/pcihp_slot.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/hotplug/pcihp_slot.c')
-rw-r--r--drivers/pci/hotplug/pcihp_slot.c45
1 files changed, 45 insertions, 0 deletions
diff --git a/drivers/pci/hotplug/pcihp_slot.c b/drivers/pci/hotplug/pcihp_slot.c
index 80b461c98557..749fdf070319 100644
--- a/drivers/pci/hotplug/pcihp_slot.c
+++ b/drivers/pci/hotplug/pcihp_slot.c
@@ -158,6 +158,47 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp)
158 */ 158 */
159} 159}
160 160
161/* Program PCIE MaxPayload setting on device: ensure parent maxpayload <= device */
162static 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
161void pci_configure_slot(struct pci_dev *dev) 202void pci_configure_slot(struct pci_dev *dev)
162{ 203{
163 struct pci_dev *cdev; 204 struct pci_dev *cdev;
@@ -169,6 +210,10 @@ void pci_configure_slot(struct pci_dev *dev)
169 (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) 210 (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)))
170 return; 211 return;
171 212
213 ret = pci_set_payload(dev);
214 if (ret)
215 dev_warn(&dev->dev, "could not set device max payload\n");
216
172 memset(&hpp, 0, sizeof(hpp)); 217 memset(&hpp, 0, sizeof(hpp));
173 ret = pci_get_hp_params(dev, &hpp); 218 ret = pci_get_hp_params(dev, &hpp);
174 if (ret) 219 if (ret)