Path: blob/master/drivers/crypto/nx/nx-common-pseries.c
26282 views
// SPDX-License-Identifier: GPL-2.0-or-later1/*2* Driver for IBM Power 842 compression accelerator3*4* Copyright (C) IBM Corporation, 20125*6* Authors: Robert Jennings <[email protected]>7* Seth Jennings <[email protected]>8*/910#include <asm/vio.h>11#include <asm/hvcall.h>12#include <asm/vas.h>13#include <crypto/internal/scompress.h>1415#include "nx-842.h"16#include "nx_csbcpb.h" /* struct nx_csbcpb */1718MODULE_LICENSE("GPL");19MODULE_AUTHOR("Robert Jennings <[email protected]>");20MODULE_DESCRIPTION("842 H/W Compression driver for IBM Power processors");21MODULE_ALIAS_CRYPTO("842");22MODULE_ALIAS_CRYPTO("842-nx");2324/*25* Coprocessor type specific capabilities from the hypervisor.26*/27struct hv_nx_cop_caps {28__be64 descriptor;29__be64 req_max_processed_len; /* Max bytes in one GZIP request */30__be64 min_compress_len; /* Min compression size in bytes */31__be64 min_decompress_len; /* Min decompression size in bytes */32} __packed __aligned(0x1000);3334/*35* Coprocessor type specific capabilities.36*/37struct nx_cop_caps {38u64 descriptor;39u64 req_max_processed_len; /* Max bytes in one GZIP request */40u64 min_compress_len; /* Min compression in bytes */41u64 min_decompress_len; /* Min decompression in bytes */42};4344static u64 caps_feat;45static struct nx_cop_caps nx_cop_caps;4647static struct nx842_constraints nx842_pseries_constraints = {48.alignment = DDE_BUFFER_ALIGN,49.multiple = DDE_BUFFER_LAST_MULT,50.minimum = DDE_BUFFER_LAST_MULT,51.maximum = PAGE_SIZE, /* dynamic, max_sync_size */52};5354static int check_constraints(unsigned long buf, unsigned int *len, bool in)55{56if (!IS_ALIGNED(buf, nx842_pseries_constraints.alignment)) {57pr_debug("%s buffer 0x%lx not aligned to 0x%x\n",58in ? "input" : "output", buf,59nx842_pseries_constraints.alignment);60return -EINVAL;61}62if (*len % nx842_pseries_constraints.multiple) {63pr_debug("%s buffer len 0x%x not multiple of 0x%x\n",64in ? "input" : "output", *len,65nx842_pseries_constraints.multiple);66if (in)67return -EINVAL;68*len = round_down(*len, nx842_pseries_constraints.multiple);69}70if (*len < nx842_pseries_constraints.minimum) {71pr_debug("%s buffer len 0x%x under minimum 0x%x\n",72in ? "input" : "output", *len,73nx842_pseries_constraints.minimum);74return -EINVAL;75}76if (*len > nx842_pseries_constraints.maximum) {77pr_debug("%s buffer len 0x%x over maximum 0x%x\n",78in ? "input" : "output", *len,79nx842_pseries_constraints.maximum);80if (in)81return -EINVAL;82*len = nx842_pseries_constraints.maximum;83}84return 0;85}8687/* I assume we need to align the CSB? */88#define WORKMEM_ALIGN (256)8990struct nx842_workmem {91/* scatterlist */92char slin[4096];93char slout[4096];94/* coprocessor status/parameter block */95struct nx_csbcpb csbcpb;9697char padding[WORKMEM_ALIGN];98} __aligned(WORKMEM_ALIGN);99100/* Macros for fields within nx_csbcpb */101/* Check the valid bit within the csbcpb valid field */102#define NX842_CSBCBP_VALID_CHK(x) (x & BIT_MASK(7))103104/* CE macros operate on the completion_extension field bits in the csbcpb.105* CE0 0=full completion, 1=partial completion106* CE1 0=CE0 indicates completion, 1=termination (output may be modified)107* CE2 0=processed_bytes is source bytes, 1=processed_bytes is target bytes */108#define NX842_CSBCPB_CE0(x) (x & BIT_MASK(7))109#define NX842_CSBCPB_CE1(x) (x & BIT_MASK(6))110#define NX842_CSBCPB_CE2(x) (x & BIT_MASK(5))111112/* The NX unit accepts data only on 4K page boundaries */113#define NX842_HW_PAGE_SIZE (4096)114#define NX842_HW_PAGE_MASK (~(NX842_HW_PAGE_SIZE-1))115116struct ibm_nx842_counters {117atomic64_t comp_complete;118atomic64_t comp_failed;119atomic64_t decomp_complete;120atomic64_t decomp_failed;121atomic64_t swdecomp;122atomic64_t comp_times[32];123atomic64_t decomp_times[32];124};125126struct nx842_devdata {127struct vio_dev *vdev;128struct device *dev;129struct ibm_nx842_counters *counters;130unsigned int max_sg_len;131unsigned int max_sync_size;132unsigned int max_sync_sg;133};134135static struct nx842_devdata __rcu *devdata;136static DEFINE_SPINLOCK(devdata_spinlock);137138#define NX842_COUNTER_INC(_x) \139static inline void nx842_inc_##_x( \140const struct nx842_devdata *dev) { \141if (dev) \142atomic64_inc(&dev->counters->_x); \143}144NX842_COUNTER_INC(comp_complete);145NX842_COUNTER_INC(comp_failed);146NX842_COUNTER_INC(decomp_complete);147NX842_COUNTER_INC(decomp_failed);148NX842_COUNTER_INC(swdecomp);149150#define NX842_HIST_SLOTS 16151152static void ibm_nx842_incr_hist(atomic64_t *times, unsigned int time)153{154int bucket = fls(time);155156if (bucket)157bucket = min((NX842_HIST_SLOTS - 1), bucket - 1);158159atomic64_inc(×[bucket]);160}161162/* NX unit operation flags */163#define NX842_OP_COMPRESS 0x0164#define NX842_OP_CRC 0x1165#define NX842_OP_DECOMPRESS 0x2166#define NX842_OP_COMPRESS_CRC (NX842_OP_COMPRESS | NX842_OP_CRC)167#define NX842_OP_DECOMPRESS_CRC (NX842_OP_DECOMPRESS | NX842_OP_CRC)168#define NX842_OP_ASYNC (1<<23)169#define NX842_OP_NOTIFY (1<<22)170#define NX842_OP_NOTIFY_INT(x) ((x & 0xff)<<8)171172static unsigned long nx842_get_desired_dma(struct vio_dev *viodev)173{174/* No use of DMA mappings within the driver. */175return 0;176}177178struct nx842_slentry {179__be64 ptr; /* Real address (use __pa()) */180__be64 len;181};182183/* pHyp scatterlist entry */184struct nx842_scatterlist {185int entry_nr; /* number of slentries */186struct nx842_slentry *entries; /* ptr to array of slentries */187};188189/* Does not include sizeof(entry_nr) in the size */190static inline unsigned long nx842_get_scatterlist_size(191struct nx842_scatterlist *sl)192{193return sl->entry_nr * sizeof(struct nx842_slentry);194}195196static int nx842_build_scatterlist(unsigned long buf, int len,197struct nx842_scatterlist *sl)198{199unsigned long entrylen;200struct nx842_slentry *entry;201202sl->entry_nr = 0;203204entry = sl->entries;205while (len) {206entry->ptr = cpu_to_be64(nx842_get_pa((void *)buf));207entrylen = min_t(int, len,208LEN_ON_SIZE(buf, NX842_HW_PAGE_SIZE));209entry->len = cpu_to_be64(entrylen);210211len -= entrylen;212buf += entrylen;213214sl->entry_nr++;215entry++;216}217218return 0;219}220221static int nx842_validate_result(struct device *dev,222struct cop_status_block *csb)223{224/* The csb must be valid after returning from vio_h_cop_sync */225if (!NX842_CSBCBP_VALID_CHK(csb->valid)) {226dev_err(dev, "%s: cspcbp not valid upon completion.\n",227__func__);228dev_dbg(dev, "valid:0x%02x cs:0x%02x cc:0x%02x ce:0x%02x\n",229csb->valid,230csb->crb_seq_number,231csb->completion_code,232csb->completion_extension);233dev_dbg(dev, "processed_bytes:%d address:0x%016lx\n",234be32_to_cpu(csb->processed_byte_count),235(unsigned long)be64_to_cpu(csb->address));236return -EIO;237}238239/* Check return values from the hardware in the CSB */240switch (csb->completion_code) {241case 0: /* Completed without error */242break;243case 64: /* Compression ok, but output larger than input */244dev_dbg(dev, "%s: output size larger than input size\n",245__func__);246break;247case 13: /* Output buffer too small */248dev_dbg(dev, "%s: Out of space in output buffer\n",249__func__);250return -ENOSPC;251case 65: /* Calculated CRC doesn't match the passed value */252dev_dbg(dev, "%s: CRC mismatch for decompression\n",253__func__);254return -EINVAL;255case 66: /* Input data contains an illegal template field */256case 67: /* Template indicates data past the end of the input stream */257dev_dbg(dev, "%s: Bad data for decompression (code:%d)\n",258__func__, csb->completion_code);259return -EINVAL;260default:261dev_dbg(dev, "%s: Unspecified error (code:%d)\n",262__func__, csb->completion_code);263return -EIO;264}265266/* Hardware sanity check */267if (!NX842_CSBCPB_CE2(csb->completion_extension)) {268dev_err(dev, "%s: No error returned by hardware, but "269"data returned is unusable, contact support.\n"270"(Additional info: csbcbp->processed bytes "271"does not specify processed bytes for the "272"target buffer.)\n", __func__);273return -EIO;274}275276return 0;277}278279/**280* nx842_pseries_compress - Compress data using the 842 algorithm281*282* Compression provide by the NX842 coprocessor on IBM Power systems.283* The input buffer is compressed and the result is stored in the284* provided output buffer.285*286* Upon return from this function @outlen contains the length of the287* compressed data. If there is an error then @outlen will be 0 and an288* error will be specified by the return code from this function.289*290* @in: Pointer to input buffer291* @inlen: Length of input buffer292* @out: Pointer to output buffer293* @outlen: Length of output buffer294* @wmem: ptr to buffer for working memory, size determined by295* nx842_pseries_driver.workmem_size296*297* Returns:298* 0 Success, output of length @outlen stored in the buffer at @out299* -ENOMEM Unable to allocate internal buffers300* -ENOSPC Output buffer is to small301* -EIO Internal error302* -ENODEV Hardware unavailable303*/304static int nx842_pseries_compress(const unsigned char *in, unsigned int inlen,305unsigned char *out, unsigned int *outlen,306void *wmem)307{308struct nx842_devdata *local_devdata;309struct device *dev = NULL;310struct nx842_workmem *workmem;311struct nx842_scatterlist slin, slout;312struct nx_csbcpb *csbcpb;313int ret = 0;314unsigned long inbuf, outbuf;315struct vio_pfo_op op = {316.done = NULL,317.handle = 0,318.timeout = 0,319};320unsigned long start = get_tb();321322inbuf = (unsigned long)in;323if (check_constraints(inbuf, &inlen, true))324return -EINVAL;325326outbuf = (unsigned long)out;327if (check_constraints(outbuf, outlen, false))328return -EINVAL;329330rcu_read_lock();331local_devdata = rcu_dereference(devdata);332if (!local_devdata || !local_devdata->dev) {333rcu_read_unlock();334return -ENODEV;335}336dev = local_devdata->dev;337338/* Init scatterlist */339workmem = PTR_ALIGN(wmem, WORKMEM_ALIGN);340slin.entries = (struct nx842_slentry *)workmem->slin;341slout.entries = (struct nx842_slentry *)workmem->slout;342343/* Init operation */344op.flags = NX842_OP_COMPRESS_CRC;345csbcpb = &workmem->csbcpb;346memset(csbcpb, 0, sizeof(*csbcpb));347op.csbcpb = nx842_get_pa(csbcpb);348349if ((inbuf & NX842_HW_PAGE_MASK) ==350((inbuf + inlen - 1) & NX842_HW_PAGE_MASK)) {351/* Create direct DDE */352op.in = nx842_get_pa((void *)inbuf);353op.inlen = inlen;354} else {355/* Create indirect DDE (scatterlist) */356nx842_build_scatterlist(inbuf, inlen, &slin);357op.in = nx842_get_pa(slin.entries);358op.inlen = -nx842_get_scatterlist_size(&slin);359}360361if ((outbuf & NX842_HW_PAGE_MASK) ==362((outbuf + *outlen - 1) & NX842_HW_PAGE_MASK)) {363/* Create direct DDE */364op.out = nx842_get_pa((void *)outbuf);365op.outlen = *outlen;366} else {367/* Create indirect DDE (scatterlist) */368nx842_build_scatterlist(outbuf, *outlen, &slout);369op.out = nx842_get_pa(slout.entries);370op.outlen = -nx842_get_scatterlist_size(&slout);371}372373dev_dbg(dev, "%s: op.in %lx op.inlen %ld op.out %lx op.outlen %ld\n",374__func__, (unsigned long)op.in, (long)op.inlen,375(unsigned long)op.out, (long)op.outlen);376377/* Send request to pHyp */378ret = vio_h_cop_sync(local_devdata->vdev, &op);379380/* Check for pHyp error */381if (ret) {382dev_dbg(dev, "%s: vio_h_cop_sync error (ret=%d, hret=%ld)\n",383__func__, ret, op.hcall_err);384ret = -EIO;385goto unlock;386}387388/* Check for hardware error */389ret = nx842_validate_result(dev, &csbcpb->csb);390if (ret)391goto unlock;392393*outlen = be32_to_cpu(csbcpb->csb.processed_byte_count);394dev_dbg(dev, "%s: processed_bytes=%d\n", __func__, *outlen);395396unlock:397if (ret)398nx842_inc_comp_failed(local_devdata);399else {400nx842_inc_comp_complete(local_devdata);401ibm_nx842_incr_hist(local_devdata->counters->comp_times,402(get_tb() - start) / tb_ticks_per_usec);403}404rcu_read_unlock();405return ret;406}407408/**409* nx842_pseries_decompress - Decompress data using the 842 algorithm410*411* Decompression provide by the NX842 coprocessor on IBM Power systems.412* The input buffer is decompressed and the result is stored in the413* provided output buffer. The size allocated to the output buffer is414* provided by the caller of this function in @outlen. Upon return from415* this function @outlen contains the length of the decompressed data.416* If there is an error then @outlen will be 0 and an error will be417* specified by the return code from this function.418*419* @in: Pointer to input buffer420* @inlen: Length of input buffer421* @out: Pointer to output buffer422* @outlen: Length of output buffer423* @wmem: ptr to buffer for working memory, size determined by424* nx842_pseries_driver.workmem_size425*426* Returns:427* 0 Success, output of length @outlen stored in the buffer at @out428* -ENODEV Hardware decompression device is unavailable429* -ENOMEM Unable to allocate internal buffers430* -ENOSPC Output buffer is to small431* -EINVAL Bad input data encountered when attempting decompress432* -EIO Internal error433*/434static int nx842_pseries_decompress(const unsigned char *in, unsigned int inlen,435unsigned char *out, unsigned int *outlen,436void *wmem)437{438struct nx842_devdata *local_devdata;439struct device *dev = NULL;440struct nx842_workmem *workmem;441struct nx842_scatterlist slin, slout;442struct nx_csbcpb *csbcpb;443int ret = 0;444unsigned long inbuf, outbuf;445struct vio_pfo_op op = {446.done = NULL,447.handle = 0,448.timeout = 0,449};450unsigned long start = get_tb();451452/* Ensure page alignment and size */453inbuf = (unsigned long)in;454if (check_constraints(inbuf, &inlen, true))455return -EINVAL;456457outbuf = (unsigned long)out;458if (check_constraints(outbuf, outlen, false))459return -EINVAL;460461rcu_read_lock();462local_devdata = rcu_dereference(devdata);463if (!local_devdata || !local_devdata->dev) {464rcu_read_unlock();465return -ENODEV;466}467dev = local_devdata->dev;468469workmem = PTR_ALIGN(wmem, WORKMEM_ALIGN);470471/* Init scatterlist */472slin.entries = (struct nx842_slentry *)workmem->slin;473slout.entries = (struct nx842_slentry *)workmem->slout;474475/* Init operation */476op.flags = NX842_OP_DECOMPRESS_CRC;477csbcpb = &workmem->csbcpb;478memset(csbcpb, 0, sizeof(*csbcpb));479op.csbcpb = nx842_get_pa(csbcpb);480481if ((inbuf & NX842_HW_PAGE_MASK) ==482((inbuf + inlen - 1) & NX842_HW_PAGE_MASK)) {483/* Create direct DDE */484op.in = nx842_get_pa((void *)inbuf);485op.inlen = inlen;486} else {487/* Create indirect DDE (scatterlist) */488nx842_build_scatterlist(inbuf, inlen, &slin);489op.in = nx842_get_pa(slin.entries);490op.inlen = -nx842_get_scatterlist_size(&slin);491}492493if ((outbuf & NX842_HW_PAGE_MASK) ==494((outbuf + *outlen - 1) & NX842_HW_PAGE_MASK)) {495/* Create direct DDE */496op.out = nx842_get_pa((void *)outbuf);497op.outlen = *outlen;498} else {499/* Create indirect DDE (scatterlist) */500nx842_build_scatterlist(outbuf, *outlen, &slout);501op.out = nx842_get_pa(slout.entries);502op.outlen = -nx842_get_scatterlist_size(&slout);503}504505dev_dbg(dev, "%s: op.in %lx op.inlen %ld op.out %lx op.outlen %ld\n",506__func__, (unsigned long)op.in, (long)op.inlen,507(unsigned long)op.out, (long)op.outlen);508509/* Send request to pHyp */510ret = vio_h_cop_sync(local_devdata->vdev, &op);511512/* Check for pHyp error */513if (ret) {514dev_dbg(dev, "%s: vio_h_cop_sync error (ret=%d, hret=%ld)\n",515__func__, ret, op.hcall_err);516goto unlock;517}518519/* Check for hardware error */520ret = nx842_validate_result(dev, &csbcpb->csb);521if (ret)522goto unlock;523524*outlen = be32_to_cpu(csbcpb->csb.processed_byte_count);525526unlock:527if (ret)528/* decompress fail */529nx842_inc_decomp_failed(local_devdata);530else {531nx842_inc_decomp_complete(local_devdata);532ibm_nx842_incr_hist(local_devdata->counters->decomp_times,533(get_tb() - start) / tb_ticks_per_usec);534}535536rcu_read_unlock();537return ret;538}539540/**541* nx842_OF_set_defaults -- Set default (disabled) values for devdata542*543* @devdata: struct nx842_devdata to update544*545* Returns:546* 0 on success547* -ENOENT if @devdata ptr is NULL548*/549static int nx842_OF_set_defaults(struct nx842_devdata *devdata)550{551if (devdata) {552devdata->max_sync_size = 0;553devdata->max_sync_sg = 0;554devdata->max_sg_len = 0;555return 0;556} else557return -ENOENT;558}559560/**561* nx842_OF_upd_status -- Check the device info from OF status prop562*563* The status property indicates if the accelerator is enabled. If the564* device is in the OF tree it indicates that the hardware is present.565* The status field indicates if the device is enabled when the status566* is 'okay'. Otherwise the device driver will be disabled.567*568* @devdata: struct nx842_devdata to use for dev_info569* @prop: struct property point containing the maxsyncop for the update570*571* Returns:572* 0 - Device is available573* -ENODEV - Device is not available574*/575static int nx842_OF_upd_status(struct nx842_devdata *devdata,576struct property *prop)577{578const char *status = (const char *)prop->value;579580if (!strncmp(status, "okay", (size_t)prop->length))581return 0;582if (!strncmp(status, "disabled", (size_t)prop->length))583return -ENODEV;584dev_info(devdata->dev, "%s: unknown status '%s'\n", __func__, status);585586return -EINVAL;587}588589/**590* nx842_OF_upd_maxsglen -- Update the device info from OF maxsglen prop591*592* Definition of the 'ibm,max-sg-len' OF property:593* This field indicates the maximum byte length of a scatter list594* for the platform facility. It is a single cell encoded as with encode-int.595*596* Example:597* # od -x ibm,max-sg-len598* 0000000 0000 0ff0599*600* In this example, the maximum byte length of a scatter list is601* 0x0ff0 (4,080).602*603* @devdata: struct nx842_devdata to update604* @prop: struct property point containing the maxsyncop for the update605*606* Returns:607* 0 on success608* -EINVAL on failure609*/610static int nx842_OF_upd_maxsglen(struct nx842_devdata *devdata,611struct property *prop) {612int ret = 0;613const unsigned int maxsglen = of_read_number(prop->value, 1);614615if (prop->length != sizeof(maxsglen)) {616dev_err(devdata->dev, "%s: unexpected format for ibm,max-sg-len property\n", __func__);617dev_dbg(devdata->dev, "%s: ibm,max-sg-len is %d bytes long, expected %lu bytes\n", __func__,618prop->length, sizeof(maxsglen));619ret = -EINVAL;620} else {621devdata->max_sg_len = min_t(unsigned int,622maxsglen, NX842_HW_PAGE_SIZE);623}624625return ret;626}627628/**629* nx842_OF_upd_maxsyncop -- Update the device info from OF maxsyncop prop630*631* Definition of the 'ibm,max-sync-cop' OF property:632* Two series of cells. The first series of cells represents the maximums633* that can be synchronously compressed. The second series of cells634* represents the maximums that can be synchronously decompressed.635* 1. The first cell in each series contains the count of the number of636* data length, scatter list elements pairs that follow – each being637* of the form638* a. One cell data byte length639* b. One cell total number of scatter list elements640*641* Example:642* # od -x ibm,max-sync-cop643* 0000000 0000 0001 0000 1000 0000 01fe 0000 0001644* 0000020 0000 1000 0000 01fe645*646* In this example, compression supports 0x1000 (4,096) data byte length647* and 0x1fe (510) total scatter list elements. Decompression supports648* 0x1000 (4,096) data byte length and 0x1f3 (510) total scatter list649* elements.650*651* @devdata: struct nx842_devdata to update652* @prop: struct property point containing the maxsyncop for the update653*654* Returns:655* 0 on success656* -EINVAL on failure657*/658static int nx842_OF_upd_maxsyncop(struct nx842_devdata *devdata,659struct property *prop) {660int ret = 0;661unsigned int comp_data_limit, decomp_data_limit;662unsigned int comp_sg_limit, decomp_sg_limit;663const struct maxsynccop_t {664__be32 comp_elements;665__be32 comp_data_limit;666__be32 comp_sg_limit;667__be32 decomp_elements;668__be32 decomp_data_limit;669__be32 decomp_sg_limit;670} *maxsynccop;671672if (prop->length != sizeof(*maxsynccop)) {673dev_err(devdata->dev, "%s: unexpected format for ibm,max-sync-cop property\n", __func__);674dev_dbg(devdata->dev, "%s: ibm,max-sync-cop is %d bytes long, expected %lu bytes\n", __func__, prop->length,675sizeof(*maxsynccop));676ret = -EINVAL;677goto out;678}679680maxsynccop = (const struct maxsynccop_t *)prop->value;681comp_data_limit = be32_to_cpu(maxsynccop->comp_data_limit);682comp_sg_limit = be32_to_cpu(maxsynccop->comp_sg_limit);683decomp_data_limit = be32_to_cpu(maxsynccop->decomp_data_limit);684decomp_sg_limit = be32_to_cpu(maxsynccop->decomp_sg_limit);685686/* Use one limit rather than separate limits for compression and687* decompression. Set a maximum for this so as not to exceed the688* size that the header can support and round the value down to689* the hardware page size (4K) */690devdata->max_sync_size = min(comp_data_limit, decomp_data_limit);691692devdata->max_sync_size = min_t(unsigned int, devdata->max_sync_size,69365536);694695if (devdata->max_sync_size < 4096) {696dev_err(devdata->dev, "%s: hardware max data size (%u) is "697"less than the driver minimum, unable to use "698"the hardware device\n",699__func__, devdata->max_sync_size);700ret = -EINVAL;701goto out;702}703704nx842_pseries_constraints.maximum = devdata->max_sync_size;705706devdata->max_sync_sg = min(comp_sg_limit, decomp_sg_limit);707if (devdata->max_sync_sg < 1) {708dev_err(devdata->dev, "%s: hardware max sg size (%u) is "709"less than the driver minimum, unable to use "710"the hardware device\n",711__func__, devdata->max_sync_sg);712ret = -EINVAL;713goto out;714}715716out:717return ret;718}719720/**721* nx842_OF_upd -- Handle OF properties updates for the device.722*723* Set all properties from the OF tree. Optionally, a new property724* can be provided by the @new_prop pointer to overwrite an existing value.725* The device will remain disabled until all values are valid, this function726* will return an error for updates unless all values are valid.727*728* @new_prop: If not NULL, this property is being updated. If NULL, update729* all properties from the current values in the OF tree.730*731* Returns:732* 0 - Success733* -ENOMEM - Could not allocate memory for new devdata structure734* -EINVAL - property value not found, new_prop is not a recognized735* property for the device or property value is not valid.736* -ENODEV - Device is not available737*/738static int nx842_OF_upd(struct property *new_prop)739{740struct nx842_devdata *old_devdata = NULL;741struct nx842_devdata *new_devdata = NULL;742struct device_node *of_node = NULL;743struct property *status = NULL;744struct property *maxsglen = NULL;745struct property *maxsyncop = NULL;746int ret = 0;747unsigned long flags;748749new_devdata = kzalloc(sizeof(*new_devdata), GFP_NOFS);750if (!new_devdata)751return -ENOMEM;752753spin_lock_irqsave(&devdata_spinlock, flags);754old_devdata = rcu_dereference_check(devdata,755lockdep_is_held(&devdata_spinlock));756if (old_devdata)757of_node = old_devdata->dev->of_node;758759if (!old_devdata || !of_node) {760pr_err("%s: device is not available\n", __func__);761spin_unlock_irqrestore(&devdata_spinlock, flags);762kfree(new_devdata);763return -ENODEV;764}765766memcpy(new_devdata, old_devdata, sizeof(*old_devdata));767new_devdata->counters = old_devdata->counters;768769/* Set ptrs for existing properties */770status = of_find_property(of_node, "status", NULL);771maxsglen = of_find_property(of_node, "ibm,max-sg-len", NULL);772maxsyncop = of_find_property(of_node, "ibm,max-sync-cop", NULL);773if (!status || !maxsglen || !maxsyncop) {774dev_err(old_devdata->dev, "%s: Could not locate device properties\n", __func__);775ret = -EINVAL;776goto error_out;777}778779/*780* If this is a property update, there are only certain properties that781* we care about. Bail if it isn't in the below list782*/783if (new_prop && (strncmp(new_prop->name, "status", new_prop->length) ||784strncmp(new_prop->name, "ibm,max-sg-len", new_prop->length) ||785strncmp(new_prop->name, "ibm,max-sync-cop", new_prop->length)))786goto out;787788/* Perform property updates */789ret = nx842_OF_upd_status(new_devdata, status);790if (ret)791goto error_out;792793ret = nx842_OF_upd_maxsglen(new_devdata, maxsglen);794if (ret)795goto error_out;796797ret = nx842_OF_upd_maxsyncop(new_devdata, maxsyncop);798if (ret)799goto error_out;800801out:802dev_info(old_devdata->dev, "%s: max_sync_size new:%u old:%u\n",803__func__, new_devdata->max_sync_size,804old_devdata->max_sync_size);805dev_info(old_devdata->dev, "%s: max_sync_sg new:%u old:%u\n",806__func__, new_devdata->max_sync_sg,807old_devdata->max_sync_sg);808dev_info(old_devdata->dev, "%s: max_sg_len new:%u old:%u\n",809__func__, new_devdata->max_sg_len,810old_devdata->max_sg_len);811812rcu_assign_pointer(devdata, new_devdata);813spin_unlock_irqrestore(&devdata_spinlock, flags);814synchronize_rcu();815dev_set_drvdata(new_devdata->dev, new_devdata);816kfree(old_devdata);817return 0;818819error_out:820if (new_devdata) {821dev_info(old_devdata->dev, "%s: device disabled\n", __func__);822nx842_OF_set_defaults(new_devdata);823rcu_assign_pointer(devdata, new_devdata);824spin_unlock_irqrestore(&devdata_spinlock, flags);825synchronize_rcu();826dev_set_drvdata(new_devdata->dev, new_devdata);827kfree(old_devdata);828} else {829dev_err(old_devdata->dev, "%s: could not update driver from hardware\n", __func__);830spin_unlock_irqrestore(&devdata_spinlock, flags);831}832833if (!ret)834ret = -EINVAL;835return ret;836}837838/**839* nx842_OF_notifier - Process updates to OF properties for the device840*841* @np: notifier block842* @action: notifier action843* @data: struct of_reconfig_data pointer844*845* Returns:846* NOTIFY_OK on success847* NOTIFY_BAD encoded with error number on failure, use848* notifier_to_errno() to decode this value849*/850static int nx842_OF_notifier(struct notifier_block *np, unsigned long action,851void *data)852{853struct of_reconfig_data *upd = data;854struct nx842_devdata *local_devdata;855struct device_node *node = NULL;856857rcu_read_lock();858local_devdata = rcu_dereference(devdata);859if (local_devdata)860node = local_devdata->dev->of_node;861862if (local_devdata &&863action == OF_RECONFIG_UPDATE_PROPERTY &&864!strcmp(upd->dn->name, node->name)) {865rcu_read_unlock();866nx842_OF_upd(upd->prop);867} else868rcu_read_unlock();869870return NOTIFY_OK;871}872873static struct notifier_block nx842_of_nb = {874.notifier_call = nx842_OF_notifier,875};876877#define nx842_counter_read(_name) \878static ssize_t nx842_##_name##_show(struct device *dev, \879struct device_attribute *attr, \880char *buf) { \881struct nx842_devdata *local_devdata; \882int p = 0; \883rcu_read_lock(); \884local_devdata = rcu_dereference(devdata); \885if (local_devdata) \886p = snprintf(buf, PAGE_SIZE, "%lld\n", \887atomic64_read(&local_devdata->counters->_name)); \888rcu_read_unlock(); \889return p; \890}891892#define NX842DEV_COUNTER_ATTR_RO(_name) \893nx842_counter_read(_name); \894static struct device_attribute dev_attr_##_name = __ATTR(_name, \8950444, \896nx842_##_name##_show,\897NULL);898899NX842DEV_COUNTER_ATTR_RO(comp_complete);900NX842DEV_COUNTER_ATTR_RO(comp_failed);901NX842DEV_COUNTER_ATTR_RO(decomp_complete);902NX842DEV_COUNTER_ATTR_RO(decomp_failed);903NX842DEV_COUNTER_ATTR_RO(swdecomp);904905static ssize_t nx842_timehist_show(struct device *,906struct device_attribute *, char *);907908static struct device_attribute dev_attr_comp_times = __ATTR(comp_times, 0444,909nx842_timehist_show, NULL);910static struct device_attribute dev_attr_decomp_times = __ATTR(decomp_times,9110444, nx842_timehist_show, NULL);912913static ssize_t nx842_timehist_show(struct device *dev,914struct device_attribute *attr, char *buf) {915char *p = buf;916struct nx842_devdata *local_devdata;917atomic64_t *times;918int bytes_remain = PAGE_SIZE;919int bytes;920int i;921922rcu_read_lock();923local_devdata = rcu_dereference(devdata);924if (!local_devdata) {925rcu_read_unlock();926return 0;927}928929if (attr == &dev_attr_comp_times)930times = local_devdata->counters->comp_times;931else if (attr == &dev_attr_decomp_times)932times = local_devdata->counters->decomp_times;933else {934rcu_read_unlock();935return 0;936}937938for (i = 0; i < (NX842_HIST_SLOTS - 2); i++) {939bytes = snprintf(p, bytes_remain, "%u-%uus:\t%lld\n",940i ? (2<<(i-1)) : 0, (2<<i)-1,941atomic64_read(×[i]));942bytes_remain -= bytes;943p += bytes;944}945/* The last bucket holds everything over946* 2<<(NX842_HIST_SLOTS - 2) us */947bytes = snprintf(p, bytes_remain, "%uus - :\t%lld\n",9482<<(NX842_HIST_SLOTS - 2),949atomic64_read(×[(NX842_HIST_SLOTS - 1)]));950p += bytes;951952rcu_read_unlock();953return p - buf;954}955956static struct attribute *nx842_sysfs_entries[] = {957&dev_attr_comp_complete.attr,958&dev_attr_comp_failed.attr,959&dev_attr_decomp_complete.attr,960&dev_attr_decomp_failed.attr,961&dev_attr_swdecomp.attr,962&dev_attr_comp_times.attr,963&dev_attr_decomp_times.attr,964NULL,965};966967static const struct attribute_group nx842_attribute_group = {968.name = NULL, /* put in device directory */969.attrs = nx842_sysfs_entries,970};971972#define nxcop_caps_read(_name) \973static ssize_t nxcop_##_name##_show(struct device *dev, \974struct device_attribute *attr, char *buf) \975{ \976return sprintf(buf, "%lld\n", nx_cop_caps._name); \977}978979#define NXCT_ATTR_RO(_name) \980nxcop_caps_read(_name); \981static struct device_attribute dev_attr_##_name = __ATTR(_name, \9820444, \983nxcop_##_name##_show, \984NULL);985986NXCT_ATTR_RO(req_max_processed_len);987NXCT_ATTR_RO(min_compress_len);988NXCT_ATTR_RO(min_decompress_len);989990static struct attribute *nxcop_caps_sysfs_entries[] = {991&dev_attr_req_max_processed_len.attr,992&dev_attr_min_compress_len.attr,993&dev_attr_min_decompress_len.attr,994NULL,995};996997static const struct attribute_group nxcop_caps_attr_group = {998.name = "nx_gzip_caps",999.attrs = nxcop_caps_sysfs_entries,1000};10011002static struct nx842_driver nx842_pseries_driver = {1003.name = KBUILD_MODNAME,1004.owner = THIS_MODULE,1005.workmem_size = sizeof(struct nx842_workmem),1006.constraints = &nx842_pseries_constraints,1007.compress = nx842_pseries_compress,1008.decompress = nx842_pseries_decompress,1009};10101011static void *nx842_pseries_crypto_alloc_ctx(void)1012{1013return nx842_crypto_alloc_ctx(&nx842_pseries_driver);1014}10151016static struct scomp_alg nx842_pseries_alg = {1017.base.cra_name = "842",1018.base.cra_driver_name = "842-nx",1019.base.cra_priority = 300,1020.base.cra_module = THIS_MODULE,10211022.alloc_ctx = nx842_pseries_crypto_alloc_ctx,1023.free_ctx = nx842_crypto_free_ctx,1024.compress = nx842_crypto_compress,1025.decompress = nx842_crypto_decompress,1026};10271028static int nx842_probe(struct vio_dev *viodev,1029const struct vio_device_id *id)1030{1031struct nx842_devdata *old_devdata, *new_devdata = NULL;1032unsigned long flags;1033int ret = 0;10341035new_devdata = kzalloc(sizeof(*new_devdata), GFP_NOFS);1036if (!new_devdata)1037return -ENOMEM;10381039new_devdata->counters = kzalloc(sizeof(*new_devdata->counters),1040GFP_NOFS);1041if (!new_devdata->counters) {1042kfree(new_devdata);1043return -ENOMEM;1044}10451046spin_lock_irqsave(&devdata_spinlock, flags);1047old_devdata = rcu_dereference_check(devdata,1048lockdep_is_held(&devdata_spinlock));10491050if (old_devdata && old_devdata->vdev != NULL) {1051dev_err(&viodev->dev, "%s: Attempt to register more than one instance of the hardware\n", __func__);1052ret = -1;1053goto error_unlock;1054}10551056dev_set_drvdata(&viodev->dev, NULL);10571058new_devdata->vdev = viodev;1059new_devdata->dev = &viodev->dev;1060nx842_OF_set_defaults(new_devdata);10611062rcu_assign_pointer(devdata, new_devdata);1063spin_unlock_irqrestore(&devdata_spinlock, flags);1064synchronize_rcu();1065kfree(old_devdata);10661067of_reconfig_notifier_register(&nx842_of_nb);10681069ret = nx842_OF_upd(NULL);1070if (ret)1071goto error;10721073ret = crypto_register_scomp(&nx842_pseries_alg);1074if (ret) {1075dev_err(&viodev->dev, "could not register comp alg: %d\n", ret);1076goto error;1077}10781079rcu_read_lock();1080dev_set_drvdata(&viodev->dev, rcu_dereference(devdata));1081rcu_read_unlock();10821083if (sysfs_create_group(&viodev->dev.kobj, &nx842_attribute_group)) {1084dev_err(&viodev->dev, "could not create sysfs device attributes\n");1085ret = -1;1086goto error;1087}10881089if (caps_feat) {1090if (sysfs_create_group(&viodev->dev.kobj,1091&nxcop_caps_attr_group)) {1092dev_err(&viodev->dev,1093"Could not create sysfs NX capability entries\n");1094ret = -1;1095goto error;1096}1097}10981099return 0;11001101error_unlock:1102spin_unlock_irqrestore(&devdata_spinlock, flags);1103if (new_devdata)1104kfree(new_devdata->counters);1105kfree(new_devdata);1106error:1107return ret;1108}11091110static void nx842_remove(struct vio_dev *viodev)1111{1112struct nx842_devdata *old_devdata;1113unsigned long flags;11141115pr_info("Removing IBM Power 842 compression device\n");1116sysfs_remove_group(&viodev->dev.kobj, &nx842_attribute_group);11171118if (caps_feat)1119sysfs_remove_group(&viodev->dev.kobj, &nxcop_caps_attr_group);11201121crypto_unregister_scomp(&nx842_pseries_alg);11221123of_reconfig_notifier_unregister(&nx842_of_nb);11241125spin_lock_irqsave(&devdata_spinlock, flags);1126old_devdata = rcu_dereference_check(devdata,1127lockdep_is_held(&devdata_spinlock));1128RCU_INIT_POINTER(devdata, NULL);1129spin_unlock_irqrestore(&devdata_spinlock, flags);1130synchronize_rcu();1131dev_set_drvdata(&viodev->dev, NULL);1132if (old_devdata)1133kfree(old_devdata->counters);1134kfree(old_devdata);1135}11361137/*1138* Get NX capabilities from the hypervisor.1139* Only NXGZIP capabilities are provided by the hypersvisor right1140* now and these values are available to user space with sysfs.1141*/1142static void __init nxcop_get_capabilities(void)1143{1144struct hv_vas_all_caps *hv_caps;1145struct hv_nx_cop_caps *hv_nxc;1146u64 feat;1147int rc;11481149hv_caps = kmalloc(sizeof(*hv_caps), GFP_KERNEL);1150if (!hv_caps)1151return;1152/*1153* Get NX overall capabilities with feature type=01154*/1155rc = h_query_vas_capabilities(H_QUERY_NX_CAPABILITIES, 0,1156(u64)virt_to_phys(hv_caps));1157if (!rc)1158feat = be64_to_cpu(hv_caps->feat_type);1159kfree(hv_caps);1160if (rc)1161return;1162if (!(feat & VAS_NX_GZIP_FEAT_BIT))1163return;11641165/*1166* NX-GZIP feature available1167*/1168hv_nxc = kmalloc(sizeof(*hv_nxc), GFP_KERNEL);1169if (!hv_nxc)1170return;1171/*1172* Get capabilities for NX-GZIP feature1173*/1174rc = h_query_vas_capabilities(H_QUERY_NX_CAPABILITIES,1175VAS_NX_GZIP_FEAT,1176(u64)virt_to_phys(hv_nxc));11771178if (!rc) {1179nx_cop_caps.descriptor = be64_to_cpu(hv_nxc->descriptor);1180nx_cop_caps.req_max_processed_len =1181be64_to_cpu(hv_nxc->req_max_processed_len);1182nx_cop_caps.min_compress_len =1183be64_to_cpu(hv_nxc->min_compress_len);1184nx_cop_caps.min_decompress_len =1185be64_to_cpu(hv_nxc->min_decompress_len);1186caps_feat = feat;1187}11881189kfree(hv_nxc);1190}11911192static const struct vio_device_id nx842_vio_driver_ids[] = {1193{"ibm,compression-v1", "ibm,compression"},1194{"", ""},1195};1196MODULE_DEVICE_TABLE(vio, nx842_vio_driver_ids);11971198static struct vio_driver nx842_vio_driver = {1199.name = KBUILD_MODNAME,1200.probe = nx842_probe,1201.remove = nx842_remove,1202.get_desired_dma = nx842_get_desired_dma,1203.id_table = nx842_vio_driver_ids,1204};12051206static int __init nx842_pseries_init(void)1207{1208struct nx842_devdata *new_devdata;1209struct device_node *np;1210int ret;12111212np = of_find_compatible_node(NULL, NULL, "ibm,compression");1213if (!np)1214return -ENODEV;1215of_node_put(np);12161217RCU_INIT_POINTER(devdata, NULL);1218new_devdata = kzalloc(sizeof(*new_devdata), GFP_KERNEL);1219if (!new_devdata)1220return -ENOMEM;12211222RCU_INIT_POINTER(devdata, new_devdata);1223/*1224* Get NX capabilities from the hypervisor.1225*/1226nxcop_get_capabilities();12271228ret = vio_register_driver(&nx842_vio_driver);1229if (ret) {1230pr_err("Could not register VIO driver %d\n", ret);12311232kfree(new_devdata);1233return ret;1234}12351236ret = vas_register_api_pseries(THIS_MODULE, VAS_COP_TYPE_GZIP,1237"nx-gzip");12381239if (ret)1240pr_err("NX-GZIP is not supported. Returned=%d\n", ret);12411242return 0;1243}12441245module_init(nx842_pseries_init);12461247static void __exit nx842_pseries_exit(void)1248{1249struct nx842_devdata *old_devdata;1250unsigned long flags;12511252vas_unregister_api_pseries();12531254crypto_unregister_scomp(&nx842_pseries_alg);12551256spin_lock_irqsave(&devdata_spinlock, flags);1257old_devdata = rcu_dereference_check(devdata,1258lockdep_is_held(&devdata_spinlock));1259RCU_INIT_POINTER(devdata, NULL);1260spin_unlock_irqrestore(&devdata_spinlock, flags);1261synchronize_rcu();1262if (old_devdata && old_devdata->dev)1263dev_set_drvdata(old_devdata->dev, NULL);1264kfree(old_devdata);1265vio_unregister_driver(&nx842_vio_driver);1266}12671268module_exit(nx842_pseries_exit);1269127012711272