18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Intel I/OAT DMA Linux driver 48c2ecf20Sopenharmony_ci * Copyright(c) 2004 - 2015 Intel Corporation. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/init.h> 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/dmaengine.h> 108c2ecf20Sopenharmony_ci#include <linux/pci.h> 118c2ecf20Sopenharmony_ci#include "dma.h" 128c2ecf20Sopenharmony_ci#include "registers.h" 138c2ecf20Sopenharmony_ci#include "hw.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include "../dmaengine.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistatic ssize_t cap_show(struct dma_chan *c, char *page) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci struct dma_device *dma = c->device; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci return sprintf(page, "copy%s%s%s%s%s\n", 228c2ecf20Sopenharmony_ci dma_has_cap(DMA_PQ, dma->cap_mask) ? " pq" : "", 238c2ecf20Sopenharmony_ci dma_has_cap(DMA_PQ_VAL, dma->cap_mask) ? " pq_val" : "", 248c2ecf20Sopenharmony_ci dma_has_cap(DMA_XOR, dma->cap_mask) ? " xor" : "", 258c2ecf20Sopenharmony_ci dma_has_cap(DMA_XOR_VAL, dma->cap_mask) ? " xor_val" : "", 268c2ecf20Sopenharmony_ci dma_has_cap(DMA_INTERRUPT, dma->cap_mask) ? " intr" : ""); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci} 298c2ecf20Sopenharmony_cistruct ioat_sysfs_entry ioat_cap_attr = __ATTR_RO(cap); 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic ssize_t version_show(struct dma_chan *c, char *page) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci struct dma_device *dma = c->device; 348c2ecf20Sopenharmony_ci struct ioatdma_device *ioat_dma = to_ioatdma_device(dma); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci return sprintf(page, "%d.%d\n", 378c2ecf20Sopenharmony_ci ioat_dma->version >> 4, ioat_dma->version & 0xf); 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_cistruct ioat_sysfs_entry ioat_version_attr = __ATTR_RO(version); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic ssize_t 428c2ecf20Sopenharmony_ciioat_attr_show(struct kobject *kobj, struct attribute *attr, char *page) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci struct ioat_sysfs_entry *entry; 458c2ecf20Sopenharmony_ci struct ioatdma_chan *ioat_chan; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci entry = container_of(attr, struct ioat_sysfs_entry, attr); 488c2ecf20Sopenharmony_ci ioat_chan = container_of(kobj, struct ioatdma_chan, kobj); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (!entry->show) 518c2ecf20Sopenharmony_ci return -EIO; 528c2ecf20Sopenharmony_ci return entry->show(&ioat_chan->dma_chan, page); 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic ssize_t 568c2ecf20Sopenharmony_ciioat_attr_store(struct kobject *kobj, struct attribute *attr, 578c2ecf20Sopenharmony_ciconst char *page, size_t count) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci struct ioat_sysfs_entry *entry; 608c2ecf20Sopenharmony_ci struct ioatdma_chan *ioat_chan; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci entry = container_of(attr, struct ioat_sysfs_entry, attr); 638c2ecf20Sopenharmony_ci ioat_chan = container_of(kobj, struct ioatdma_chan, kobj); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci if (!entry->store) 668c2ecf20Sopenharmony_ci return -EIO; 678c2ecf20Sopenharmony_ci return entry->store(&ioat_chan->dma_chan, page, count); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ciconst struct sysfs_ops ioat_sysfs_ops = { 718c2ecf20Sopenharmony_ci .show = ioat_attr_show, 728c2ecf20Sopenharmony_ci .store = ioat_attr_store, 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_civoid ioat_kobject_add(struct ioatdma_device *ioat_dma, struct kobj_type *type) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci struct dma_device *dma = &ioat_dma->dma_dev; 788c2ecf20Sopenharmony_ci struct dma_chan *c; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci list_for_each_entry(c, &dma->channels, device_node) { 818c2ecf20Sopenharmony_ci struct ioatdma_chan *ioat_chan = to_ioat_chan(c); 828c2ecf20Sopenharmony_ci struct kobject *parent = &c->dev->device.kobj; 838c2ecf20Sopenharmony_ci int err; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci err = kobject_init_and_add(&ioat_chan->kobj, type, 868c2ecf20Sopenharmony_ci parent, "quickdata"); 878c2ecf20Sopenharmony_ci if (err) { 888c2ecf20Sopenharmony_ci dev_warn(to_dev(ioat_chan), 898c2ecf20Sopenharmony_ci "sysfs init error (%d), continuing...\n", err); 908c2ecf20Sopenharmony_ci kobject_put(&ioat_chan->kobj); 918c2ecf20Sopenharmony_ci set_bit(IOAT_KOBJ_INIT_FAIL, &ioat_chan->state); 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_civoid ioat_kobject_del(struct ioatdma_device *ioat_dma) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct dma_device *dma = &ioat_dma->dma_dev; 998c2ecf20Sopenharmony_ci struct dma_chan *c; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci list_for_each_entry(c, &dma->channels, device_node) { 1028c2ecf20Sopenharmony_ci struct ioatdma_chan *ioat_chan = to_ioat_chan(c); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (!test_bit(IOAT_KOBJ_INIT_FAIL, &ioat_chan->state)) { 1058c2ecf20Sopenharmony_ci kobject_del(&ioat_chan->kobj); 1068c2ecf20Sopenharmony_ci kobject_put(&ioat_chan->kobj); 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic ssize_t ring_size_show(struct dma_chan *c, char *page) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci struct ioatdma_chan *ioat_chan = to_ioat_chan(c); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci return sprintf(page, "%d\n", (1 << ioat_chan->alloc_order) & ~1); 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_cistatic struct ioat_sysfs_entry ring_size_attr = __ATTR_RO(ring_size); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic ssize_t ring_active_show(struct dma_chan *c, char *page) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci struct ioatdma_chan *ioat_chan = to_ioat_chan(c); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* ...taken outside the lock, no need to be precise */ 1248c2ecf20Sopenharmony_ci return sprintf(page, "%d\n", ioat_ring_active(ioat_chan)); 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_cistatic struct ioat_sysfs_entry ring_active_attr = __ATTR_RO(ring_active); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic ssize_t intr_coalesce_show(struct dma_chan *c, char *page) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci struct ioatdma_chan *ioat_chan = to_ioat_chan(c); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci return sprintf(page, "%d\n", ioat_chan->intr_coalesce); 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic ssize_t intr_coalesce_store(struct dma_chan *c, const char *page, 1368c2ecf20Sopenharmony_cisize_t count) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci int intr_coalesce = 0; 1398c2ecf20Sopenharmony_ci struct ioatdma_chan *ioat_chan = to_ioat_chan(c); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (sscanf(page, "%du", &intr_coalesce) != -1) { 1428c2ecf20Sopenharmony_ci if ((intr_coalesce < 0) || 1438c2ecf20Sopenharmony_ci (intr_coalesce > IOAT_INTRDELAY_MASK)) 1448c2ecf20Sopenharmony_ci return -EINVAL; 1458c2ecf20Sopenharmony_ci ioat_chan->intr_coalesce = intr_coalesce; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci return count; 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic struct ioat_sysfs_entry intr_coalesce_attr = __ATTR_RW(intr_coalesce); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic struct attribute *ioat_attrs[] = { 1548c2ecf20Sopenharmony_ci &ring_size_attr.attr, 1558c2ecf20Sopenharmony_ci &ring_active_attr.attr, 1568c2ecf20Sopenharmony_ci &ioat_cap_attr.attr, 1578c2ecf20Sopenharmony_ci &ioat_version_attr.attr, 1588c2ecf20Sopenharmony_ci &intr_coalesce_attr.attr, 1598c2ecf20Sopenharmony_ci NULL, 1608c2ecf20Sopenharmony_ci}; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistruct kobj_type ioat_ktype = { 1638c2ecf20Sopenharmony_ci .sysfs_ops = &ioat_sysfs_ops, 1648c2ecf20Sopenharmony_ci .default_attrs = ioat_attrs, 1658c2ecf20Sopenharmony_ci}; 166