diff mbox

[v4,08/10] core/opal: Switch to PCI slot

Message ID 1424155737-29640-9-git-send-email-gwshan@linux.vnet.ibm.com
State Superseded
Delegated to: Benjamin Herrenschmidt
Headers show

Commit Message

Gavin Shan Feb. 17, 2015, 6:48 a.m. UTC
Apart from IODA table and error injection reset, we use PCI slot
to help completing various resets. It's notable that bit#0 of
"id" is indicator of compound (PHB OPAL ID + Slot ID), or just
slot ID. In order for back-compatibility, PHB OPAL ID is stored
in bits[48:63] while slot ID stored in bits[32:47].

The patch also adds two more OPAL APIs to help managing PCI slots:
opal_pci_get_power_status() and opal_pci_get_presence_status().
Those two APIs might need run internal state machine to get the
final result and opal_pci_poll() is involved for that.

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
 core/pci-opal.c | 150 +++++++++++++++++++++++++++++++++++---------------------
 include/opal.h  |   9 ++--
 include/pci.h   |  72 ---------------------------
 3 files changed, 98 insertions(+), 133 deletions(-)

Comments

Stewart Smith Feb. 18, 2015, 2 a.m. UTC | #1
Gavin Shan <gwshan@linux.vnet.ibm.com> writes:
> -opal_call(OPAL_PCI_POLL, opal_pci_poll, 1);
> +opal_call(OPAL_PCI_POLL, opal_pci_poll, 2);

This looks like a backwards incompatible change? I don't *think* we
could reasonably add another parameter and have old kernels still work
correctly?

It'd also be great if you could add documentation about the new (and
old) calls as well (in doc/opal-api/ )
Gavin Shan Feb. 18, 2015, 3:07 a.m. UTC | #2
On Wed, Feb 18, 2015 at 01:00:58PM +1100, Stewart Smith wrote:
>Gavin Shan <gwshan@linux.vnet.ibm.com> writes:
>> -opal_call(OPAL_PCI_POLL, opal_pci_poll, 1);
>> +opal_call(OPAL_PCI_POLL, opal_pci_poll, 2);
>
>This looks like a backwards incompatible change? I don't *think* we
>could reasonably add another parameter and have old kernels still work
>correctly?
>

Yes, the change looks subtle to ensure backwords compatibility. With
old firmware + new kernel, PCI slots won't be populated from kernel
side and we don't expect opal_pci_poll() to return additional PCI slot
power or presence status. For new firmware + old kernel, we shouldn't
call opal_pci_poll() when the slot in NORMAL state. Thus the firmware
won't return additional power or presence status and old kernel needn't
them as well.

>It'd also be great if you could add documentation about the new (and
>old) calls as well (in doc/opal-api/ )

I'll add doc/opal-api/opal-pci.txt seperately if you agree. It would
describe all PCI related OPAL calls.

Thanks,
Gavin
Stewart Smith Feb. 19, 2015, 5:02 a.m. UTC | #3
Gavin Shan <gwshan@linux.vnet.ibm.com> writes:
> I'll add doc/opal-api/opal-pci.txt seperately if you agree. It would
> describe all PCI related OPAL calls.

That'd be great! Separate patch is fine.
diff mbox

Patch

diff --git a/core/pci-opal.c b/core/pci-opal.c
index a1c6e7a..912e7ac 100644
--- a/core/pci-opal.c
+++ b/core/pci-opal.c
@@ -16,8 +16,9 @@ 
 
 #include <skiboot.h>
 #include <opal-api.h>
-#include <pci.h>
 #include <pci-cfg.h>
+#include <pci.h>
+#include <pci-slot.h>
 #include <timebase.h>
 #include <lock.h>
 
@@ -461,83 +462,95 @@  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,
-                              uint8_t assert_state)
+static int64_t opal_pci_ret_to_ms(int64_t val)
 {
-	struct phb *phb = pci_get_phb(phb_id);
+	/*
+	 * If the return value is positive, translate
+	 * it to milliseconds. Otherwise, the original
+	 * value is returned
+	 */
+	if (val > 0) {
+		val = tb_to_msecs(val);
+		if (val == 0)
+			val = 1;
+	}
+
+	return val;
+}
+
+static int64_t opal_pci_reset(uint64_t id,
+			      uint8_t reset_scope,
+			      uint8_t assert_state)
+{
+	struct pci_slot *slot = pci_slot_find(id);
 	int64_t rc = OPAL_SUCCESS;
 
-	if (!phb)
+	if (!slot || !slot->phb || !slot->phb->ops || !slot->phb->ops->lock)
 		return OPAL_PARAMETER;
-	if (!phb->ops)
-		return OPAL_UNSUPPORTED;
 	if (assert_state != OPAL_ASSERT_RESET &&
 	    assert_state != OPAL_DEASSERT_RESET)
 		return OPAL_PARAMETER;
 
-	phb->ops->lock(phb);
+	slot->phb->ops->lock(slot->phb);
 
 	switch(reset_scope) {
 	case OPAL_RESET_PHB_COMPLETE:
-		if (!phb->ops->complete_reset) {
+		if (assert_state != OPAL_ASSERT_RESET)
+			break;
+		if (!slot->ops.creset) {
 			rc = OPAL_UNSUPPORTED;
 			break;
 		}
 
-		rc = phb->ops->complete_reset(phb, assert_state);
-		if (rc < 0)
-			prerror("PHB#%d: Failure on complete reset, rc=%lld\n",
-				phb->opal_id, rc);
+		rc = slot->ops.creset(slot);
 		break;
 	case OPAL_RESET_PCI_FUNDAMENTAL:
-		if (!phb->ops->fundamental_reset) {
+		if (assert_state != OPAL_ASSERT_RESET)
+			break;
+		if (!slot->ops.freset) {
 			rc = OPAL_UNSUPPORTED;
 			break;
 		}
 
-		/* We need do nothing on deassert time */
-		if (assert_state != OPAL_ASSERT_RESET)
-			break;
-
-		rc = phb->ops->fundamental_reset(phb);
-		if (rc < 0)
-			prerror("PHB#%d: Failure on fundamental reset, rc=%lld\n",
-				phb->opal_id, rc);
+		rc = slot->ops.freset(slot);
 		break;
 	case OPAL_RESET_PCI_HOT:
-		if (!phb->ops->hot_reset) {
+		if (assert_state != OPAL_ASSERT_RESET)
+			break;
+		if (!slot->ops.hreset) {
 			rc = OPAL_UNSUPPORTED;
 			break;
 		}
 
-		/* We need do nothing on deassert time */
-		if (assert_state != OPAL_ASSERT_RESET)
-			break;
-
-		rc = phb->ops->hot_reset(phb);
-		if (rc < 0)
-			prerror("PHB#%d: Failure on hot reset, rc=%lld\n",
-				phb->opal_id, rc);
+		rc = slot->ops.hreset(slot);
 		break;
 	case OPAL_RESET_PCI_IODA_TABLE:
 		if (assert_state != OPAL_ASSERT_RESET)
 			break;
-		if (phb->ops->ioda_reset)
-			phb->ops->ioda_reset(phb, true);
+		if (!slot->phb->ops->ioda_reset) {
+			rc = OPAL_UNSUPPORTED;
+			break;
+		}
+
+		rc = slot->phb->ops->ioda_reset(slot->phb, true);
 		break;
 	case OPAL_RESET_PHB_ERROR:
 		if (assert_state != OPAL_ASSERT_RESET)
 			break;
-		if (phb->ops->papr_errinjct_reset)
-			phb->ops->papr_errinjct_reset(phb);
+		if (!slot->phb->ops->papr_errinjct_reset) {
+			rc = OPAL_UNSUPPORTED;
+			break;
+		}
+
+		rc = slot->phb->ops->papr_errinjct_reset(slot->phb);
 		break;
 	default:
 		rc = OPAL_UNSUPPORTED;
 	}
-	phb->ops->unlock(phb);
-	pci_put_phb(phb);
+	slot->phb->ops->unlock(slot->phb);
+	pci_put_phb(slot->phb);
 
-	return (rc > 0) ? tb_to_msecs(rc) : rc;
+	return opal_pci_ret_to_ms(rc);
 }
 opal_call(OPAL_PCI_RESET, opal_pci_reset, 3);
 
@@ -562,31 +575,58 @@  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_get_power_status(uint64_t id, uint8_t *val)
 {
-	struct phb *phb = pci_get_phb(phb_id);
-	int64_t rc;
+	struct pci_slot *slot = pci_slot_find(id);
+	int64_t rc = OPAL_SUCCESS;
 
-	if (!phb)
+	if (!slot || !slot->phb || !slot->phb->ops || !slot->phb->ops->lock)
 		return OPAL_PARAMETER;
-	if (!phb->ops || !phb->ops->poll)
+	if (!slot->ops.get_power_status)
 		return OPAL_UNSUPPORTED;
 
-	phb->ops->lock(phb);
-	rc = phb->ops->poll(phb);
-	phb->ops->unlock(phb);
-	pci_put_phb(phb);
+	slot->phb->ops->lock(slot->phb);
+	rc = slot->ops.get_power_status(slot, val);
+	slot->phb->ops->unlock(slot->phb);
+	pci_put_phb(slot->phb);
+	return opal_pci_ret_to_ms(rc);
+}
+opal_call(OPAL_PCI_GET_POWER_STATUS, opal_pci_get_power_status, 2);
 
-	/* Return milliseconds for caller to sleep: round up */
-	if (rc > 0) {
-		rc = tb_to_msecs(rc);
-		if (rc == 0)
-			rc = 1;
-	}
+static int64_t opal_pci_get_presence_status(uint64_t id, uint8_t *val)
+{
+	struct pci_slot *slot = pci_slot_find(id);
+	int64_t rc = OPAL_SUCCESS;
 
-	return rc;
+	if (!slot || !slot->phb || !slot->phb->ops || !slot->phb->ops->lock)
+		return OPAL_PARAMETER;
+	if (!slot->ops.get_presence_status)
+		return OPAL_UNSUPPORTED;
+
+	slot->phb->ops->lock(slot->phb);
+	rc = slot->ops.get_presence_status(slot, val);
+	slot->phb->ops->unlock(slot->phb);
+	pci_put_phb(slot->phb);
+	return opal_pci_ret_to_ms(rc);
+}
+opal_call(OPAL_PCI_GET_PRESENCE_STATUS, opal_pci_get_presence_status, 2);
+
+static int64_t opal_pci_poll(uint64_t id, uint8_t *val)
+{
+	struct pci_slot *slot = pci_slot_find(id);
+	int64_t rc;
+
+	if (!slot || !slot->phb || !slot->phb->ops || !slot->phb->ops->lock)
+		return OPAL_PARAMETER;
+
+	slot->phb->ops->lock(slot->phb);
+	rc = slot->ops.poll(slot, val);
+	slot->phb->ops->unlock(slot->phb);
+	pci_put_phb(slot->phb);
+
+	return opal_pci_ret_to_ms(rc);
 }
-opal_call(OPAL_PCI_POLL, opal_pci_poll, 1);
+opal_call(OPAL_PCI_POLL, opal_pci_poll, 2);
 
 static int64_t opal_pci_set_phb_tce_memory(uint64_t phb_id,
 					   uint64_t tce_mem_addr,
diff --git a/include/opal.h b/include/opal.h
index 0a57bd0..6300fb3 100644
--- a/include/opal.h
+++ b/include/opal.h
@@ -161,7 +161,9 @@ 
 #define OPAL_IPMI_SEND				107
 #define OPAL_IPMI_RECV				108
 #define OPAL_I2C_REQUEST			109
-#define OPAL_LAST				109
+#define OPAL_PCI_GET_POWER_STATUS		110
+#define OPAL_PCI_GET_PRESENCE_STATUS		111
+#define OPAL_LAST				111
 
 /* Device tree flags */
 
@@ -368,11 +370,6 @@  enum OpalPciResetState {
 	OPAL_ASSERT_RESET   = 1
 };
 
-enum OpalPciMaskAction {
-	OPAL_UNMASK_ERROR_TYPE = 0,
-	OPAL_MASK_ERROR_TYPE = 1
-};
-
 enum OpalSlotLedType {
 	OPAL_SLOT_LED_ID_TYPE = 0,
 	OPAL_SLOT_LED_FAULT_TYPE = 1
diff --git a/include/pci.h b/include/pci.h
index fcc8087..e1d75a1 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -266,78 +266,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);