diff options
author | Ian Munsie <imunsie@au1.ibm.com> | 2016-05-24 21:22:53 +1000 |
---|---|---|
committer | Stewart Smith <stewart@linux.vnet.ibm.com> | 2016-06-09 14:09:21 +1000 |
commit | 5477148a439fda9fb55ea4a828c958fcdcc10f2e (patch) | |
tree | 1e883fe8d162db42ef6e7b00981162e41c629132 /hw | |
parent | 487b85f9fd423c45da26a7c6b426ccfc7d23a2c2 (diff) | |
download | skiboot-5477148a439fda9fb55ea4a828c958fcdcc10f2e.zip skiboot-5477148a439fda9fb55ea4a828c958fcdcc10f2e.tar.gz skiboot-5477148a439fda9fb55ea4a828c958fcdcc10f2e.tar.bz2 |
phb3: Add support for CAPP DMA mode
The XSL used in the Mellanox CX4 card uses a DMA mode of CAPI, which
requires a few registers configured specially. In addition to enabling
the mode,
- The CAPP only owns some of the PHB read buffers, and must be
configured to use the correct ones, and the self-snoop configured for
the same ones.
- The tve needs to be configured to allow the card to access all kernel
memory as it uses DMA accesses to read the scheduled process area from
the kernel, among other things.
These cannot be configured unconditionally, as doing so will break
existing CAPI devices that do not use DMA mode. This adds a new mode to
the OPAL_PCI_SET_PHB_CAPI_MODE API to enable CAPI in DMA mode.
Since the snoop on/off modes write to the capi snoop configuration
register, which is configured differently in DMA mode, it uses the
redundant bits from the apc master powerbus control register to
determine if it should configure the register for DMA mode rather than
requiring any more permutations of the mode parameter.
Signed-off-by: Ian Munsie <imunsie@au1.ibm.com>
Reviewed-by: Frederic Barrat <fbarrat@linux.vnet.ibm.com>
Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/phb3.c | 56 |
1 files changed, 46 insertions, 10 deletions
@@ -3324,14 +3324,22 @@ static int64_t phb3_get_diag_data(struct phb *phb, return OPAL_SUCCESS; } -static void phb3_init_capp_regs(struct phb3 *p) +static void phb3_init_capp_regs(struct phb3 *p, bool dma_mode) { uint64_t reg; uint32_t offset; + uint64_t read_buffers = 0; + + if (dma_mode) { + /* In DMA mode, the CAPP only owns some of the PHB read buffers */ + read_buffers = 0x1; + } offset = PHB3_CAPP_REG_OFFSET(p); xscom_read(p->chip_id, APC_MASTER_PB_CTRL + offset, ®); + reg &= ~PPC_BITMASK(10, 11); reg |= PPC_BIT(3); + reg |= read_buffers << PPC_BITLSHIFT(11); xscom_write(p->chip_id, APC_MASTER_PB_CTRL + offset, reg); /* Dynamically workout which PHB to connect to port 0 of the CAPP. @@ -3378,7 +3386,10 @@ static void phb3_init_capp_regs(struct phb3 *p) xscom_write(p->chip_id, FLUSH_UOP_CONFIG1 + offset, 0xB188280728000000); xscom_write(p->chip_id, FLUSH_UOP_CONFIG2 + offset, 0xB188400F00000000); - xscom_write(p->chip_id, SNOOP_CAPI_CONFIG + offset, 0xA1F0000000000000); + + reg = 0xA1F0000000000000; + reg |= read_buffers << PPC_BITLSHIFT(39); + xscom_write(p->chip_id, SNOOP_CAPI_CONFIG + offset, reg); } /* override some inits with CAPI defaults */ @@ -3395,7 +3406,7 @@ static void phb3_init_capp_errors(struct phb3 *p) #define PE_REG_OFFSET(p) \ ((PHB3_IS_NAPLES(p) && (p)->index) ? 0x40 : 0x0) -static int64_t enable_capi_mode(struct phb3 *p, uint64_t pe_number) +static int64_t enable_capi_mode(struct phb3 *p, uint64_t pe_number, bool dma_mode) { uint64_t reg; int i; @@ -3417,7 +3428,12 @@ static int64_t enable_capi_mode(struct phb3 *p, uint64_t pe_number) return OPAL_HARDWARE; } - xscom_write(p->chip_id, p->spci_xscom + 0x3, 0x8000000000000000ull); + /* pb aib capp enable */ + reg = PPC_BIT(0); /* capp enable */ + if (dma_mode) + reg |= PPC_BIT(1); /* capp dma mode */ + xscom_write(p->chip_id, p->spci_xscom + 0x3, reg); + /* FIXME security timer bar xscom_write(p->chip_id, p->spci_xscom + 0x4, 0x8000000000000000ull); */ @@ -3456,8 +3472,16 @@ static int64_t enable_capi_mode(struct phb3 *p, uint64_t pe_number) /* set tve no translate mode allow mmio window */ memset(p->tve_cache, 0x0, sizeof(p->tve_cache)); - /* Allow address range 0x0002000000000000: 0x0002FFFFFFFFFFF */ - p->tve_cache[pe_number * 2] = 0x000000FFFFFF0a00ULL; + if (dma_mode) { + /* + * CAPP DMA mode needs access to all of memory, set address + * range to 0x0000000000000000: 0x0002FFFFFFFFFFF + */ + p->tve_cache[pe_number * 2] = 0x000000FFFFFF0200ULL; + } else { + /* Allow address range 0x0002000000000000: 0x0002FFFFFFFFFFF */ + p->tve_cache[pe_number * 2] = 0x000000FFFFFF0a00ULL; + } phb3_ioda_sel(p, IODA2_TBL_TVT, 0, true); for (i = 0; i < ARRAY_SIZE(p->tve_cache); i++) @@ -3484,7 +3508,7 @@ static int64_t enable_capi_mode(struct phb3 *p, uint64_t pe_number) phb3_init_capp_errors(p); - phb3_init_capp_regs(p); + phb3_init_capp_regs(p, dma_mode); if (!chiptod_capp_timebase_sync(p)) { PHBERR(p, "CAPP: Failed to sync timebase\n"); @@ -3500,6 +3524,7 @@ static int64_t phb3_set_capi_mode(struct phb *phb, uint64_t mode, struct phb3 *p = phb_to_phb3(phb); struct proc_chip *chip = get_chip(p->chip_id); uint64_t reg; + uint64_t read_buffers; uint32_t offset; u8 mask; @@ -3545,7 +3570,10 @@ static int64_t phb3_set_capi_mode(struct phb *phb, uint64_t mode, return OPAL_UNSUPPORTED; case OPAL_PHB_CAPI_MODE_CAPI: - return enable_capi_mode(p, pe_number); + return enable_capi_mode(p, pe_number, false); + + case OPAL_PHB_CAPI_MODE_DMA: + return enable_capi_mode(p, pe_number, true); case OPAL_PHB_CAPI_MODE_SNOOP_OFF: xscom_write(p->chip_id, SNOOP_CAPI_CONFIG + offset, @@ -3555,8 +3583,16 @@ static int64_t phb3_set_capi_mode(struct phb *phb, uint64_t mode, case OPAL_PHB_CAPI_MODE_SNOOP_ON: xscom_write(p->chip_id, CAPP_ERR_STATUS_CTRL + offset, 0x0000000000000000); - xscom_write(p->chip_id, SNOOP_CAPI_CONFIG + offset, - 0xA1F0000000000000); + /* + * Make sure the PHB read buffers being snooped match those + * being used so we don't need another mode to set SNOOP+DMA + */ + xscom_read(p->chip_id, APC_MASTER_PB_CTRL + offset, ®); + read_buffers = (reg >> PPC_BITLSHIFT(11)) & 0x3; + reg = 0xA1F0000000000000; + reg |= read_buffers << PPC_BITLSHIFT(39); + xscom_write(p->chip_id, SNOOP_CAPI_CONFIG + offset, reg); + return OPAL_SUCCESS; } |