From patchwork Thu Jun 4 06:19:03 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gavin Shan X-Patchwork-Id: 480441 X-Patchwork-Delegate: benh@kernel.crashing.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 2A92E140187 for ; Thu, 4 Jun 2015 16:21:55 +1000 (AEST) Received: from ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 050DE1A027E for ; Thu, 4 Jun 2015 16:21:55 +1000 (AEST) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Received: from e23smtp05.au.ibm.com (e23smtp05.au.ibm.com [202.81.31.147]) (using TLSv1 with cipher CAMELLIA256-SHA (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id D25851A0D43 for ; Thu, 4 Jun 2015 16:21:49 +1000 (AEST) Received: from /spool/local by e23smtp05.au.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Thu, 4 Jun 2015 16:21:49 +1000 Received: from d23dlp02.au.ibm.com (202.81.31.213) by e23smtp05.au.ibm.com (202.81.31.211) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Thu, 4 Jun 2015 16:21:47 +1000 Received: from d23relay07.au.ibm.com (d23relay07.au.ibm.com [9.190.26.37]) by d23dlp02.au.ibm.com (Postfix) with ESMTP id 8A3B02BB0055 for ; Thu, 4 Jun 2015 16:21:47 +1000 (EST) Received: from d23av03.au.ibm.com (d23av03.au.ibm.com [9.190.234.97]) by d23relay07.au.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id t546KObg54591606 for ; Thu, 4 Jun 2015 16:20:32 +1000 Received: from d23av03.au.ibm.com (localhost [127.0.0.1]) by d23av03.au.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id t546K0Na011843 for ; Thu, 4 Jun 2015 16:20:00 +1000 Received: from ozlabs.au.ibm.com (ozlabs.au.ibm.com [9.192.253.14]) by d23av03.au.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id t546Jx6R010920; Thu, 4 Jun 2015 16:19:59 +1000 Received: from bran.ozlabs.ibm.com (unknown [9.192.254.114]) by ozlabs.au.ibm.com (Postfix) with ESMTP id E2CE8A03E1; Thu, 4 Jun 2015 16:19:13 +1000 (AEST) Received: from gwshan (shangw.ozlabs.ibm.com [10.61.2.199]) by bran.ozlabs.ibm.com (Postfix) with ESMTP id ECEE9E387C; Thu, 4 Jun 2015 16:19:13 +1000 (AEST) Received: by gwshan (Postfix, from userid 1000) id E0EE19422B2; Thu, 4 Jun 2015 16:19:13 +1000 (AEST) From: Gavin Shan To: skiboot@lists.ozlabs.org Date: Thu, 4 Jun 2015 16:19:03 +1000 Message-Id: <1433398749-15096-12-git-send-email-gwshan@linux.vnet.ibm.com> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1433398749-15096-1-git-send-email-gwshan@linux.vnet.ibm.com> References: <1433398749-15096-1-git-send-email-gwshan@linux.vnet.ibm.com> X-TM-AS-MML: disable X-Content-Scanned: Fidelis XPS MAILER x-cbid: 15060406-0017-0000-0000-000001599FCC Subject: [Skiboot] [PATCH v7 11/17] hw/p5ioc: Support PHB slot X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" The patch refactors functions used for PHB slot management for P5IOC2. Also, PHB slots are created before platform's PHB setup hook (platform.pci_setup_phb()). That means the platforms can override the properties or methods of the PHB slot if necessary. Signed-off-by: Gavin Shan --- hw/p5ioc2-phb.c | 372 +++++++++---------------------------------------------- include/p5ioc2.h | 9 +- 2 files changed, 60 insertions(+), 321 deletions(-) diff --git a/hw/p5ioc2-phb.c b/hw/p5ioc2-phb.c index 0848b99..85f3857 100644 --- a/hw/p5ioc2-phb.c +++ b/hw/p5ioc2-phb.c @@ -20,8 +20,9 @@ #include #include #include -#include #include +#include +#include #include #include @@ -30,19 +31,6 @@ #define PHBERR(p, fmt, a...) prlog(PR_ERR, "PHB%d: " fmt, \ (p)->phb.opal_id, ## a) -/* Helper to set the state machine timeout */ -static inline uint64_t p5ioc2_set_sm_timeout(struct p5ioc2_phb *p, uint64_t dur) -{ - uint64_t target, now = mftb(); - - target = now + dur; - if (target == 0) - target++; - p->delay_tgt_tb = target; - - return dur; -} - /* * Lock callbacks. Allows the OPAL API handlers to lock the * PHB around calls such as config space, EEH, etc... @@ -206,10 +194,11 @@ static int64_t p5ioc2_pcicfg_write32(struct phb *phb, uint32_t bdfn, return OPAL_SUCCESS; } -static int64_t p5ioc2_presence_detect(struct phb *phb) +static int64_t p5ioc2_get_presence_status(struct pci_slot *slot, + uint8_t *val) { - struct p5ioc2_phb *p = phb_to_p5ioc2_phb(phb); - uint16_t slotstat; + struct p5ioc2_phb *p = phb_to_p5ioc2_phb(slot->phb); + uint16_t sts; int64_t rc; if (!p->is_pcie) { @@ -218,315 +207,74 @@ static int64_t p5ioc2_presence_detect(struct phb *phb) lsr = in_be32(p->regs + SHPC_LOGICAL_SLOT); if (GETFIELD(SHPC_LOGICAL_SLOT_PRSNT, lsr) != SHPC_SLOT_STATE_EMPTY) - return OPAL_SHPC_DEV_PRESENT; + *val = 1; else - return OPAL_SHPC_DEV_NOT_PRESENT; + *val = 0; + return OPAL_SUCCESS; } - rc = p5ioc2_pcicfg_read16(&p->phb, 0, p->ecap + PCICAP_EXP_SLOTSTAT, - &slotstat); - if (rc || !(slotstat & PCICAP_EXP_SLOTSTAT_PDETECTST)) - return OPAL_SHPC_DEV_NOT_PRESENT; - return OPAL_SHPC_DEV_PRESENT; + rc = p5ioc2_pcicfg_read16(&p->phb, 0, + p->ecap + PCICAP_EXP_SLOTSTAT, &sts); + if (rc == OPAL_SUCCESS && + (sts & PCICAP_EXP_SLOTSTAT_PDETECTST)) + *val = 1; + else + *val = 0; + return OPAL_SUCCESS; } -static int64_t p5ioc2_link_state(struct phb *phb) +static int64_t p5ioc2_get_link_status(struct pci_slot *slot, + uint8_t *val) { - struct p5ioc2_phb *p = phb_to_p5ioc2_phb(phb); + struct p5ioc2_phb *p = phb_to_p5ioc2_phb(slot->phb); uint16_t lstat; int64_t rc; - /* XXX Test for PHB in error state ? */ - if (!p->is_pcie) - return OPAL_SHPC_LINK_UP_x1; - - rc = p5ioc2_pcicfg_read16(&p->phb, 0, p->ecap + PCICAP_EXP_LSTAT, - &lstat); - if (rc < 0) { - /* Shouldn't happen */ - PHBERR(p, "Failed to read link status\n"); - return OPAL_HARDWARE; - } - if (!(lstat & PCICAP_EXP_LSTAT_DLLL_ACT)) - return OPAL_SHPC_LINK_DOWN; - return GETFIELD(PCICAP_EXP_LSTAT_WIDTH, lstat); -} - -static int64_t p5ioc2_power_state(struct phb *phb __unused) -{ - /* XXX FIXME */ -#if 0 - struct p5ioc2_phb *p = phb_to_p5ioc2_phb(phb); - uint64_t reg = in_be64(p->regs + PHB_PCIE_SLOTCTL2); - - /* XXX Test for PHB in error state ? */ - - if (reg & PHB_PCIE_SLOTCTL2_PWR_EN_STAT) - return OPAL_SHPC_POWER_ON; - - return OPAL_SHPC_POWER_OFF; -#else - return OPAL_SHPC_POWER_ON; -#endif -} - -/* p5ioc2_sm_slot_power_off - Slot power off state machine - */ -static int64_t p5ioc2_sm_slot_power_off(struct p5ioc2_phb *p) -{ - switch(p->state) { - default: - break; + if (!p->is_pcie) { + *val = 1; + return OPAL_SUCCESS; } - /* Unknown state, hardware error ? */ - return OPAL_HARDWARE; -} - -static int64_t p5ioc2_slot_power_off(struct phb *phb) -{ - struct p5ioc2_phb *p = phb_to_p5ioc2_phb(phb); - - if (p->state != P5IOC2_PHB_STATE_FUNCTIONAL) - return OPAL_BUSY; - - /* run state machine */ - return p5ioc2_sm_slot_power_off(p); -} - -static int64_t p5ioc2_sm_slot_power_on(struct p5ioc2_phb *p __unused) -{ -#if 0 - uint64_t reg; - uint32_t reg32; - uint16_t brctl; - - switch(p->state) { - case P5IOC2_PHB_STATE_FUNCTIONAL: - /* Check presence */ - reg = in_be64(p->regs + PHB_PCIE_SLOTCTL2); - if (!(reg & PHB_PCIE_SLOTCTL2_PRSTN_STAT)) { - PHBDBG(p, "Slot power on: no device\n"); - return OPAL_CLOSED; - } - - /* Adjust UTL interrupt settings to disable various - * errors that would interfere with the process - */ - out_be64(p->regs + UTL_PCIE_PORT_IRQ_EN, 0x7e00000000000000); - - /* If the power is not on, turn it on now */ - if (!(reg & PHB_PCIE_SLOTCTL2_PWR_EN_STAT)) { - reg = in_be64(p->regs + PHB_HOTPLUG_OVERRIDE); - reg &= ~(0x8c00000000000000ul); - reg |= 0x8400000000000000ul; - out_be64(p->regs + PHB_HOTPLUG_OVERRIDE, reg); - p->state = PHB_STATE_SPUP_STABILIZE_DELAY; - PHBDBG(p, "Slot power on: powering on...\n"); - return p5ioc2_set_sm_timeout(p, secs_to_tb(2)); - } - /* Power is already on */ - power_ok: - /* Ensure hot reset is deasserted */ - p5ioc2_pcicfg_read16(&p->phb, 0, PCI_CFG_BRCTL, &brctl); - brctl &= ~PCI_CFG_BRCTL_SECONDARY_RESET; - p5ioc2_pcicfg_write16(&p->phb, 0, PCI_CFG_BRCTL, brctl); - p->retries = 40; - p->state = PHB_STATE_SPUP_WAIT_LINK; - PHBDBG(p, "Slot power on: waiting for link\n"); - /* Fall through */ - case PHB_STATE_SPUP_WAIT_LINK: - reg = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL); - /* Link is up ? Complete */ - - /* XXX TODO: Check link width problem and if present - * go straight to the host reset code path. - */ - if (reg & PHB_PCIE_DLP_TC_DL_LINKACT) { - /* Restore UTL interrupts */ - out_be64(p->regs + UTL_PCIE_PORT_IRQ_EN, - 0xfe65000000000000); - p->state = PHB_STATE_FUNCTIONAL; - PHBDBG(p, "Slot power on: up !\n"); - return OPAL_SUCCESS; - } - /* Retries */ - p->retries--; - if (p->retries == 0) { - /* XXX Improve logging */ - PHBERR(p,"Slot power on: Timeout waiting for link\n"); - goto error; - } - /* Check time elapsed */ - if ((p->retries % 20) != 0) - return p5ioc2_set_sm_timeout(p, msecs_to_tb(10)); - - /* >200ms, time to try a hot reset after clearing the - * link status bit (doco says to do so) - */ - out_be64(p->regs + UTL_PCIE_PORT_STATUS, 0x0080000000000000); - - /* Mask receiver error status in AER */ - p5ioc2_pcicfg_read32(&p->phb, 0, - p->aercap + PCIECAP_AER_CE_MASK, ®32); - reg32 |= PCIECAP_AER_CE_RECVR_ERR; - p5ioc2_pcicfg_write32(&p->phb, 0, - p->aercap + PCIECAP_AER_CE_MASK, reg32); - - /* Turn on host reset */ - p5ioc2_pcicfg_read16(&p->phb, 0, PCI_CFG_BRCTL, &brctl); - brctl |= PCI_CFG_BRCTL_SECONDARY_RESET; - p5ioc2_pcicfg_write16(&p->phb, 0, PCI_CFG_BRCTL, brctl); - p->state = PHB_STATE_SPUP_HOT_RESET_DELAY; - PHBDBG(p, "Slot power on: soft reset...\n"); - return p5ioc2_set_sm_timeout(p, secs_to_tb(1)); - case PHB_STATE_SPUP_HOT_RESET_DELAY: - /* Turn off host reset */ - p5ioc2_pcicfg_read16(&p->phb, 0, PCI_CFG_BRCTL, &brctl); - brctl &= ~PCI_CFG_BRCTL_SECONDARY_RESET; - p5ioc2_pcicfg_write16(&p->phb, 0, PCI_CFG_BRCTL, brctl); - /* Clear spurious errors */ - out_be64(p->regs + UTL_PCIE_PORT_STATUS, 0x00e0000000000000); - p5ioc2_pcicfg_write32(&p->phb, 0, - p->aercap + PCIECAP_AER_CE_STATUS, - PCIECAP_AER_CE_RECVR_ERR); - /* Unmask receiver error status in AER */ - p5ioc2_pcicfg_read32(&p->phb, 0, - p->aercap + PCIECAP_AER_CE_MASK, ®32); - reg32 &= ~PCIECAP_AER_CE_RECVR_ERR; - p5ioc2_pcicfg_write32(&p->phb, 0, - p->aercap + PCIECAP_AER_CE_MASK, reg32); - /* Go back to waiting for link */ - p->state = PHB_STATE_SPUP_WAIT_LINK; - PHBDBG(p, "Slot power on: waiting for link (2)\n"); - return p5ioc2_set_sm_timeout(p, msecs_to_tb(10)); - - case PHB_STATE_SPUP_STABILIZE_DELAY: - /* Come here after the 2s delay after power up */ - p->retries = 1000; - p->state = PHB_STATE_SPUP_SLOT_STATUS; - PHBDBG(p, "Slot power on: waiting for power\n"); - /* Fall through */ - case PHB_STATE_SPUP_SLOT_STATUS: - reg = in_be64(p->regs + PHB_PCIE_SLOTCTL2); - - /* Doc says to check LED status, but we ignore that, there - * no point really and it's easier that way - */ - if (reg & PHB_PCIE_SLOTCTL2_PWR_EN_STAT) - goto power_ok; - if (p->retries-- == 0) { - /* XXX Improve error logging */ - PHBERR(p, "Timeout powering up slot\n"); - goto error; - } - return p5ioc2_set_sm_timeout(p, msecs_to_tb(10)); - default: - break; - } + rc = p5ioc2_pcicfg_read16(&p->phb, 0, + p->ecap + PCICAP_EXP_LSTAT, &lstat); + if (rc == OPAL_SUCCESS && + (lstat & PCICAP_EXP_LSTAT_DLLL_ACT)) + *val = GETFIELD(PCICAP_EXP_LSTAT_WIDTH, lstat); + else + *val = 0; - /* Unknown state, hardware error ? */ - error: - p->state = PHB_STATE_FUNCTIONAL; - return OPAL_HARDWARE; -#else return OPAL_SUCCESS; -#endif -} - -static int64_t p5ioc2_slot_power_on(struct phb *phb) -{ - struct p5ioc2_phb *p = phb_to_p5ioc2_phb(phb); - - if (p->state != P5IOC2_PHB_STATE_FUNCTIONAL) - return OPAL_BUSY; - - /* run state machine */ - return p5ioc2_sm_slot_power_on(p); } -static int64_t p5ioc2_sm_hot_reset(struct p5ioc2_phb *p) +static struct pci_slot *p5ioc2_phb_slot_create(struct phb *phb) { - switch(p->state) { - default: - break; - } + struct pci_slot *slot; - /* Unknown state, hardware error ? */ - return OPAL_HARDWARE; -} + slot = pci_slot_alloc(phb, NULL); + if (!slot) + return NULL; -static int64_t p5ioc2_hot_reset(struct phb *phb) -{ - struct p5ioc2_phb *p = phb_to_p5ioc2_phb(phb); + /* Elementary functions */ + slot->ops.get_presence_status = p5ioc2_get_presence_status; + slot->ops.get_link_status = p5ioc2_get_link_status; + slot->ops.get_power_status = NULL; + slot->ops.get_attention_status = NULL; + slot->ops.get_latch_status = NULL; + slot->ops.set_power_status = NULL; + slot->ops.set_attention_status = NULL; - if (p->state != P5IOC2_PHB_STATE_FUNCTIONAL) - return OPAL_BUSY; - - /* run state machine */ - return p5ioc2_sm_hot_reset(p); -} - -static int64_t p5ioc2_sm_freset(struct p5ioc2_phb *p) -{ - switch(p->state) { - default: - break; - } - - /* XXX Not implemented, return success to make - * pci.c happy, otherwise probing of slots will - * fail + /* + * SM-based functions. We don't support various reset + * requests on P5IOC yet. */ - return OPAL_SUCCESS; -} + slot->ops.prepare_link_change = NULL; + slot->ops.poll_link = NULL; + slot->ops.hreset = NULL; + slot->ops.freset = NULL; + slot->ops.pfreset = NULL; + slot->ops.creset = NULL; -static int64_t p5ioc2_freset(struct phb *phb) -{ - struct p5ioc2_phb *p = phb_to_p5ioc2_phb(phb); - - if (p->state != P5IOC2_PHB_STATE_FUNCTIONAL) - return OPAL_BUSY; - - /* run state machine */ - return p5ioc2_sm_freset(p); -} - -static int64_t p5ioc2_poll(struct phb *phb) -{ - struct p5ioc2_phb *p = phb_to_p5ioc2_phb(phb); - uint64_t now = mftb(); - - if (p->state == P5IOC2_PHB_STATE_FUNCTIONAL) - return OPAL_SUCCESS; - - /* Check timer */ - if (p->delay_tgt_tb && - tb_compare(now, p->delay_tgt_tb) == TB_ABEFOREB) - return p->delay_tgt_tb - now; - - /* Expired (or not armed), clear it */ - p->delay_tgt_tb = 0; - -#if 0 - /* Dispatch to the right state machine */ - switch(p->state) { - case PHB_STATE_SPUP_STABILIZE_DELAY: - case PHB_STATE_SPUP_SLOT_STATUS: - case PHB_STATE_SPUP_WAIT_LINK: - case PHB_STATE_SPUP_HOT_RESET_DELAY: - return p5ioc2_sm_slot_power_on(p); - case PHB_STATE_SPDOWN_STABILIZE_DELAY: - case PHB_STATE_SPDOWN_SLOT_STATUS: - return p5ioc2_sm_slot_power_off(p); - case PHB_STATE_HRESET_DELAY: - return p5ioc2_sm_hot_reset(p); - default: - break; - } -#endif - /* Unknown state, could be a HW error */ - return OPAL_HARDWARE; + return slot; } static int64_t p5ioc2_eeh_freeze_status(struct phb *phb, uint64_t pe_number, @@ -776,14 +524,6 @@ static const struct phb_ops p5ioc2_phb_ops = { .get_msi_64 = p5ioc2_get_msi_64, .ioda_reset = p5ioc2_ioda_reset, .set_phb_tce_memory = p5ioc2_set_phb_tce_memory, - .presence_detect = p5ioc2_presence_detect, - .link_state = p5ioc2_link_state, - .power_state = p5ioc2_power_state, - .slot_power_off = p5ioc2_slot_power_off, - .slot_power_on = p5ioc2_slot_power_on, - .hot_reset = p5ioc2_hot_reset, - .fundamental_reset = p5ioc2_freset, - .poll = p5ioc2_poll, }; /* p5ioc2_phb_get_xive - Interrupt control from OPAL */ @@ -1125,6 +865,7 @@ void p5ioc2_phb_setup(struct p5ioc2 *ioc, struct p5ioc2_phb *p, uint32_t buid) { uint32_t phbid; + struct pci_slot *slot; p->index = index; p->ca = ca; @@ -1211,9 +952,12 @@ void p5ioc2_phb_setup(struct p5ioc2 *ioc, struct p5ioc2_phb *p, * get a useful OPAL ID for it */ pci_register_phb(&p->phb); + slot = p5ioc2_phb_slot_create(&p->phb); + if (!slot) + prlog(PR_NOTICE, "P5IOC2: Cannot create PHB#%d slot\n", + p->phb.opal_id); /* Platform additional setup */ if (platform.pci_setup_phb) platform.pci_setup_phb(&p->phb, p->index); } - diff --git a/include/p5ioc2.h b/include/p5ioc2.h index fb9ed1b..fd7df4c 100644 --- a/include/p5ioc2.h +++ b/include/p5ioc2.h @@ -91,17 +91,15 @@ enum p5ioc2_phb_state { P5IOC2_PHB_STATE_FUNCTIONAL, }; -/* - * Structure for a PHB - */ +/* Structure for a PHB */ struct p5ioc2; - struct p5ioc2_phb { bool active; /* Is this PHB functional ? */ bool is_pcie; uint8_t ca; /* CA0 or CA1 */ uint8_t index; /* 0..3 index inside CA */ + enum p5ioc2_phb_state state; void *ca_regs; /* Calgary regs */ void *regs; /* PHB regs */ struct lock lock; @@ -110,9 +108,6 @@ struct p5ioc2_phb { uint64_t io_base; int64_t ecap; /* cached PCI-E cap offset */ int64_t aercap; /* cached AER ecap offset */ - enum p5ioc2_phb_state state; - uint64_t delay_tgt_tb; - uint64_t retries; uint64_t xive_cache[16]; struct p5ioc2 *ioc; struct phb phb;