diff options
author | Gavin Shan <gwshan@linux.vnet.ibm.com> | 2016-06-10 15:03:42 +1000 |
---|---|---|
committer | Stewart Smith <stewart@linux.vnet.ibm.com> | 2016-06-14 16:00:16 +1000 |
commit | bc66fb67aee6f9e6520120c2476d58f3899c9221 (patch) | |
tree | 378f502d261691a66fc19ff96ebf301c22c9c7fc /include | |
parent | 0bf9c3c44bf1bde1c7bec86d33a6e3ccb6e56c90 (diff) | |
download | skiboot-bc66fb67aee6f9e6520120c2476d58f3899c9221.zip skiboot-bc66fb67aee6f9e6520120c2476d58f3899c9221.tar.gz skiboot-bc66fb67aee6f9e6520120c2476d58f3899c9221.tar.bz2 |
core/pci: Support PCI slot
Every PCIE bridge port or PHB is expected to be bound with PCI slot
, to which various PCI slot's functionalities are attached (e.g. power,
link, reset). This supports PCI slot:
* PCI slot is reprsented by "struct pci_slot".
* "struct pci_slot_ops" represents the functions supported on the
PCI slot. It's initialized by PCI slot core at the beginning and
allowed to be overrided by platform partially or completely.
* On PCI hot plugging event, the PCI devices behind the slot are
enumarated. Device sub-tree is populated and sent to OS by OPAL
message.
* On PCI hot unplugging event, the PCI devices behind the slot are
destroyed. Device sub-tree is removed and the slot is powered off.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'include')
-rw-r--r-- | include/opal-api.h | 10 | ||||
-rw-r--r-- | include/pci-slot.h | 255 | ||||
-rw-r--r-- | include/pci.h | 66 | ||||
-rw-r--r-- | include/platform.h | 1 |
4 files changed, 277 insertions, 55 deletions
diff --git a/include/opal-api.h b/include/opal-api.h index 2f91715..b4d96b8 100644 --- a/include/opal-api.h +++ b/include/opal-api.h @@ -376,6 +376,16 @@ enum OpalPciMaskAction { OPAL_MASK_ERROR_TYPE = 1 }; +enum OpalPciSlotPresence { + OPAL_PCI_SLOT_EMPTY = 0, + OPAL_PCI_SLOT_PRESENT = 1 +}; + +enum OpalPciSlotPower { + OPAL_PCI_SLOT_POWER_OFF = 0, + OPAL_PCI_SLOT_POWER_ON = 1 +}; + enum OpalSlotLedType { OPAL_SLOT_LED_TYPE_ID = 0, /* IDENTIFY LED */ OPAL_SLOT_LED_TYPE_FAULT = 1, /* FAULT LED */ diff --git a/include/pci-slot.h b/include/pci-slot.h new file mode 100644 index 0000000..cf22432 --- /dev/null +++ b/include/pci-slot.h @@ -0,0 +1,255 @@ +/* Copyright 2013-2016 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __PCI_SLOT_H +#define __PCI_SLOT_H + +#include <opal.h> +#include <device.h> +#include <timebase.h> +#include <timer.h> +#include <ccan/list/list.h> + +/* + * PCI Slot Info: Wired Lane Values + * + * Values 0 to 6 match slot map 1005. In case of *any* change here + * make sure to keep the lxvpd.c parsing code in sync *and* the + * corresponding label strings in pci.c + */ +#define PCI_SLOT_WIRED_LANES_UNKNOWN 0x00 +#define PCI_SLOT_WIRED_LANES_PCIE_X1 0x01 +#define PCI_SLOT_WIRED_LANES_PCIE_X2 0x02 +#define PCI_SLOT_WIRED_LANES_PCIE_X4 0x03 +#define PCI_SLOT_WIRED_LANES_PCIE_X8 0x04 +#define PCI_SLOT_WIRED_LANES_PCIE_X16 0x05 +#define PCI_SLOT_WIRED_LANES_PCIE_X32 0x06 +#define PCI_SLOT_WIRED_LANES_PCIX_32 0x07 +#define PCI_SLOT_WIRED_LANES_PCIX_64 0x08 + +/* PCI Slot Info: Bus Clock Values */ +#define PCI_SLOT_BUS_CLK_RESERVED 0x00 +#define PCI_SLOT_BUS_CLK_GEN_1 0x01 +#define PCI_SLOT_BUS_CLK_GEN_2 0x02 +#define PCI_SLOT_BUS_CLK_GEN_3 0x03 + +/* PCI Slot Info: Connector Type Values */ +#define PCI_SLOT_CONNECTOR_PCIE_EMBED 0x00 +#define PCI_SLOT_CONNECTOR_PCIE_X1 0x01 +#define PCI_SLOT_CONNECTOR_PCIE_X2 0x02 +#define PCI_SLOT_CONNECTOR_PCIE_X4 0x03 +#define PCI_SLOT_CONNECTOR_PCIE_X8 0x04 +#define PCI_SLOT_CONNECTOR_PCIE_X16 0x05 +#define PCI_SLOT_CONNECTOR_PCIE_NS 0x0E /* Non-Standard */ + +/* PCI Slot Info: Card Description Values */ +#define PCI_SLOT_DESC_NON_STANDARD 0x00 /* Embed/Non-Standard */ +#define PCI_SLOT_DESC_PCIE_FH_FL 0x00 /* Full Height, Full Length */ +#define PCI_SLOT_DESC_PCIE_FH_HL 0x01 /* Full Height, Half Length */ +#define PCI_SLOT_DESC_PCIE_HH_FL 0x02 /* Half Height, Full Length */ +#define PCI_SLOT_DESC_PCIE_HH_HL 0x03 /* Half Height, Half Length */ + +/* PCI Slot Info: Mechanicals Values */ +#define PCI_SLOT_MECH_NONE 0x00 +#define PCI_SLOT_MECH_RIGHT 0x01 +#define PCI_SLOT_MECH_LEFT 0x02 +#define PCI_SLOT_MECH_RIGHT_LEFT 0x03 + +/* PCI Slot Info: Power LED Control Values */ +#define PCI_SLOT_PWR_LED_CTL_NONE 0x00 /* No Control */ +#define PCI_SLOT_PWR_LED_CTL_FSP 0x01 /* FSP Controlled */ +#define PCI_SLOT_PWR_LED_CTL_KERNEL 0x02 /* Kernel Controlled */ + +/* PCI Slot Info: ATTN LED Control Values */ +#define PCI_SLOT_ATTN_LED_CTL_NONE 0x00 /* No Control */ +#define PCI_SLOT_ATTN_LED_CTL_FSP 0x01 /* FSP Controlled */ +#define PCI_SLOT_ATTN_LED_CTL_KERNEL 0x02 /* Kernel Controlled */ + +/* Attention LED */ +#define PCI_SLOT_ATTN_LED_OFF 0 +#define PCI_SLOT_ATTN_LED_ON 1 +#define PCI_SLOT_ATTN_LED_BLINK 2 + +/* Power state */ +#define PCI_SLOT_POWER_OFF 0 +#define PCI_SLOT_POWER_ON 1 + +/* + * We have hard and soft reset for slot. Hard reset requires + * power-off and then power-on, but soft reset only resets + * secondary bus. + */ +struct pci_slot; +struct pci_slot_ops { + /* For slot management */ + int64_t (*get_presence_state)(struct pci_slot *slot, uint8_t *val); + int64_t (*get_link_state)(struct pci_slot *slot, uint8_t *val); + int64_t (*get_power_state)(struct pci_slot *slot, uint8_t *val); + int64_t (*get_attention_state)(struct pci_slot *slot, uint8_t *val); + int64_t (*get_latch_state)(struct pci_slot *slot, uint8_t *val); + int64_t (*set_power_state)(struct pci_slot *slot, uint8_t val); + int64_t (*set_attention_state)(struct pci_slot *slot, uint8_t val); + + /* SM based functions for reset */ + void (*prepare_link_change)(struct pci_slot *slot, bool is_up); + int64_t (*poll_link)(struct pci_slot *slot); + int64_t (*creset)(struct pci_slot *slot); + int64_t (*freset)(struct pci_slot *slot); + int64_t (*pfreset)(struct pci_slot *slot); + int64_t (*hreset)(struct pci_slot *slot); + int64_t (*poll)(struct pci_slot *slot); + + /* Auxillary functions */ + void (*add_properties)(struct pci_slot *slot, struct dt_node *np); +}; + +/* + * The PCI slot state is split up into base and number. With this + * design, the individual platforms can introduce their own PCI + * slot states with addition to the base. Eventually, the base + * state can be recognized by PCI slot core. + */ +#define PCI_SLOT_STATE_MASK 0xFFFFFF00 +#define PCI_SLOT_STATE_NORMAL 0x00000000 +#define PCI_SLOT_STATE_LINK 0x00000100 +#define PCI_SLOT_STATE_LINK_START_POLL 0x00000101 +#define PCI_SLOT_STATE_LINK_DELAY_FINALIZED 0x00000102 +#define PCI_SLOT_STATE_LINK_POLLING 0x00000103 +#define PCI_SLOT_STATE_HRESET 0x00000200 +#define PCI_SLOT_STATE_HRESET_START 0x00000201 +#define PCI_SLOT_STATE_HRESET_HOLD 0x00000202 +#define PCI_SLOT_STATE_FRESET 0x00000300 +#define PCI_SLOT_STATE_FRESET_POWER_OFF 0x00000301 +#define PCI_SLOT_STATE_PFRESET 0x00000400 +#define PCI_SLOT_STATE_PFRESET_START 0x00000401 +#define PCI_SLOT_STATE_CRESET 0x00000500 +#define PCI_SLOT_STATE_CRESET_START 0x00000501 +#define PCI_SLOT_STATE_GPOWER 0x00000600 +#define PCI_SLOT_STATE_GPOWER_START 0x00000601 +#define PCI_SLOT_STATE_SPOWER 0x00000700 +#define PCI_SLOT_STATE_SPOWER_START 0x00000701 +#define PCI_SLOT_STATE_SPOWER_DONE 0x00000702 +#define PCI_SLOT_STATE_GPRESENCE 0x00000800 +#define PCI_SLOT_STATE_GPRESENCE_START 0x00000801 + + +struct pci_slot { + uint32_t flags; +#define PCI_SLOT_FLAG_BOOTUP 0x1 + + struct phb *phb; + struct pci_device *pd; + + /* Identifier */ + uint64_t id; + struct timer timer; + uint64_t async_token; + uint8_t power_state; + + /* Slot information */ + uint8_t pluggable; + uint8_t power_ctl; + uint8_t power_led_ctl; + uint8_t attn_led_ctl; + uint8_t connector_type; + uint8_t card_desc; + uint8_t card_mech; + uint8_t wired_lanes; + + /* + * PCI slot is driven by state machine with polling function. + * @delay_tgt_tb tracks the current delay while @retries has + * the left rounds of delays. They should be set prior to + * switching next PCI slot state and changed (decreased) + * accordingly in the polling function. + */ + uint32_t state; + uint32_t retry_state; + uint32_t link_cap; + uint32_t slot_cap; + uint64_t delay_tgt_tb; + uint64_t retries; + struct pci_slot_ops ops; + void *data; +}; + +#define PCI_SLOT_ID_PREFIX 0x8000000000000000 +#define PCI_SLOT_ID(phb, bdfn) \ + (PCI_SLOT_ID_PREFIX | ((uint64_t)(bdfn) << 16) | (phb)->opal_id) +#define PCI_PHB_SLOT_ID(phb) ((phb)->opal_id) +#define PCI_SLOT_PHB_INDEX(id) ((id) & 0xfffful) +#define PCI_SLOT_BDFN(id) (((id) >> 16) & 0xfffful) + +static inline uint32_t pci_slot_add_flags(struct pci_slot *slot, + uint32_t flags) +{ + uint32_t old = 0; + + if (slot) { + old = slot->flags; + slot->flags |= flags; + } + + return old; +} + +static inline bool pci_slot_has_flags(struct pci_slot *slot, + uint32_t flags) +{ + if (!slot) + return false; + + if ((slot->flags & flags) == flags) + return true; + + return false; +} + +static inline uint32_t pci_slot_remove_flags(struct pci_slot *slot, + uint32_t flags) +{ + uint32_t old = 0; + + if (slot) { + old = slot->flags; + slot->flags &= ~flags; + } + + return old; +} + +static inline void pci_slot_set_state(struct pci_slot *slot, uint32_t state) +{ + if (slot) + slot->state = state; +} + +static inline uint64_t pci_slot_set_sm_timeout(struct pci_slot *slot, + uint64_t dur) +{ + if (slot) + slot->delay_tgt_tb = mftb() + dur; + return dur; +} + +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 void pci_slot_add_dt_properties(struct pci_slot *slot, + struct dt_node *np); +extern struct pci_slot *pci_slot_find(uint64_t id); +#endif /* __PCI_SLOT_H */ diff --git a/include/pci.h b/include/pci.h index 69be49e..486b712 100644 --- a/include/pci.h +++ b/include/pci.h @@ -22,60 +22,6 @@ #include <lock.h> #include <ccan/list/list.h> -/* PCI Slot Info: Wired Lane Values - * - * Values 0 to 6 match slot map 1005. In case of *any* change here - * make sure to keep the lxvpd.c parsing code in sync *and* the - * corresponding label strings in pci.c - */ -#define PCI_SLOT_WIRED_LANES_UNKNOWN 0x00 -#define PCI_SLOT_WIRED_LANES_PCIE_X1 0x01 -#define PCI_SLOT_WIRED_LANES_PCIE_X2 0x02 -#define PCI_SLOT_WIRED_LANES_PCIE_X4 0x03 -#define PCI_SLOT_WIRED_LANES_PCIE_X8 0x04 -#define PCI_SLOT_WIRED_LANES_PCIE_X16 0x05 -#define PCI_SLOT_WIRED_LANES_PCIE_X32 0x06 -#define PCI_SLOT_WIRED_LANES_PCIX_32 0x07 -#define PCI_SLOT_WIRED_LANES_PCIX_64 0x08 - -/* PCI Slot Info: Bus Clock Values */ -#define PCI_SLOT_BUS_CLK_RESERVED 0x00 -#define PCI_SLOT_BUS_CLK_GEN_1 0x01 -#define PCI_SLOT_BUS_CLK_GEN_2 0x02 -#define PCI_SLOT_BUS_CLK_GEN_3 0x03 - -/* PCI Slot Info: Connector Type Values */ -#define PCI_SLOT_CONNECTOR_PCIE_EMBED 0x00 -#define PCI_SLOT_CONNECTOR_PCIE_X1 0x01 -#define PCI_SLOT_CONNECTOR_PCIE_X2 0x02 -#define PCI_SLOT_CONNECTOR_PCIE_X4 0x03 -#define PCI_SLOT_CONNECTOR_PCIE_X8 0x04 -#define PCI_SLOT_CONNECTOR_PCIE_X16 0x05 -#define PCI_SLOT_CONNECTOR_PCIE_NS 0x0E /* Non-Standard */ - -/* PCI Slot Info: Card Description Values */ -#define PCI_SLOT_DESC_NON_STANDARD 0x00 /* Embed/Non-Standard Connector */ -#define PCI_SLOT_DESC_PCIE_FH_FL 0x00 /* Full Height, Full Length */ -#define PCI_SLOT_DESC_PCIE_FH_HL 0x01 /* Full Height, Half Length */ -#define PCI_SLOT_DESC_PCIE_HH_FL 0x02 /* Half Height, Full Length */ -#define PCI_SLOT_DESC_PCIE_HH_HL 0x03 /* Half Height, Half Length */ - -/* PCI Slot Info: Mechanicals Values */ -#define PCI_SLOT_MECH_NONE 0x00 -#define PCI_SLOT_MECH_RIGHT 0x01 -#define PCI_SLOT_MECH_LEFT 0x02 -#define PCI_SLOT_MECH_RIGHT_LEFT 0x03 - -/* PCI Slot Info: Power LED Control Values */ -#define PCI_SLOT_PWR_LED_CTL_NONE 0x00 /* No Control */ -#define PCI_SLOT_PWR_LED_CTL_FSP 0x01 /* FSP Controlled */ -#define PCI_SLOT_PWR_LED_CTL_KERNEL 0x02 /* Kernel Controlled */ - -/* PCI Slot Info: ATTN LED Control Values */ -#define PCI_SLOT_ATTN_LED_CTL_NONE 0x00 /* No Control */ -#define PCI_SLOT_ATTN_LED_CTL_FSP 0x01 /* FSP Controlled */ -#define PCI_SLOT_ATTN_LED_CTL_KERNEL 0x02 /* Kernel Controlled */ - /* PCI Slot Entry Information */ struct pci_slot_info { char label[16]; @@ -151,6 +97,7 @@ struct pci_device { struct list_head pcrf; struct dt_node *dn; + struct pci_slot *slot; struct pci_slot_info *slot_info; struct pci_device *parent; struct list_head children; @@ -462,6 +409,7 @@ struct phb { uint32_t mps; /* PCI-X only slot info, for PCI-E this is in the RC bridge */ + struct pci_slot *slot; struct pci_slot_info *slot_info; /* Base location code used to generate the children one */ @@ -519,7 +467,15 @@ static inline int64_t pci_cfg_write32(struct phb *phb, uint32_t bdfn, } /* Utilities */ - +extern void pci_remove_bus(struct phb *phb, struct list_head *list); +extern uint8_t pci_scan_bus(struct phb *phb, uint8_t bus, uint8_t max_bus, + struct list_head *list, struct pci_device *parent, + bool scan_downstream); +extern void pci_add_device_nodes(struct phb *phb, + struct list_head *list, + struct dt_node *parent_node, + struct pci_lsi_state *lstate, + uint8_t swizzle); extern int64_t pci_find_cap(struct phb *phb, uint16_t bdfn, uint8_t cap); extern int64_t pci_find_ecap(struct phb *phb, uint16_t bdfn, uint16_t cap, uint8_t *version); diff --git a/include/platform.h b/include/platform.h index f1bdc30..d07994f 100644 --- a/include/platform.h +++ b/include/platform.h @@ -20,6 +20,7 @@ /* Some fwd declarations for types used further down */ struct phb; struct pci_device; +struct pci_slot; struct errorlog; enum resource_id { |