Skip to content

Commit

Permalink
core/pcie-slots: Make dynamic slot creation generic
Browse files Browse the repository at this point in the history
astbmc has some code to handle devices that are behind a "slot" on a
riser card that can't be added to the static slot tables for a system.
We probably want to use this code outside the slot table handling so
move it somewhere generic and rework it so slot table specifics aren't
buried inside it.

Signed-off-by: Oliver O'Halloran <oohall@gmail.com>
Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
  • Loading branch information
oohal authored and stewartsmith committed Sep 15, 2017
1 parent 529d86d commit cc41ce9
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 62 deletions.
51 changes: 51 additions & 0 deletions core/pcie-slot.c
Expand Up @@ -528,5 +528,56 @@ struct pci_slot *pcie_slot_create(struct phb *phb, struct pci_device *pd)
slot->ops.hreset = pcie_slot_sm_hreset;
slot->ops.freset = pcie_slot_sm_freset;

slot->wired_lanes = PCI_SLOT_WIRED_LANES_UNKNOWN;
slot->connector_type = PCI_SLOT_CONNECTOR_PCIE_NS;
slot->card_desc = PCI_SLOT_DESC_NON_STANDARD;
slot->card_mech = PCI_SLOT_MECH_NONE;
slot->power_led_ctl = PCI_SLOT_PWR_LED_CTL_NONE;
slot->attn_led_ctl = PCI_SLOT_ATTN_LED_CTL_NONE;

return slot;
}

/* FIXME: this is kind of insane */
struct pci_slot *pcie_slot_create_dynamic(struct phb *phb,
struct pci_device *pd)
{
uint32_t ecap, val;
struct pci_slot *slot;

if (!phb || !pd || pd->slot)
return NULL;

/* Try to create slot whose details aren't provided by platform.
* We only care the downstream ports of PCIe switch that connects
* to root port.
*/
if (pd->dev_type != PCIE_TYPE_SWITCH_DNPORT ||
!pd->parent || !pd->parent->parent ||
pd->parent->parent->parent)
return NULL;

ecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);
pci_cfg_read32(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTCAP, &val);
if (!(val & PCICAP_EXP_SLOTCAP_HPLUG_CAP))
return NULL;

slot = pcie_slot_create(phb, pd);

/* On superMicro's "p8dnu" platform, we create dynamic PCI slots
* for all downstream ports of PEX9733 that is connected to PHB
* direct slot. The power supply to the PCI slot is lost after
* PCI adapter is removed from it. The power supply can't be
* turned on when the slot is in empty state. The power supply
* isn't turned on automatically when inserting PCI adapter to
* the slot at later point. We set a flag to the slot here, to
* turn on the power supply in (suprise or managed) hot-add path.
*
* We have same issue with PEX8718 as above on "p8dnu" platform.
*/
if (dt_node_is_compatible(dt_root, "supermicro,p8dnu") && slot->pd &&
(slot->pd->vdid == 0x973310b5 || slot->pd->vdid == 0x871810b5))
pci_slot_add_flags(slot, PCI_SLOT_FLAG_FORCE_POWERON);

return slot;
}
3 changes: 3 additions & 0 deletions include/pci-slot.h
Expand Up @@ -252,6 +252,9 @@ extern struct pci_slot *pci_slot_alloc(struct phb *phb,
struct pci_device *pd);
extern struct pci_slot *pcie_slot_create(struct phb *phb,
struct pci_device *pd);
extern struct pci_slot *pcie_slot_create_dynamic(struct phb *phb,
struct pci_device *pd);

extern void pci_slot_add_dt_properties(struct pci_slot *slot,
struct dt_node *np);
extern struct pci_slot *pci_slot_find(uint64_t id);
Expand Down
74 changes: 12 additions & 62 deletions platforms/astbmc/slots.c
Expand Up @@ -85,7 +85,7 @@ static const struct slot_table_entry *match_slot_dev_entry(struct phb *phb,
return NULL;
}

static void add_slot_properties(struct pci_slot *slot,
static void slot_table_add_properties(struct pci_slot *slot,
struct dt_node *np)
{
struct phb *phb = slot->phb;
Expand Down Expand Up @@ -126,82 +126,32 @@ static void add_slot_properties(struct pci_slot *slot,
loc_code, strlen(loc_code) + 1);
}

static void init_slot_info(struct pci_slot *slot, bool pluggable, void *data)
{
slot->data = data;
slot->ops.add_properties = add_slot_properties;

slot->pluggable = pluggable;
slot->power_ctl = false;
slot->wired_lanes = PCI_SLOT_WIRED_LANES_UNKNOWN;
slot->connector_type = PCI_SLOT_CONNECTOR_PCIE_NS;
slot->card_desc = PCI_SLOT_DESC_NON_STANDARD;
slot->card_mech = PCI_SLOT_MECH_NONE;
slot->power_led_ctl = PCI_SLOT_PWR_LED_CTL_NONE;
slot->attn_led_ctl = PCI_SLOT_ATTN_LED_CTL_NONE;
}

static void create_dynamic_slot(struct phb *phb, struct pci_device *pd)
{
uint32_t ecap, val;
struct pci_slot *slot;

if (!phb || !pd || pd->slot)
return;

/* Try to create slot whose details aren't provided by platform.
* We only care the downstream ports of PCIe switch that connects
* to root port.
*/
if (pd->dev_type != PCIE_TYPE_SWITCH_DNPORT ||
!pd->parent || !pd->parent->parent ||
pd->parent->parent->parent)
return;

ecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);
pci_cfg_read32(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTCAP, &val);
if (!(val & PCICAP_EXP_SLOTCAP_HPLUG_CAP))
return;

slot = pcie_slot_create(phb, pd);
assert(slot);
init_slot_info(slot, true, NULL);

/* On superMicro's "p8dnu" platform, we create dynamic PCI slots
* for all downstream ports of PEX9733 that is connected to PHB
* direct slot. The power supply to the PCI slot is lost after
* PCI adapter is removed from it. The power supply can't be
* turned on when the slot is in empty state. The power supply
* isn't turned on automatically when inserting PCI adapter to
* the slot at later point. We set a flag to the slot here, to
* turn on the power supply in (suprise or managed) hot-add path.
*
* We have same issue with PEX8718 as above on "p8dnu" platform.
*/
if (dt_node_is_compatible(dt_root, "supermicro,p8dnu") && slot->pd &&
(slot->pd->vdid == 0x973310b5 || slot->pd->vdid == 0x871810b5))
pci_slot_add_flags(slot, PCI_SLOT_FLAG_FORCE_POWERON);
}

void slot_table_get_slot_info(struct phb *phb, struct pci_device *pd)
{
const struct slot_table_entry *ent;
struct pci_slot *slot;
bool pluggable;

if (!pd || pd->slot)
return;

ent = match_slot_dev_entry(phb, pd);

if (!ent || !ent->name) {
create_dynamic_slot(phb, pd);
slot = pcie_slot_create_dynamic(phb, pd);
if (slot) {
slot->ops.add_properties = slot_table_add_properties;
slot->pluggable = true;
}

return;
}

slot = pcie_slot_create(phb, pd);
assert(slot);

pluggable = !!(ent->etype == st_pluggable_slot);
init_slot_info(slot, pluggable, (void *)ent);
slot->pluggable = !!(ent->etype == st_pluggable_slot);
slot->ops.add_properties = slot_table_add_properties;
slot->data = (void *)ent;
}

static int __pci_find_dev_by_location(struct phb *phb,
Expand Down

0 comments on commit cc41ce9

Please sign in to comment.