forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ocxl: Provide global MMIO accessors for external drivers
External drivers that communicate via OpenCAPI will need to make MMIO calls to interact with the devices. Signed-off-by: Alastair D'Silva <alastair@d-silva.org> Reviewed-by: Greg Kurz <groug@kaod.org> Acked-by: Frederic Barrat <fbarrat@linux.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
- Loading branch information
Showing
3 changed files
with
345 additions
and
1 deletion.
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
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,234 @@ | ||
// SPDX-License-Identifier: GPL-2.0+ | ||
// Copyright 2019 IBM Corp. | ||
#include <linux/sched/mm.h> | ||
#include "trace.h" | ||
#include "ocxl_internal.h" | ||
|
||
int ocxl_global_mmio_read32(struct ocxl_afu *afu, size_t offset, | ||
enum ocxl_endian endian, u32 *val) | ||
{ | ||
if (offset > afu->config.global_mmio_size - 4) | ||
return -EINVAL; | ||
|
||
#ifdef __BIG_ENDIAN__ | ||
if (endian == OCXL_HOST_ENDIAN) | ||
endian = OCXL_BIG_ENDIAN; | ||
#endif | ||
|
||
switch (endian) { | ||
case OCXL_BIG_ENDIAN: | ||
*val = readl_be((char *)afu->global_mmio_ptr + offset); | ||
break; | ||
|
||
default: | ||
*val = readl((char *)afu->global_mmio_ptr + offset); | ||
break; | ||
} | ||
|
||
return 0; | ||
} | ||
EXPORT_SYMBOL_GPL(ocxl_global_mmio_read32); | ||
|
||
int ocxl_global_mmio_read64(struct ocxl_afu *afu, size_t offset, | ||
enum ocxl_endian endian, u64 *val) | ||
{ | ||
if (offset > afu->config.global_mmio_size - 8) | ||
return -EINVAL; | ||
|
||
#ifdef __BIG_ENDIAN__ | ||
if (endian == OCXL_HOST_ENDIAN) | ||
endian = OCXL_BIG_ENDIAN; | ||
#endif | ||
|
||
switch (endian) { | ||
case OCXL_BIG_ENDIAN: | ||
*val = readq_be((char *)afu->global_mmio_ptr + offset); | ||
break; | ||
|
||
default: | ||
*val = readq((char *)afu->global_mmio_ptr + offset); | ||
break; | ||
} | ||
|
||
return 0; | ||
} | ||
EXPORT_SYMBOL_GPL(ocxl_global_mmio_read64); | ||
|
||
int ocxl_global_mmio_write32(struct ocxl_afu *afu, size_t offset, | ||
enum ocxl_endian endian, u32 val) | ||
{ | ||
if (offset > afu->config.global_mmio_size - 4) | ||
return -EINVAL; | ||
|
||
#ifdef __BIG_ENDIAN__ | ||
if (endian == OCXL_HOST_ENDIAN) | ||
endian = OCXL_BIG_ENDIAN; | ||
#endif | ||
|
||
switch (endian) { | ||
case OCXL_BIG_ENDIAN: | ||
writel_be(val, (char *)afu->global_mmio_ptr + offset); | ||
break; | ||
|
||
default: | ||
writel(val, (char *)afu->global_mmio_ptr + offset); | ||
break; | ||
} | ||
|
||
|
||
return 0; | ||
} | ||
EXPORT_SYMBOL_GPL(ocxl_global_mmio_write32); | ||
|
||
int ocxl_global_mmio_write64(struct ocxl_afu *afu, size_t offset, | ||
enum ocxl_endian endian, u64 val) | ||
{ | ||
if (offset > afu->config.global_mmio_size - 8) | ||
return -EINVAL; | ||
|
||
#ifdef __BIG_ENDIAN__ | ||
if (endian == OCXL_HOST_ENDIAN) | ||
endian = OCXL_BIG_ENDIAN; | ||
#endif | ||
|
||
switch (endian) { | ||
case OCXL_BIG_ENDIAN: | ||
writeq_be(val, (char *)afu->global_mmio_ptr + offset); | ||
break; | ||
|
||
default: | ||
writeq(val, (char *)afu->global_mmio_ptr + offset); | ||
break; | ||
} | ||
|
||
|
||
return 0; | ||
} | ||
EXPORT_SYMBOL_GPL(ocxl_global_mmio_write64); | ||
|
||
int ocxl_global_mmio_set32(struct ocxl_afu *afu, size_t offset, | ||
enum ocxl_endian endian, u32 mask) | ||
{ | ||
u32 tmp; | ||
|
||
if (offset > afu->config.global_mmio_size - 4) | ||
return -EINVAL; | ||
|
||
#ifdef __BIG_ENDIAN__ | ||
if (endian == OCXL_HOST_ENDIAN) | ||
endian = OCXL_BIG_ENDIAN; | ||
#endif | ||
|
||
switch (endian) { | ||
case OCXL_BIG_ENDIAN: | ||
tmp = readl_be((char *)afu->global_mmio_ptr + offset); | ||
tmp |= mask; | ||
writel_be(tmp, (char *)afu->global_mmio_ptr + offset); | ||
break; | ||
|
||
default: | ||
tmp = readl((char *)afu->global_mmio_ptr + offset); | ||
tmp |= mask; | ||
writel(tmp, (char *)afu->global_mmio_ptr + offset); | ||
break; | ||
} | ||
|
||
return 0; | ||
} | ||
EXPORT_SYMBOL_GPL(ocxl_global_mmio_set32); | ||
|
||
int ocxl_global_mmio_set64(struct ocxl_afu *afu, size_t offset, | ||
enum ocxl_endian endian, u64 mask) | ||
{ | ||
u64 tmp; | ||
|
||
if (offset > afu->config.global_mmio_size - 8) | ||
return -EINVAL; | ||
|
||
#ifdef __BIG_ENDIAN__ | ||
if (endian == OCXL_HOST_ENDIAN) | ||
endian = OCXL_BIG_ENDIAN; | ||
#endif | ||
|
||
switch (endian) { | ||
case OCXL_BIG_ENDIAN: | ||
tmp = readq_be((char *)afu->global_mmio_ptr + offset); | ||
tmp |= mask; | ||
writeq_be(tmp, (char *)afu->global_mmio_ptr + offset); | ||
break; | ||
|
||
default: | ||
tmp = readq((char *)afu->global_mmio_ptr + offset); | ||
tmp |= mask; | ||
writeq(tmp, (char *)afu->global_mmio_ptr + offset); | ||
break; | ||
} | ||
|
||
return 0; | ||
} | ||
EXPORT_SYMBOL_GPL(ocxl_global_mmio_set64); | ||
|
||
int ocxl_global_mmio_clear32(struct ocxl_afu *afu, size_t offset, | ||
enum ocxl_endian endian, u32 mask) | ||
{ | ||
u32 tmp; | ||
|
||
if (offset > afu->config.global_mmio_size - 4) | ||
return -EINVAL; | ||
|
||
#ifdef __BIG_ENDIAN__ | ||
if (endian == OCXL_HOST_ENDIAN) | ||
endian = OCXL_BIG_ENDIAN; | ||
#endif | ||
|
||
switch (endian) { | ||
case OCXL_BIG_ENDIAN: | ||
tmp = readl_be((char *)afu->global_mmio_ptr + offset); | ||
tmp &= ~mask; | ||
writel_be(tmp, (char *)afu->global_mmio_ptr + offset); | ||
break; | ||
|
||
default: | ||
tmp = readl((char *)afu->global_mmio_ptr + offset); | ||
tmp &= ~mask; | ||
writel(tmp, (char *)afu->global_mmio_ptr + offset); | ||
break; | ||
} | ||
|
||
|
||
return 0; | ||
} | ||
EXPORT_SYMBOL_GPL(ocxl_global_mmio_clear32); | ||
|
||
int ocxl_global_mmio_clear64(struct ocxl_afu *afu, size_t offset, | ||
enum ocxl_endian endian, u64 mask) | ||
{ | ||
u64 tmp; | ||
|
||
if (offset > afu->config.global_mmio_size - 8) | ||
return -EINVAL; | ||
|
||
#ifdef __BIG_ENDIAN__ | ||
if (endian == OCXL_HOST_ENDIAN) | ||
endian = OCXL_BIG_ENDIAN; | ||
#endif | ||
|
||
switch (endian) { | ||
case OCXL_BIG_ENDIAN: | ||
tmp = readq_be((char *)afu->global_mmio_ptr + offset); | ||
tmp &= ~mask; | ||
writeq_be(tmp, (char *)afu->global_mmio_ptr + offset); | ||
break; | ||
|
||
default: | ||
tmp = readq((char *)afu->global_mmio_ptr + offset); | ||
tmp &= ~mask; | ||
writeq(tmp, (char *)afu->global_mmio_ptr + offset); | ||
break; | ||
} | ||
|
||
writeq(tmp, (char *)afu->global_mmio_ptr + offset); | ||
|
||
return 0; | ||
} | ||
EXPORT_SYMBOL_GPL(ocxl_global_mmio_clear64); |
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