/* 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 #include #include #include #include /* * 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 (*hreset)(struct pci_slot *slot); int64_t (*run_sm)(struct pci_slot *slot); int64_t (*completed_sm_run)(struct pci_slot *slot, uint64_t err); /* 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 (PCI_SLOT_STATE_LINK + 1) #define PCI_SLOT_STATE_LINK_DELAY_FINALIZED (PCI_SLOT_STATE_LINK + 2) #define PCI_SLOT_STATE_LINK_POLLING (PCI_SLOT_STATE_LINK + 3) #define PCI_SLOT_STATE_HRESET 0x00000200 #define PCI_SLOT_STATE_HRESET_START (PCI_SLOT_STATE_HRESET + 1) #define PCI_SLOT_STATE_HRESET_HOLD (PCI_SLOT_STATE_HRESET + 2) #define PCI_SLOT_STATE_FRESET 0x00000300 #define PCI_SLOT_STATE_FRESET_POWER_OFF (PCI_SLOT_STATE_FRESET + 1) #define PCI_SLOT_STATE_CRESET 0x00000400 #define PCI_SLOT_STATE_CRESET_START (PCI_SLOT_STATE_CRESET + 1) #define PCI_SLOT_STATE_GPOWER 0x00000500 #define PCI_SLOT_STATE_GPOWER_START (PCI_SLOT_STATE_GPOWER + 1) #define PCI_SLOT_STATE_SPOWER 0x00000600 #define PCI_SLOT_STATE_SPOWER_START (PCI_SLOT_STATE_SPOWER + 1) #define PCI_SLOT_STATE_SPOWER_DONE (PCI_SLOT_STATE_SPOWER + 2) #define PCI_SLOT_STATE_GPRESENCE 0x00000700 #define PCI_SLOT_STATE_GPRESENCE_START (PCI_SLOT_STATE_GPRESENCE + 1) struct pci_slot { uint32_t flags; #define PCI_SLOT_FLAG_BOOTUP 0x1 #define PCI_SLOT_FLAG_FORCE_POWERON 0x2 #define PCI_SLOT_FLAG_BROKEN_PDC 0x4 #define PCI_SLOT_FLAG_ENFORCE 0x8 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 surprise_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; uint8_t power_limit; /* * 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; uint16_t pcie_cap; uint32_t link_cap; uint32_t slot_cap; uint64_t delay_tgt_tb; uint64_t retries; uint64_t link_retries; struct pci_slot_ops ops; struct pci_slot *peer_slot; void *data; }; #define PCI_SLOT_ID_PREFIX 0x8000000000000000UL #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 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); extern void pci_slot_add_loc(struct pci_slot *slot, struct dt_node *np, const char *label); /* DT based slot map */ extern struct dt_node *dt_slots; extern struct dt_node *map_pci_dev_to_slot(struct phb *phb, struct pci_device *pd); #endif /* __PCI_SLOT_H */