[Skiboot] [PATCH v10 16/17] core/opal: Use PCI slot and new APIs for slot states

Alistair Popple alistair at popple.id.au
Thu May 5 19:23:03 AEST 2016


On Tue, 3 May 2016 15:04:41 Gavin Shan wrote:
> The various reset requests are completed by PHB's callbacks. All
> of them (except reset on IODA table or error injection) are covered
> by PCI slot. opal_pci_poll() faces similar situation.
> 
> This reimplements opal_pci_reset() and opal_pci_poll() based on
> the callbacks provided by PCI slot instead of PHB. Also, couple of
> new APIs are introduced based on the callbacks in PCI slot as below:
> 
>    * opal_pci_get_presence_state(): Check if there is adapter presented
>      behind the specified PHB or PCI slot.
>    * opal_pci_get_power_state(): Returns power supply state (on or off)
>      on the specified PHB or PCI slot.
>    * opal_pci_set_power_state(): Sets power supply state (on or off)
>      on the specified PHB or PCI slot.
>    * opal_pci_poll2(): Poll for PCI slot state. It accepts two arguments
>      while opal_pci_poll() accepts only one.
> 
> Eventually, the definition of unused PHB's callbacks are removed.
> 
> Signed-off-by: Gavin Shan <gwshan at linux.vnet.ibm.com>
> ---
>  core/pci-opal.c    | 174 +++++++++++++++++++++++++++++++++++++++++++++--------
>  include/opal-api.h |   6 +-
>  include/pci.h      |  72 ----------------------
>  3 files changed, 153 insertions(+), 99 deletions(-)
> 
> diff --git a/core/pci-opal.c b/core/pci-opal.c
> index 40eda39..f798c52 100644
> --- a/core/pci-opal.c
> +++ b/core/pci-opal.c
> @@ -18,6 +18,7 @@
>  #include <opal-api.h>
>  #include <pci.h>
>  #include <pci-cfg.h>
> +#include <pci-slot.h>
>  #include <timebase.h>
>  
>  #define OPAL_PCICFG_ACCESS(op, cb, type)	\
> @@ -461,16 +462,15 @@ static int64_t opal_pci_map_pe_dma_window_real(uint64_t phb_id,
>  }
>  opal_call(OPAL_PCI_MAP_PE_DMA_WINDOW_REAL, opal_pci_map_pe_dma_window_real, 5);
>  
> -static int64_t opal_pci_reset(uint64_t phb_id, uint8_t reset_scope,
> +static int64_t opal_pci_reset(uint64_t id, uint8_t reset_scope,
>                                uint8_t assert_state)
>  {
> -	struct phb *phb = pci_get_phb(phb_id);
> +	struct pci_slot *slot = pci_slot_find(id);
> +	struct phb *phb = slot ? slot->phb : NULL;
>  	int64_t rc = OPAL_SUCCESS;
>  
> -	if (!phb)
> +	if (!slot || !phb)
>  		return OPAL_PARAMETER;
> -	if (!phb->ops)
> -		return OPAL_UNSUPPORTED;
>  	if (assert_state != OPAL_ASSERT_RESET &&
>  	    assert_state != OPAL_DEASSERT_RESET)
>  		return OPAL_PARAMETER;
> @@ -479,18 +479,22 @@ static int64_t opal_pci_reset(uint64_t phb_id, uint8_t reset_scope,
>  
>  	switch(reset_scope) {
>  	case OPAL_RESET_PHB_COMPLETE:
> -		if (!phb->ops->complete_reset) {
> +		/* Complete reset is applicable to PHB slot only */
> +		if (!slot->ops.creset || slot->pd) {
>  			rc = OPAL_UNSUPPORTED;
>  			break;
>  		}
>  
> -		rc = phb->ops->complete_reset(phb, assert_state);
> +		if (assert_state != OPAL_ASSERT_RESET)
> +			break;
> +
> +		rc = slot->ops.creset(slot);
>  		if (rc < 0)
> -			prerror("PHB#%d: Failure on complete reset, rc=%lld\n",
> -				phb->opal_id, rc);
> +			prlog(PR_ERR, "SLOT-%016llx: Error %lld on complete reset\n",
> +			      slot->id, rc);
>  		break;
>  	case OPAL_RESET_PCI_FUNDAMENTAL:
> -		if (!phb->ops->fundamental_reset) {
> +		if (!slot->ops.freset) {
>  			rc = OPAL_UNSUPPORTED;
>  			break;
>  		}
> @@ -499,13 +503,13 @@ static int64_t opal_pci_reset(uint64_t phb_id, uint8_t reset_scope,
>  		if (assert_state != OPAL_ASSERT_RESET)
>  			break;
>  
> -		rc = phb->ops->fundamental_reset(phb);
> +		rc = slot->ops.freset(slot);
>  		if (rc < 0)
> -			prerror("PHB#%d: Failure on fundamental reset, rc=%lld\n",
> -				phb->opal_id, rc);
> +			prlog(PR_ERR, "SLOT-%016llx: Error %lld on fundamental reset\n",
> +			      slot->id, rc);
>  		break;
>  	case OPAL_RESET_PCI_HOT:
> -		if (!phb->ops->hot_reset) {
> +		if (!slot->ops.hreset) {
>  			rc = OPAL_UNSUPPORTED;
>  			break;
>  		}
> @@ -514,22 +518,34 @@ static int64_t opal_pci_reset(uint64_t phb_id, uint8_t reset_scope,
>  		if (assert_state != OPAL_ASSERT_RESET)
>  			break;
>  
> -		rc = phb->ops->hot_reset(phb);
> +		rc = slot->ops.hreset(slot);
>  		if (rc < 0)
> -			prerror("PHB#%d: Failure on hot reset, rc=%lld\n",
> -				phb->opal_id, rc);
> +			prlog(PR_ERR, "SLOT-%016llx: Error %lld on hot reset\n",
> +			      slot->id, rc);
>  		break;
>  	case OPAL_RESET_PCI_IODA_TABLE:
> +		/* It's allowed on PHB slot only */
> +		if (slot->pd || !phb->ops || !phb->ops->ioda_reset) {
> +			rc = OPAL_UNSUPPORTED;
> +			break;
> +		}
> +
>  		if (assert_state != OPAL_ASSERT_RESET)
>  			break;
> -		if (phb->ops->ioda_reset)
> -			phb->ops->ioda_reset(phb, true);
> +
> +		rc = phb->ops->ioda_reset(phb, true);
>  		break;
>  	case OPAL_RESET_PHB_ERROR:
> +		/* It's allowed on PHB slot only */
> +		if (slot->pd || !phb->ops || !phb->ops->papr_errinjct_reset) {
> +			rc = OPAL_UNSUPPORTED;
> +			break;
> +		}
> +
>  		if (assert_state != OPAL_ASSERT_RESET)
>  			break;
> -		if (phb->ops->papr_errinjct_reset)
> -			phb->ops->papr_errinjct_reset(phb);
> +
> +		rc = phb->ops->papr_errinjct_reset(phb);
>  		break;
>  	default:
>  		rc = OPAL_UNSUPPORTED;
> @@ -560,18 +576,19 @@ static int64_t opal_pci_reinit(uint64_t phb_id,
>  }
>  opal_call(OPAL_PCI_REINIT, opal_pci_reinit, 3);
>  
> -static int64_t opal_pci_poll(uint64_t phb_id)
> +static int64_t opal_pci_poll(uint64_t id)
>  {
> -	struct phb *phb = pci_get_phb(phb_id);
> +	struct pci_slot *slot = pci_slot_find(id);
> +	struct phb *phb = slot ? slot->phb : NULL;
>  	int64_t rc;
>  
> -	if (!phb)
> +	if (!slot || !phb)
>  		return OPAL_PARAMETER;
> -	if (!phb->ops || !phb->ops->poll)
> +	if (!slot->ops.poll)
>  		return OPAL_UNSUPPORTED;
>  
>  	phb_lock(phb);
> -	rc = phb->ops->poll(phb);
> +	rc = slot->ops.poll(slot, NULL);
>  	phb_unlock(phb);
>  
>  	/* Return milliseconds for caller to sleep: round up */
> @@ -585,6 +602,111 @@ static int64_t opal_pci_poll(uint64_t phb_id)
>  }
>  opal_call(OPAL_PCI_POLL, opal_pci_poll, 1);
>  
> +static int64_t opal_pci_get_presence_state(uint64_t id, uint64_t data)
> +{
> +	struct pci_slot *slot = pci_slot_find(id);
> +	struct phb *phb = slot ? slot->phb : NULL;
> +	uint8_t *presence = (uint8_t *)data;
> +	int64_t rc = OPAL_SUCCESS;
> +
> +	if (!slot || !phb)
> +		return OPAL_PARAMETER;
> +	if (!slot->ops.get_presence_status)
> +		return OPAL_UNSUPPORTED;
> +
> +	phb_lock(phb);
> +	rc = slot->ops.get_presence_status(slot, presence);
> +	phb_unlock(phb);
> +
> +	if (rc > 0) {
> +		rc = tb_to_msecs(rc);
> +		if (rc == 0)
> +			rc = 1;
> +	}
> +
> +	return rc;
> +}
> +opal_call(OPAL_PCI_GET_PRESENCE_STATE, opal_pci_get_presence_state, 2);
> +
> +static int64_t opal_pci_get_power_state(uint64_t id, uint64_t data)
> +{
> +	struct pci_slot *slot = pci_slot_find(id);
> +	struct phb *phb = slot ? slot->phb : NULL;
> +	uint8_t *power_state = (uint8_t *)data;
> +	int64_t rc = OPAL_SUCCESS;
> +
> +	if (!slot || !phb)
> +		return OPAL_PARAMETER;
> +	if (!slot->ops.get_power_status)
> +		return OPAL_UNSUPPORTED;
> +
> +	phb_lock(phb);
> +	rc = slot->ops.get_power_status(slot, power_state);
> +	phb_unlock(phb);
> +
> +	if (rc > 0) {
> +		rc = tb_to_msecs(rc);
> +		if (rc == 0)
> +			rc = 1;
> +	}
> +
> +	return rc;
> +}
> +opal_call(OPAL_PCI_GET_POWER_STATE, opal_pci_get_power_state, 2);
> +
> +static int64_t opal_pci_set_power_state(uint64_t id, uint64_t data)
> +{
> +	struct pci_slot *slot = pci_slot_find(id);
> +	struct phb *phb = slot ? slot->phb : NULL;
> +	uint8_t *power_state = (uint8_t *)data;
> +	int64_t rc = OPAL_SUCCESS;
> +
> +	if (!slot || !phb)
> +		return OPAL_PARAMETER;
> +	if (!slot->ops.get_power_status)
> +		return OPAL_UNSUPPORTED;
> +
> +	phb_lock(phb);
> +	rc = slot->ops.set_power_status(slot, *power_state);

As we discussed offline there needs to be much better separation of the
platform specific parts and the generic parts of setting the power state.

At the moment the calls to update device tree, etc. are all in the platform
specific code but they should really appear here as it will apply to all platforms
that eventually support hotplug. The platform specific code should only deal with
platform dependent functions such as actually removing power from the slots which
is completely different on say an FSP system versus a non-FSP system.

> +	phb_unlock(phb);
> +
> +	if (rc > 0) {
> +		rc = tb_to_msecs(rc);
> +		if (rc == 0)
> +			rc = 1;
> +	}
> +
> +	return rc;
> +}
> +opal_call(OPAL_PCI_SET_POWER_STATE, opal_pci_set_power_state, 2);
> +
> +static int64_t opal_pci_poll2(uint64_t id, uint64_t data)
> +{
> +	struct pci_slot *slot = pci_slot_find(id);
> +	struct phb *phb = slot ? slot->phb : NULL;
> +	uint8_t *state = (uint8_t *)data;
> +	int64_t rc;
> +
> +	if (!slot || !phb)
> +		return OPAL_PARAMETER;
> +	if (!slot->ops.poll)
> +		return OPAL_UNSUPPORTED;
> +
> +	phb_lock(phb);
> +	rc = slot->ops.poll(slot, state);
> +	phb_unlock(phb);
> +
> +	/* Return milliseconds for caller to sleep: round up */
> +	if (rc > 0) {
> +		rc = tb_to_msecs(rc);
> +		if (rc == 0)
> +			rc = 1;
> +	}
> +
> +	return rc;
> +}
> +opal_call(OPAL_PCI_POLL2, opal_pci_poll2, 2);
> +
>  static int64_t opal_pci_set_phb_tce_memory(uint64_t phb_id,
>  					   uint64_t tce_mem_addr,
>  					   uint64_t tce_mem_size)
> diff --git a/include/opal-api.h b/include/opal-api.h
> index 50de6d1..d7b5a1e 100644
> --- a/include/opal-api.h
> +++ b/include/opal-api.h
> @@ -164,7 +164,11 @@
>  #define OPAL_CEC_REBOOT2			116
>  #define OPAL_CONSOLE_FLUSH			117
>  #define OPAL_GET_DEVICE_TREE			118
> -#define OPAL_LAST				118
> +#define OPAL_PCI_GET_PRESENCE_STATE		119
> +#define OPAL_PCI_GET_POWER_STATE		120
> +#define OPAL_PCI_SET_POWER_STATE		121
> +#define OPAL_PCI_POLL2				122
> +#define OPAL_LAST				122
>  
>  /* Device tree flags */
>  
> diff --git a/include/pci.h b/include/pci.h
> index 1326a84..048ef0d 100644
> --- a/include/pci.h
> +++ b/include/pci.h
> @@ -293,78 +293,6 @@ struct phb_ops {
>  	 */
>  	int64_t (*pci_msi_eoi)(struct phb *phb, uint32_t hwirq);
>  
> -	/*
> -	 * Slot control
> -	 */
> -
> -	/* presence_detect - Check for a present device
> -	 *
> -	 * Immediate return of:
> -	 *
> -	 * OPAL_SHPC_DEV_NOT_PRESENT = 0,
> -	 * OPAL_SHPC_DEV_PRESENT = 1
> -	 *
> -	 * or a negative OPAL error code
> -	 */
> -	int64_t (*presence_detect)(struct phb *phb);
> -
> -	/* link_state - Check link state
> -	 *
> -	 * Immediate return of:
> -	 *
> -	 * OPAL_SHPC_LINK_DOWN = 0,
> -	 * OPAL_SHPC_LINK_UP_x1 = 1,
> -	 * OPAL_SHPC_LINK_UP_x2 = 2,
> -	 * OPAL_SHPC_LINK_UP_x4 = 4,
> -	 * OPAL_SHPC_LINK_UP_x8 = 8,
> -	 * OPAL_SHPC_LINK_UP_x16 = 16,
> -	 * OPAL_SHPC_LINK_UP_x32 = 32
> -	 *
> -	 * or a negative OPAL error code
> -	 */
> -	int64_t (*link_state)(struct phb *phb);
> -
> -	/* power_state - Check slot power state
> -	 *
> -	 * Immediate return of:
> -	 *
> -	 * OPAL_SLOT_POWER_OFF = 0,
> -	 * OPAL_SLOT_POWER_ON = 1,
> -	 *
> -	 * or a negative OPAL error code
> -	 */
> -	int64_t (*power_state)(struct phb *phb);
> -
> -	/* slot_power_off - Start slot power off sequence
> -	 *
> -	 * Asynchronous function, returns a positive delay
> -	 * or a negative error code
> -	 */
> -	int64_t (*slot_power_off)(struct phb *phb);
> -
> -	/* slot_power_on - Start slot power on sequence
> -	 *
> -	 * Asynchronous function, returns a positive delay
> -	 * or a negative error code.
> -	 */
> -	int64_t (*slot_power_on)(struct phb *phb);
> -
> -	/* PHB power off and on after complete init */
> -	int64_t (*complete_reset)(struct phb *phb, uint8_t assert);
> -
> -	/* hot_reset - Hot Reset sequence */
> -	int64_t (*hot_reset)(struct phb *phb);
> -
> -	/* Fundamental reset */
> -	int64_t (*fundamental_reset)(struct phb *phb);
> -
> -	/* poll - Poll and advance asynchronous operations
> -	 *
> -	 * Returns a positive delay, 0 for success or a
> -	 * negative OPAL error code
> -	 */
> -	int64_t (*poll)(struct phb *phb);
> -
>  	/* Put phb in capi mode or pcie mode */
>  	int64_t (*set_capi_mode)(struct phb *phb, uint64_t mode, uint64_t pe_number);
>  
> 



More information about the Skiboot mailing list