blob: 5eabd5af5abc01cc2206d4664ae46d3e0c890925 [file] [log] [blame]
// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
/* Copyright 2013-2018 IBM Corp. */
#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 (*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 */