Skip to content

Commit

Permalink
phb4: Block D-state power management on direct slots
Browse files Browse the repository at this point in the history
As current revisions of PHB4 don't properly handle the resulting
L1 link transition.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
  • Loading branch information
ozbenh authored and stewartsmith committed Jun 6, 2017
1 parent 68d9e87 commit 9eb2ab7
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 4 deletions.
10 changes: 10 additions & 0 deletions core/pci.c
Expand Up @@ -202,11 +202,21 @@ static void pci_init_aer_cap(struct phb *phb, struct pci_device *pd)
pci_set_cap(pd, PCIECAP_ID_AER, pos, NULL, true);
}

static void pci_init_pm_cap(struct phb *phb, struct pci_device *pd)
{
int64_t pos;

pos = pci_find_cap(phb, pd->bdfn, PCI_CFG_CAP_ID_PM);
if (pos > 0)
pci_set_cap(pd, PCI_CFG_CAP_ID_PM, pos, NULL, false);
}

void pci_init_capabilities(struct phb *phb, struct pci_device *pd)
{
pci_init_pcie_cap(phb, pd);
pci_init_aer_cap(phb, pd);
pci_init_iov_cap(phb, pd);
pci_init_pm_cap(phb, pd);
}

static struct pci_device *pci_scan_one(struct phb *phb, struct pci_device *parent,
Expand Down
34 changes: 30 additions & 4 deletions hw/phb4.c
Expand Up @@ -644,19 +644,45 @@ static void phb4_endpoint_init(struct phb *phb,
pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_CAPCTL, val32);
}

static int64_t phb4_pcicfg_no_dstate(void *dev,
struct pci_cfg_reg_filter *pcrf,
uint32_t offset, uint32_t len,
uint32_t *data, bool write)
{
uint32_t loff = offset - pcrf->start;

/* Disable D-state change on children of the PHB. For now we
* simply block all writes to the PM control/status
*/
if (write && loff >= 4 && loff < 6)
return OPAL_SUCCESS;

return OPAL_PARTIAL;
}

static void phb4_check_device_quirks(struct phb *phb, struct pci_device *dev)
{
// FIXME: add quirks later if necessary
/* Some special adapter tweaks for devices directly under the PHB */
if (dev->primary_bus != 1)
return;

/* PM quirk */
if (!pci_has_cap(dev, PCI_CFG_CAP_ID_PM, false))
return;

pci_add_cfg_reg_filter(dev,
pci_cap(dev, PCI_CFG_CAP_ID_PM, false), 8,
PCI_REG_FLAG_WRITE,
phb4_pcicfg_no_dstate);
}

static int phb4_device_init(struct phb *phb, struct pci_device *dev,
void *data __unused)
{
int ecap, aercap;

/* Some special adapter tweaks for devices directly under the PHB */
if (dev->primary_bus == 1)
phb4_check_device_quirks(phb, dev);
/* Setup special device quirks */
phb4_check_device_quirks(phb, dev);

/* Common initialization for the device */
pci_device_init(phb, dev);
Expand Down
3 changes: 3 additions & 0 deletions include/pci-cfg.h
Expand Up @@ -108,6 +108,9 @@
#define PCI_CFG_CAP_ID 0
#define PCI_CFG_CAP_NEXT 1

/* PCI Power Management capability */
#define PCI_CFG_CAP_ID_PM 1

/* PCI bridge subsystem ID capability */
#define PCI_CFG_CAP_ID_SUBSYS_VID 0x0d
#define PCICAP_SUBSYS_VID_VENDOR 4
Expand Down

0 comments on commit 9eb2ab7

Please sign in to comment.