// SPDX-License-Identifier: GPL-2.0-only
/*
* IBM Accelerator Family 'GenWQE'
*
* (C) Copyright IBM Corp. 2013
*
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
* Author: Michael Jung <mijung@gmx.net>
* Author: Michael Ruettger <michael@ibmra.de>
*/
/*
* Miscelanous functionality used in the other GenWQE driver parts.
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/vmalloc.h>
#include <linux/page-flags.h>
#include <linux/scatterlist.h>
#include <linux/hugetlb.h>
#include <linux/iommu.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/ctype.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/pgtable.h>
#include "genwqe_driver.h"
#include "card_base.h"
#include "card_ddcb.h"
/**
* __genwqe_writeq() - Write 64-bit register
* @cd: genwqe device descriptor
* @byte_offs: byte offset within BAR
* @val: 64-bit value
*
* Return: 0 if success; < 0 if error
*/
int __genwqe_writeq(struct genwqe_dev *cd, u64 byte_offs, u64 val)
{
struct pci_dev *pci_dev = cd->pci_dev;
if (cd->err_inject & GENWQE_INJECT_HARDWARE_FAILURE)
return -EIO;
if (cd->mmio == NULL)
return -EIO;
if (pci_channel_offline(pci_dev))
return -EIO;
__raw_writeq((__force u64)cpu_to_be64(val), cd->mmio + byte_offs);
return 0;
}
/**
* __genwqe_readq() - Read 64-bit register
* @cd: genwqe device descriptor
* @byte_offs: offset within BAR
*
* Return: value from register
*/
u64 __genwqe_readq(struct genwqe_dev *cd, u64 byte_offs)
{
if (cd->err_inject & GENWQE_INJECT_HARDWARE_FAILURE)
return 0xffffffffffffffffull;
if ((cd->err_inject & GENWQE_INJECT_GFIR_FATAL) &&
(byte_offs == IO_SLC_CFGREG_GFIR))
return 0x000000000000ffffull;
if ((cd->err_inject & GENWQE_INJECT_GFIR_INFO) &&
(byte_offs == IO_SLC_CFGREG_GFIR))
return 0x00000000ffff0000ull;
if (cd->mmio == NULL)
return 0xffffffffffffffffull;
return be64_to_cpu((__force __be64)__raw_readq(cd->mmio + byte_offs));
}
/**
* __genwqe_writel() - Write 32-bit register
* @cd: genwqe device descriptor
* @byte_offs: byte offset within BAR
* @val: 32-bit value
*
* Return: 0 if success; < 0 if error
*/
int __genwqe_writel(struct genwqe_dev *cd, u64 byte_offs, u32 val)
{
struct pci_dev *pci_dev = cd->pci_dev;
if (cd->err_inject & GENWQE_INJECT_HARDWARE_FAILURE)
return -EIO;
if (cd->mmio == NULL)
return -EIO;
if (pci_channel_offline(pci_dev))
return -EIO;
__raw_writel((__force u32)cpu_to_be32(val), cd->mmio + byte_offs);
return 0;
}
/**
* __genwqe_readl() - Read 32-bit register
* @cd: genwqe device descriptor
* @byte_offs: offset within BAR
*
* Return: Value from register
*/
u32 __genwqe_readl(struct genwqe_dev *cd, u64 byte_offs)
{
if (cd->err_inject & GENWQE_INJECT_HARDWARE_FAILURE)
return 0xffffffff;
if (cd->mmio == NULL)
return 0xffffffff;
return be32_to_cpu((__force __be32)__raw_readl(cd->mmio + byte_offs));
}
/**
* genwqe_read_app_id() - Extract app_id
* @cd: genwqe device descriptor
* @app_name: carrier used to pass-back name
* @len: length of data for name
*
* app_unitcfg need to be filled with valid data first
*/
int genwqe_read_app_id(struct genwqe_dev *cd, char *app_name, int len)
{
int i, j;
u32 app_id = (u32)cd->app_unitcfg;
memset(app_name, 0, len);
for (i = 0, j = 0; j < min(len, 4); j++) {
char ch = (char)((app_id >> (24 - j*8)) & 0xff);
if (ch == ' ')
continue;
app_name[i++] = isprint(ch) ? ch : 'X';
}
return i;
}
/**
* genwqe_init_crc32() - Prepare a lookup table for fast crc32 calculations
*
* Existing kernel functions seem to use a different polynom,
* therefore we could not use them here.
*
* Genwqe's Polynomial = 0x20044009
*/
#define CRC32_POLYNOMIAL 0x20044009
static u32 crc32_tab[256]; /* crc32 lookup table */
void genwqe_init_crc32(void)
{
int i, j;
u32 crc;
for (i = 0; i < 256; i++) {
crc = i << 24;
for (j = 0; j < 8; j++) {
if (crc & 0x80000000)
crc = (crc << 1) ^ CRC32_POLYNOMIAL;
else
crc = (crc << 1);
}
crc32_tab[i] = crc;
}
}
/**
* genwqe_crc32() - Generate 32-bit crc as required for DDCBs
* @buff: pointer to data buffer
* @len: length of data for calculation
* @init: initial crc (0xffffffff at start)
*
* polynomial = x^32 * + x^29 + x^18 + x^14 + x^3 + 1 (0x20044009)
*
* Example: 4 bytes 0x01 0x02 0x03 0x04 with init=0xffffffff should
* result in a crc32 of 0xf33cb7d3.
*
* The existing kernel crc functions did not cover this polynom yet.
*
* Return: crc32 checksum.
*/
u32 genwqe_crc32(u8 *buff, size_t len, u32 init)
{
int i;
u32 crc;
crc = init;
while (len--) {
i = ((crc >> 24) ^ *buff++) & 0xFF;
crc = (crc << 8) ^ crc32_tab[i];
}
return crc;
}