MODULE_LICENSE("GPL");
MODULE_AUTHOR("Robert Jennings ");
MODULE_DESCRIPTION("842 H/W Compression driver for IBM Power processors");
MODULE_ALIAS_CRYPTO("842");
MODULE_ALIAS_CRYPTO("842-nx");
/* * Coprocessor type specific capabilities from the hypervisor.
*/ struct hv_nx_cop_caps {
__be64 descriptor;
__be64 req_max_processed_len; /* Max bytes in one GZIP request */
__be64 min_compress_len; /* Min compression size in bytes */
__be64 min_decompress_len; /* Min decompression size in bytes */
} __packed __aligned(0x1000);
/* * Coprocessor type specific capabilities.
*/ struct nx_cop_caps {
u64 descriptor;
u64 req_max_processed_len; /* Max bytes in one GZIP request */
u64 min_compress_len; /* Min compression in bytes */
u64 min_decompress_len; /* Min decompression in bytes */
};
/* pHyp scatterlist entry */ struct nx842_scatterlist { int entry_nr; /* number of slentries */ struct nx842_slentry *entries; /* ptr to array of slentries */
};
/* Does not include sizeof(entry_nr) in the size */ staticinlineunsignedlong nx842_get_scatterlist_size( struct nx842_scatterlist *sl)
{ return sl->entry_nr * sizeof(struct nx842_slentry);
}
staticint nx842_validate_result(struct device *dev, struct cop_status_block *csb)
{ /* The csb must be valid after returning from vio_h_cop_sync */ if (!NX842_CSBCBP_VALID_CHK(csb->valid)) {
dev_err(dev, "%s: cspcbp not valid upon completion.\n",
__func__);
dev_dbg(dev, "valid:0x%02x cs:0x%02x cc:0x%02x ce:0x%02x\n",
csb->valid,
csb->crb_seq_number,
csb->completion_code,
csb->completion_extension);
dev_dbg(dev, "processed_bytes:%d address:0x%016lx\n",
be32_to_cpu(csb->processed_byte_count),
(unsignedlong)be64_to_cpu(csb->address)); return -EIO;
}
/* Check return values from the hardware in the CSB */ switch (csb->completion_code) { case 0: /* Completed without error */ break; case 64: /* Compression ok, but output larger than input */
dev_dbg(dev, "%s: output size larger than input size\n",
__func__); break; case 13: /* Output buffer too small */
dev_dbg(dev, "%s: Out of space in output buffer\n",
__func__); return -ENOSPC; case 65: /* Calculated CRC doesn't match the passed value */
dev_dbg(dev, "%s: CRC mismatch for decompression\n",
__func__); return -EINVAL; case 66: /* Input data contains an illegal template field */ case 67: /* Template indicates data past the end of the input stream */
dev_dbg(dev, "%s: Bad data for decompression (code:%d)\n",
__func__, csb->completion_code); return -EINVAL; default:
dev_dbg(dev, "%s: Unspecified error (code:%d)\n",
__func__, csb->completion_code); return -EIO;
}
/* Hardware sanity check */ if (!NX842_CSBCPB_CE2(csb->completion_extension)) {
dev_err(dev, "%s: No error returned by hardware, but " "data returned is unusable, contact support.\n" "(Additional info: csbcbp->processed bytes " "does not specify processed bytes for the " "target buffer.)\n", __func__); return -EIO;
}
return 0;
}
/** * nx842_pseries_compress - Compress data using the 842 algorithm * * Compression provide by the NX842 coprocessor on IBM Power systems. * The input buffer is compressed and the result is stored in the * provided output buffer. * * Upon return from this function @outlen contains the length of the * compressed data. If there is an error then @outlen will be 0 and an * error will be specified by the return code from this function. * * @in: Pointer to input buffer * @inlen: Length of input buffer * @out: Pointer to output buffer * @outlen: Length of output buffer * @wmem: ptr to buffer for working memory, size determined by * nx842_pseries_driver.workmem_size * * Returns: * 0 Success, output of length @outlen stored in the buffer at @out * -ENOMEM Unable to allocate internal buffers * -ENOSPC Output buffer is to small * -EIO Internal error * -ENODEV Hardware unavailable
*/ staticint nx842_pseries_compress(constunsignedchar *in, unsignedint inlen, unsignedchar *out, unsignedint *outlen, void *wmem)
{ struct nx842_devdata *local_devdata; struct device *dev = NULL; struct nx842_workmem *workmem; struct nx842_scatterlist slin, slout; struct nx_csbcpb *csbcpb; int ret = 0; unsignedlong inbuf, outbuf; struct vio_pfo_op op = {
.done = NULL,
.handle = 0,
.timeout = 0,
}; unsignedlong start = get_tb();
inbuf = (unsignedlong)in; if (check_constraints(inbuf, &inlen, true)) return -EINVAL;
outbuf = (unsignedlong)out; if (check_constraints(outbuf, outlen, false)) return -EINVAL;
rcu_read_lock();
local_devdata = rcu_dereference(devdata); if (!local_devdata || !local_devdata->dev) {
rcu_read_unlock(); return -ENODEV;
}
dev = local_devdata->dev;
/** * nx842_pseries_decompress - Decompress data using the 842 algorithm * * Decompression provide by the NX842 coprocessor on IBM Power systems. * The input buffer is decompressed and the result is stored in the * provided output buffer. The size allocated to the output buffer is * provided by the caller of this function in @outlen. Upon return from * this function @outlen contains the length of the decompressed data. * If there is an error then @outlen will be 0 and an error will be * specified by the return code from this function. * * @in: Pointer to input buffer * @inlen: Length of input buffer * @out: Pointer to output buffer * @outlen: Length of output buffer * @wmem: ptr to buffer for working memory, size determined by * nx842_pseries_driver.workmem_size * * Returns: * 0 Success, output of length @outlen stored in the buffer at @out * -ENODEV Hardware decompression device is unavailable * -ENOMEM Unable to allocate internal buffers * -ENOSPC Output buffer is to small * -EINVAL Bad input data encountered when attempting decompress * -EIO Internal error
*/ staticint nx842_pseries_decompress(constunsignedchar *in, unsignedint inlen, unsignedchar *out, unsignedint *outlen, void *wmem)
{ struct nx842_devdata *local_devdata; struct device *dev = NULL; struct nx842_workmem *workmem; struct nx842_scatterlist slin, slout; struct nx_csbcpb *csbcpb; int ret = 0; unsignedlong inbuf, outbuf; struct vio_pfo_op op = {
.done = NULL,
.handle = 0,
.timeout = 0,
}; unsignedlong start = get_tb();
/* Ensure page alignment and size */
inbuf = (unsignedlong)in; if (check_constraints(inbuf, &inlen, true)) return -EINVAL;
outbuf = (unsignedlong)out; if (check_constraints(outbuf, outlen, false)) return -EINVAL;
rcu_read_lock();
local_devdata = rcu_dereference(devdata); if (!local_devdata || !local_devdata->dev) {
rcu_read_unlock(); return -ENODEV;
}
dev = local_devdata->dev;
/** * nx842_OF_set_defaults -- Set default (disabled) values for devdata * * @devdata: struct nx842_devdata to update * * Returns: * 0 on success * -ENOENT if @devdata ptr is NULL
*/ staticint nx842_OF_set_defaults(struct nx842_devdata *devdata)
{ if (devdata) {
devdata->max_sync_size = 0;
devdata->max_sync_sg = 0;
devdata->max_sg_len = 0; return 0;
} else return -ENOENT;
}
/** * nx842_OF_upd_status -- Check the device info from OF status prop * * The status property indicates if the accelerator is enabled. If the * device is in the OF tree it indicates that the hardware is present. * The status field indicates if the device is enabled when the status * is 'okay'. Otherwise the device driver will be disabled. * * @devdata: struct nx842_devdata to use for dev_info * @prop: struct property point containing the maxsyncop for the update * * Returns: * 0 - Device is available * -ENODEV - Device is not available
*/ staticint nx842_OF_upd_status(struct nx842_devdata *devdata, struct property *prop)
{ constchar *status = (constchar *)prop->value;
if (!strncmp(status, "okay", (size_t)prop->length)) return 0; if (!strncmp(status, "disabled", (size_t)prop->length)) return -ENODEV;
dev_info(devdata->dev, "%s: unknown status '%s'\n", __func__, status);
return -EINVAL;
}
/** * nx842_OF_upd_maxsglen -- Update the device info from OF maxsglen prop * * Definition of the 'ibm,max-sg-len' OF property: * This field indicates the maximum byte length of a scatter list * for the platform facility. It is a single cell encoded as with encode-int. * * Example: * # od -x ibm,max-sg-len * 0000000 0000 0ff0 * * In this example, the maximum byte length of a scatter list is * 0x0ff0 (4,080). * * @devdata: struct nx842_devdata to update * @prop: struct property point containing the maxsyncop for the update * * Returns: * 0 on success * -EINVAL on failure
*/ staticint nx842_OF_upd_maxsglen(struct nx842_devdata *devdata, struct property *prop) { int ret = 0; constunsignedint maxsglen = of_read_number(prop->value, 1);
if (prop->length != sizeof(maxsglen)) {
dev_err(devdata->dev, "%s: unexpected format for ibm,max-sg-len property\n", __func__);
dev_dbg(devdata->dev, "%s: ibm,max-sg-len is %d bytes long, expected %lu bytes\n", __func__,
prop->length, sizeof(maxsglen));
ret = -EINVAL;
} else {
devdata->max_sg_len = min_t(unsignedint,
maxsglen, NX842_HW_PAGE_SIZE);
}
return ret;
}
/** * nx842_OF_upd_maxsyncop -- Update the device info from OF maxsyncop prop * * Definition of the 'ibm,max-sync-cop' OF property: * Two series of cells. The first series of cells represents the maximums * that can be synchronously compressed. The second series of cells * represents the maximums that can be synchronously decompressed. * 1. The first cell in each series contains the count of the number of * data length, scatter list elements pairs that follow – each being * of the form * a. One cell data byte length * b. One cell total number of scatter list elements * * Example: * # od -x ibm,max-sync-cop * 0000000 0000 0001 0000 1000 0000 01fe 0000 0001 * 0000020 0000 1000 0000 01fe * * In this example, compression supports 0x1000 (4,096) data byte length * and 0x1fe (510) total scatter list elements. Decompression supports * 0x1000 (4,096) data byte length and 0x1f3 (510) total scatter list * elements. * * @devdata: struct nx842_devdata to update * @prop: struct property point containing the maxsyncop for the update * * Returns: * 0 on success * -EINVAL on failure
*/ staticint nx842_OF_upd_maxsyncop(struct nx842_devdata *devdata, struct property *prop) { int ret = 0; unsignedint comp_data_limit, decomp_data_limit; unsignedint comp_sg_limit, decomp_sg_limit; conststruct maxsynccop_t {
__be32 comp_elements;
__be32 comp_data_limit;
__be32 comp_sg_limit;
__be32 decomp_elements;
__be32 decomp_data_limit;
__be32 decomp_sg_limit;
} *maxsynccop;
if (prop->length != sizeof(*maxsynccop)) {
dev_err(devdata->dev, "%s: unexpected format for ibm,max-sync-cop property\n", __func__);
dev_dbg(devdata->dev, "%s: ibm,max-sync-cop is %d bytes long, expected %lu bytes\n", __func__, prop->length, sizeof(*maxsynccop));
ret = -EINVAL; goto out;
}
/* Use one limit rather than separate limits for compression and * decompression. Set a maximum for this so as not to exceed the * size that the header can support and round the value down to
* the hardware page size (4K) */
devdata->max_sync_size = min(comp_data_limit, decomp_data_limit);
if (devdata->max_sync_size < 4096) {
dev_err(devdata->dev, "%s: hardware max data size (%u) is " "less than the driver minimum, unable to use " "the hardware device\n",
__func__, devdata->max_sync_size);
ret = -EINVAL; goto out;
}
devdata->max_sync_sg = min(comp_sg_limit, decomp_sg_limit); if (devdata->max_sync_sg < 1) {
dev_err(devdata->dev, "%s: hardware max sg size (%u) is " "less than the driver minimum, unable to use " "the hardware device\n",
__func__, devdata->max_sync_sg);
ret = -EINVAL; goto out;
}
out: return ret;
}
/** * nx842_OF_upd -- Handle OF properties updates for the device. * * Set all properties from the OF tree. Optionally, a new property * can be provided by the @new_prop pointer to overwrite an existing value. * The device will remain disabled until all values are valid, this function * will return an error for updates unless all values are valid. * * @new_prop: If not NULL, this property is being updated. If NULL, update * all properties from the current values in the OF tree. * * Returns: * 0 - Success * -ENOMEM - Could not allocate memory for new devdata structure * -EINVAL - property value not found, new_prop is not a recognized * property for the device or property value is not valid. * -ENODEV - Device is not available
*/ staticint nx842_OF_upd(struct property *new_prop)
{ struct nx842_devdata *old_devdata = NULL; struct nx842_devdata *new_devdata = NULL; struct device_node *of_node = NULL; struct property *status = NULL; struct property *maxsglen = NULL; struct property *maxsyncop = NULL; int ret = 0; unsignedlong flags;
new_devdata = kzalloc(sizeof(*new_devdata), GFP_NOFS); if (!new_devdata) return -ENOMEM;
/* Set ptrs for existing properties */
status = of_find_property(of_node, "status", NULL);
maxsglen = of_find_property(of_node, "ibm,max-sg-len", NULL);
maxsyncop = of_find_property(of_node, "ibm,max-sync-cop", NULL); if (!status || !maxsglen || !maxsyncop) {
dev_err(old_devdata->dev, "%s: Could not locate device properties\n", __func__);
ret = -EINVAL; goto error_out;
}
/* * If this is a property update, there are only certain properties that * we care about. Bail if it isn't in the below list
*/ if (new_prop && (strncmp(new_prop->name, "status", new_prop->length) ||
strncmp(new_prop->name, "ibm,max-sg-len", new_prop->length) ||
strncmp(new_prop->name, "ibm,max-sync-cop", new_prop->length))) goto out;
/* Perform property updates */
ret = nx842_OF_upd_status(new_devdata, status); if (ret) goto error_out;
ret = nx842_OF_upd_maxsglen(new_devdata, maxsglen); if (ret) goto error_out;
ret = nx842_OF_upd_maxsyncop(new_devdata, maxsyncop); if (ret) goto error_out;
if (old_devdata && old_devdata->vdev != NULL) {
dev_err(&viodev->dev, "%s: Attempt to register more than one instance of the hardware\n", __func__);
ret = -1; goto error_unlock;
}
/* * Get NX capabilities from the hypervisor. * Only NXGZIP capabilities are provided by the hypersvisor right * now and these values are available to user space with sysfs.
*/ staticvoid __init nxcop_get_capabilities(void)
{ struct hv_vas_all_caps *hv_caps; struct hv_nx_cop_caps *hv_nxc;
u64 feat; int rc;
hv_caps = kmalloc(sizeof(*hv_caps), GFP_KERNEL); if (!hv_caps) return; /* * Get NX overall capabilities with feature type=0
*/
rc = h_query_vas_capabilities(H_QUERY_NX_CAPABILITIES, 0,
(u64)virt_to_phys(hv_caps)); if (!rc)
feat = be64_to_cpu(hv_caps->feat_type);
kfree(hv_caps); if (rc) return; if (!(feat & VAS_NX_GZIP_FEAT_BIT)) return;
/* * NX-GZIP feature available
*/
hv_nxc = kmalloc(sizeof(*hv_nxc), GFP_KERNEL); if (!hv_nxc) return; /* * Get capabilities for NX-GZIP feature
*/
rc = h_query_vas_capabilities(H_QUERY_NX_CAPABILITIES,
VAS_NX_GZIP_FEAT,
(u64)virt_to_phys(hv_nxc));
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.