-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
powerpc/powernv: Add platform-specific services for opencapi
Implement a few platform-specific calls which can be used by drivers: - provide the Transaction Layer capabilities of the host, so that the driver can find some common ground and configure the device and host appropriately. - provide the hw interrupt to be used for translation faults raised by the NPU - map/unmap some NPU mmio registers to get the fault context when the NPU raises an address translation fault The rest are wrappers around the previously-introduced opal calls. Signed-off-by: Frederic Barrat <fbarrat@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
- Loading branch information
Frederic Barrat
authored and
Michael Ellerman
committed
Jan 24, 2018
1 parent
74d656d
commit 6914c75
Showing
3 changed files
with
210 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// SPDX-License-Identifier: GPL-2.0+ | ||
// Copyright 2017 IBM Corp. | ||
#ifndef _ASM_PNV_OCXL_H | ||
#define _ASM_PNV_OCXL_H | ||
|
||
#include <linux/pci.h> | ||
|
||
#define PNV_OCXL_TL_MAX_TEMPLATE 63 | ||
#define PNV_OCXL_TL_BITS_PER_RATE 4 | ||
#define PNV_OCXL_TL_RATE_BUF_SIZE ((PNV_OCXL_TL_MAX_TEMPLATE+1) * PNV_OCXL_TL_BITS_PER_RATE / 8) | ||
|
||
extern int pnv_ocxl_get_tl_cap(struct pci_dev *dev, long *cap, | ||
char *rate_buf, int rate_buf_size); | ||
extern int pnv_ocxl_set_tl_conf(struct pci_dev *dev, long cap, | ||
uint64_t rate_buf_phys, int rate_buf_size); | ||
|
||
extern int pnv_ocxl_get_xsl_irq(struct pci_dev *dev, int *hwirq); | ||
extern void pnv_ocxl_unmap_xsl_regs(void __iomem *dsisr, void __iomem *dar, | ||
void __iomem *tfc, void __iomem *pe_handle); | ||
extern int pnv_ocxl_map_xsl_regs(struct pci_dev *dev, void __iomem **dsisr, | ||
void __iomem **dar, void __iomem **tfc, | ||
void __iomem **pe_handle); | ||
|
||
extern int pnv_ocxl_spa_setup(struct pci_dev *dev, void *spa_mem, int PE_mask, | ||
void **platform_data); | ||
extern void pnv_ocxl_spa_release(void *platform_data); | ||
extern int pnv_ocxl_spa_remove_pe(void *platform_data, int pe_handle); | ||
|
||
#endif /* _ASM_PNV_OCXL_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
// SPDX-License-Identifier: GPL-2.0+ | ||
// Copyright 2017 IBM Corp. | ||
#include <asm/pnv-ocxl.h> | ||
#include <asm/opal.h> | ||
#include "pci.h" | ||
|
||
#define PNV_OCXL_TL_P9_RECV_CAP 0x000000000000000Full | ||
/* PASIDs are 20-bit, but on P9, NPU can only handle 15 bits */ | ||
#define PNV_OCXL_PASID_BITS 15 | ||
#define PNV_OCXL_PASID_MAX ((1 << PNV_OCXL_PASID_BITS) - 1) | ||
|
||
|
||
static void set_templ_rate(unsigned int templ, unsigned int rate, char *buf) | ||
{ | ||
int shift, idx; | ||
|
||
WARN_ON(templ > PNV_OCXL_TL_MAX_TEMPLATE); | ||
idx = (PNV_OCXL_TL_MAX_TEMPLATE - templ) / 2; | ||
shift = 4 * (1 - ((PNV_OCXL_TL_MAX_TEMPLATE - templ) % 2)); | ||
buf[idx] |= rate << shift; | ||
} | ||
|
||
int pnv_ocxl_get_tl_cap(struct pci_dev *dev, long *cap, | ||
char *rate_buf, int rate_buf_size) | ||
{ | ||
if (rate_buf_size != PNV_OCXL_TL_RATE_BUF_SIZE) | ||
return -EINVAL; | ||
/* | ||
* The TL capabilities are a characteristic of the NPU, so | ||
* we go with hard-coded values. | ||
* | ||
* The receiving rate of each template is encoded on 4 bits. | ||
* | ||
* On P9: | ||
* - templates 0 -> 3 are supported | ||
* - templates 0, 1 and 3 have a 0 receiving rate | ||
* - template 2 has receiving rate of 1 (extra cycle) | ||
*/ | ||
memset(rate_buf, 0, rate_buf_size); | ||
set_templ_rate(2, 1, rate_buf); | ||
*cap = PNV_OCXL_TL_P9_RECV_CAP; | ||
return 0; | ||
} | ||
EXPORT_SYMBOL_GPL(pnv_ocxl_get_tl_cap); | ||
|
||
int pnv_ocxl_set_tl_conf(struct pci_dev *dev, long cap, | ||
uint64_t rate_buf_phys, int rate_buf_size) | ||
{ | ||
struct pci_controller *hose = pci_bus_to_host(dev->bus); | ||
struct pnv_phb *phb = hose->private_data; | ||
int rc; | ||
|
||
if (rate_buf_size != PNV_OCXL_TL_RATE_BUF_SIZE) | ||
return -EINVAL; | ||
|
||
rc = opal_npu_tl_set(phb->opal_id, dev->devfn, cap, | ||
rate_buf_phys, rate_buf_size); | ||
if (rc) { | ||
dev_err(&dev->dev, "Can't configure host TL: %d\n", rc); | ||
return -EINVAL; | ||
} | ||
return 0; | ||
} | ||
EXPORT_SYMBOL_GPL(pnv_ocxl_set_tl_conf); | ||
|
||
int pnv_ocxl_get_xsl_irq(struct pci_dev *dev, int *hwirq) | ||
{ | ||
int rc; | ||
|
||
rc = of_property_read_u32(dev->dev.of_node, "ibm,opal-xsl-irq", hwirq); | ||
if (rc) { | ||
dev_err(&dev->dev, | ||
"Can't get translation interrupt for device\n"); | ||
return rc; | ||
} | ||
return 0; | ||
} | ||
EXPORT_SYMBOL_GPL(pnv_ocxl_get_xsl_irq); | ||
|
||
void pnv_ocxl_unmap_xsl_regs(void __iomem *dsisr, void __iomem *dar, | ||
void __iomem *tfc, void __iomem *pe_handle) | ||
{ | ||
iounmap(dsisr); | ||
iounmap(dar); | ||
iounmap(tfc); | ||
iounmap(pe_handle); | ||
} | ||
EXPORT_SYMBOL_GPL(pnv_ocxl_unmap_xsl_regs); | ||
|
||
int pnv_ocxl_map_xsl_regs(struct pci_dev *dev, void __iomem **dsisr, | ||
void __iomem **dar, void __iomem **tfc, | ||
void __iomem **pe_handle) | ||
{ | ||
u64 reg; | ||
int i, j, rc = 0; | ||
void __iomem *regs[4]; | ||
|
||
/* | ||
* opal stores the mmio addresses of the DSISR, DAR, TFC and | ||
* PE_HANDLE registers in a device tree property, in that | ||
* order | ||
*/ | ||
for (i = 0; i < 4; i++) { | ||
rc = of_property_read_u64_index(dev->dev.of_node, | ||
"ibm,opal-xsl-mmio", i, ®); | ||
if (rc) | ||
break; | ||
regs[i] = ioremap(reg, 8); | ||
if (!regs[i]) { | ||
rc = -EINVAL; | ||
break; | ||
} | ||
} | ||
if (rc) { | ||
dev_err(&dev->dev, "Can't map translation mmio registers\n"); | ||
for (j = i - 1; j >= 0; j--) | ||
iounmap(regs[j]); | ||
} else { | ||
*dsisr = regs[0]; | ||
*dar = regs[1]; | ||
*tfc = regs[2]; | ||
*pe_handle = regs[3]; | ||
} | ||
return rc; | ||
} | ||
EXPORT_SYMBOL_GPL(pnv_ocxl_map_xsl_regs); | ||
|
||
struct spa_data { | ||
u64 phb_opal_id; | ||
u32 bdfn; | ||
}; | ||
|
||
int pnv_ocxl_spa_setup(struct pci_dev *dev, void *spa_mem, int PE_mask, | ||
void **platform_data) | ||
{ | ||
struct pci_controller *hose = pci_bus_to_host(dev->bus); | ||
struct pnv_phb *phb = hose->private_data; | ||
struct spa_data *data; | ||
u32 bdfn; | ||
int rc; | ||
|
||
data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
if (!data) | ||
return -ENOMEM; | ||
|
||
bdfn = (dev->bus->number << 8) | dev->devfn; | ||
rc = opal_npu_spa_setup(phb->opal_id, bdfn, virt_to_phys(spa_mem), | ||
PE_mask); | ||
if (rc) { | ||
dev_err(&dev->dev, "Can't setup Shared Process Area: %d\n", rc); | ||
kfree(data); | ||
return rc; | ||
} | ||
data->phb_opal_id = phb->opal_id; | ||
data->bdfn = bdfn; | ||
*platform_data = (void *) data; | ||
return 0; | ||
} | ||
EXPORT_SYMBOL_GPL(pnv_ocxl_spa_setup); | ||
|
||
void pnv_ocxl_spa_release(void *platform_data) | ||
{ | ||
struct spa_data *data = (struct spa_data *) platform_data; | ||
int rc; | ||
|
||
rc = opal_npu_spa_setup(data->phb_opal_id, data->bdfn, 0, 0); | ||
WARN_ON(rc); | ||
kfree(data); | ||
} | ||
EXPORT_SYMBOL_GPL(pnv_ocxl_spa_release); | ||
|
||
int pnv_ocxl_spa_remove_pe(void *platform_data, int pe_handle) | ||
{ | ||
struct spa_data *data = (struct spa_data *) platform_data; | ||
int rc; | ||
|
||
rc = opal_npu_spa_clear_cache(data->phb_opal_id, data->bdfn, pe_handle); | ||
return rc; | ||
} | ||
EXPORT_SYMBOL_GPL(pnv_ocxl_spa_remove_pe); |