/*
* Driver for IBM Power 842 compression accelerator
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (C) IBM Corporation, 2012
*
* Authors: Robert Jennings <rcj@linux.vnet.ibm.com>
* Seth Jennings <sjenning@linux.vnet.ibm.com>
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/nx842.h>
#include <linux/of.h>
#include <linux/slab.h>
#include <asm/page.h>
#include <asm/vio.h>
#include "nx_csbcpb.h" /* struct nx_csbcpb */
#define MODULE_NAME "nx-compress"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Robert Jennings <rcj@linux.vnet.ibm.com>");
MODULE_DESCRIPTION("842 H/W Compression driver for IBM Power processors");
#define SHIFT_4K 12
#define SHIFT_64K 16
#define SIZE_4K (1UL << SHIFT_4K)
#define SIZE_64K (1UL << SHIFT_64K)
/* IO buffer must be 128 byte aligned */
#define IO_BUFFER_ALIGN 128
struct nx842_header {
int blocks_nr; /* number of compressed blocks */
int offset; /* offset of the first block (from beginning of header) */
int sizes[0]; /* size of compressed blocks */
};
static inline int nx842_header_size(const struct nx842_header *hdr)
{
return sizeof(struct nx842_header) +
hdr->blocks_nr * sizeof(hdr->sizes[0]);
}
/* Macros for fields within nx_csbcpb */
/* Check the valid bit within the csbcpb valid field */
#define NX842_CSBCBP_VALID_CHK(x) (x & BIT_MASK(7))
/* CE macros operate on the completion_extension field bits in the csbcpb.
* CE0 0=full completion, 1=partial completion
* CE1 0=CE0 indicates completion, 1=termination (output may be modified)
* CE2 0=processed_bytes is source bytes, 1=processed_bytes is target bytes */
#define NX842_CSBCPB_CE0(x) (x & BIT_MASK(7))
#define NX842_CSBCPB_CE1(x) (x & BIT_MASK(6))
#define NX842_CSBCPB_CE2(x) (x & BIT_MASK(5))
/* The NX unit accepts data only on 4K page boundaries */
#define NX842_HW_PAGE_SHIFT SHIFT_4K
#define NX842_HW_PAGE_SIZE (ASM_CONST(1) << NX842_HW_PAGE_SHIFT)
#define NX842_HW_PAGE_MASK (~(NX842_HW_PAGE_SIZE-1))
enum nx842_status {
UNAVAILABLE,
AVAILABLE
};
struct ibm_nx842_counters {
atomic64_t comp_complete;
atomic64_t comp_failed;
atomic64_t decomp_complete;
atomic64_t decomp_failed;
atomic64_t swdecomp;
atomic64_t comp_times[32];
atomic64_t decomp_times[32];
};
static struct nx842_devdata {
struct vio_dev *vdev;
struct device *dev;
struct ibm_nx842_counters *counters;
unsigned int max_sg_len;
unsigned int max_sync_size;
unsigned int max_sync_sg;
enum nx842_status status;
} __rcu *devdata;
static DEFINE_SPINLOCK(devdata_mutex);
#define NX842_COUNTER_INC(_x) \
static inline void nx842_inc_##_x( \
const struct nx842_devdata *dev) { \
if (dev) \
atomic64_inc(&dev->counters->_x); \
}
NX842_COUNTER_INC(comp_complete);
NX842_COUNTER_INC(comp_failed);
NX842_COUNTER_INC(decomp_complete);
NX842_COUNTER_INC(decomp_failed);
NX842_COUNTER_INC(swdecomp);
#define NX842_HIST_SLOTS 16
static void ibm_nx842_incr_hist(atomic64_t *times, unsigned int time)
{
int bucket = fls(time);
if (bucket)
bucket = min((NX842_HIST_SLOTS - 1), bucket - 1);
atomic64_inc(×[bucket]);
}
/* NX unit operation flags */
#define NX842_OP_COMPRESS 0x0
#define NX842_OP_CRC 0x1
#define NX842_OP_DECOMPRESS 0x2
#define NX842_OP_COMPRESS_CRC (NX842_OP_COMPRESS | NX842_OP_CRC)
#define NX842_OP_DECOMPRESS_CRC (NX842_OP_DECOMPRESS | NX842_OP_CRC)
#define NX842_OP_ASYNC (1<<23)
#define NX842_OP_NOTIFY (1<<22)
#define NX842_OP_NOTIFY_INT(x) ((x & 0xff)<<8)
static unsigned long nx842_get_desired_dma(struct vio_dev *viodev)
{
/* No use of DMA mappings within the driver. */
return 0;
}
struct nx842_slentry {
unsigned long ptr; /*
|