aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorGavin Shan <gwshan@linux.vnet.ibm.com>2016-06-10 15:03:42 +1000
committerStewart Smith <stewart@linux.vnet.ibm.com>2016-06-14 16:00:16 +1000
commitbc66fb67aee6f9e6520120c2476d58f3899c9221 (patch)
tree378f502d261691a66fc19ff96ebf301c22c9c7fc /include
parent0bf9c3c44bf1bde1c7bec86d33a6e3ccb6e56c90 (diff)
downloadskiboot-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.h10
-rw-r--r--include/pci-slot.h255
-rw-r--r--include/pci.h66
-rw-r--r--include/platform.h1
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 {