mirror of
https://github.com/fpganinja/taxi.git
synced 2026-01-18 01:30:36 -08:00
cndm: Implement mmap and ioctl
Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
@@ -45,8 +45,9 @@ struct cndm_dev {
|
||||
|
||||
struct net_device *ndev[32];
|
||||
|
||||
void __iomem *bar;
|
||||
resource_size_t bar_len;
|
||||
resource_size_t hw_regs_size;
|
||||
phys_addr_t hw_regs_phys;
|
||||
void __iomem *hw_addr;
|
||||
|
||||
u32 port_count;
|
||||
u32 port_offset;
|
||||
|
||||
@@ -9,6 +9,7 @@ Authors:
|
||||
*/
|
||||
|
||||
#include "cndm.h"
|
||||
#include "cndm_ioctl.h"
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
@@ -28,8 +29,108 @@ static int cndm_release(struct inode *inode, struct file *file)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cndm_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
{
|
||||
struct miscdevice *miscdev = file->private_data;
|
||||
struct cndm_dev *cdev = container_of(miscdev, struct cndm_dev, misc_dev);
|
||||
int index;
|
||||
u64 pgoff, req_len, req_start;
|
||||
|
||||
index = vma->vm_pgoff >> (40 - PAGE_SHIFT);
|
||||
req_len = vma->vm_end - vma->vm_start;
|
||||
pgoff = vma->vm_pgoff & ((1U << (40 - PAGE_SHIFT)) - 1);
|
||||
req_start = pgoff << PAGE_SHIFT;
|
||||
|
||||
if (vma->vm_end < vma->vm_start)
|
||||
return -EINVAL;
|
||||
|
||||
if ((vma->vm_flags & VM_SHARED) == 0)
|
||||
return -EINVAL;
|
||||
|
||||
switch (index) {
|
||||
case 0:
|
||||
if (req_start + req_len > cdev->hw_regs_size)
|
||||
return -EINVAL;
|
||||
|
||||
return io_remap_pfn_range(vma, vma->vm_start,
|
||||
(cdev->hw_regs_phys >> PAGE_SHIFT) + pgoff,
|
||||
req_len, pgprot_noncached(vma->vm_page_prot));
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static long cndm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct miscdevice *miscdev = file->private_data;
|
||||
struct cndm_dev *cdev = container_of(miscdev, struct cndm_dev, misc_dev);
|
||||
size_t minsz;
|
||||
|
||||
if (cmd == CNDM_IOCTL_GET_API_VERSION) {
|
||||
// Get API version
|
||||
return CNDM_IOCTL_API_VERSION;
|
||||
} else if (cmd == CNDM_IOCTL_GET_DEVICE_INFO) {
|
||||
// Get device information
|
||||
struct cndm_ioctl_device_info info;
|
||||
|
||||
minsz = offsetofend(struct cndm_ioctl_device_info, num_irqs);
|
||||
|
||||
if (copy_from_user(&info, (void __user *)arg, minsz))
|
||||
return -EFAULT;
|
||||
|
||||
if (info.argsz < minsz)
|
||||
return -EINVAL;
|
||||
|
||||
info.flags = 0;
|
||||
info.num_regions = 1;
|
||||
info.num_irqs = 0;
|
||||
|
||||
return copy_to_user((void __user *)arg, &info, minsz) ? -EFAULT : 0;
|
||||
} else if (cmd == CNDM_IOCTL_GET_REGION_INFO) {
|
||||
// Get region information
|
||||
struct cndm_ioctl_region_info info;
|
||||
|
||||
minsz = offsetofend(struct cndm_ioctl_region_info, name);
|
||||
|
||||
if (copy_from_user(&info, (void __user *)arg, minsz))
|
||||
return -EFAULT;
|
||||
|
||||
if (info.argsz < minsz)
|
||||
return -EINVAL;
|
||||
|
||||
info.flags = 0;
|
||||
info.type = CNDM_REGION_TYPE_UNIMPLEMENTED;
|
||||
info.next = 0;
|
||||
info.child = 0;
|
||||
info.size = 0;
|
||||
info.offset = ((u64)info.index) << 40;
|
||||
info.name[0] = 0;
|
||||
|
||||
switch (info.index) {
|
||||
case 0:
|
||||
info.type = CNDM_REGION_TYPE_NIC_CTRL;
|
||||
info.next = 0;
|
||||
info.child = 0;
|
||||
info.size = cdev->hw_regs_size;
|
||||
info.offset = ((u64)info.index) << 40;
|
||||
strscpy(info.name, "ctrl", sizeof(info.name));
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return copy_to_user((void __user *)arg, &info, minsz) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
const struct file_operations cndm_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = cndm_open,
|
||||
.release = cndm_release,
|
||||
.mmap = cndm_mmap,
|
||||
.unlocked_ioctl = cndm_ioctl,
|
||||
};
|
||||
|
||||
63
src/cndm/modules/cndm/cndm_ioctl.h
Normal file
63
src/cndm/modules/cndm/cndm_ioctl.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/* SPDX-License-Identifier: GPL */
|
||||
/*
|
||||
|
||||
Copyright (c) 2025 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
#ifndef CNDM_IOCTL_H
|
||||
#define CNDM_IOCTL_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#define CNDM_IOCTL_API_VERSION 0
|
||||
|
||||
#define CNDM_IOCTL_TYPE 0x63
|
||||
#define CNDM_IOCTL_BASE 0xC0
|
||||
|
||||
enum {
|
||||
CNDM_REGION_TYPE_UNIMPLEMENTED = 0x00000000,
|
||||
CNDM_REGION_TYPE_CTRL = 0x00001000,
|
||||
CNDM_REGION_TYPE_NIC_CTRL = 0x00001001,
|
||||
CNDM_REGION_TYPE_APP_CTRL = 0x00001002,
|
||||
};
|
||||
|
||||
// get API version
|
||||
#define CNDM_IOCTL_GET_API_VERSION _IO(CNDM_IOCTL_TYPE, CNDM_IOCTL_BASE + 0)
|
||||
|
||||
// get device information
|
||||
struct cndm_ioctl_device_info {
|
||||
__u32 argsz;
|
||||
__u32 flags;
|
||||
__u32 fw_id;
|
||||
__u32 fw_ver;
|
||||
__u32 board_id;
|
||||
__u32 board_ver;
|
||||
__u32 build_date;
|
||||
__u32 git_hash;
|
||||
__u32 rel_info;
|
||||
__u32 num_regions;
|
||||
__u32 num_irqs;
|
||||
};
|
||||
|
||||
#define CNDM_IOCTL_GET_DEVICE_INFO _IO(CNDM_IOCTL_TYPE, CNDM_IOCTL_BASE + 1)
|
||||
|
||||
// get region information
|
||||
struct cndm_ioctl_region_info {
|
||||
__u32 argsz;
|
||||
__u32 flags;
|
||||
__u32 index;
|
||||
__u32 type;
|
||||
__u32 next;
|
||||
__u32 child;
|
||||
__u32 size;
|
||||
__u64 offset;
|
||||
__u8 name[32];
|
||||
};
|
||||
|
||||
#define CNDM_IOCTL_GET_REGION_INFO _IO(CNDM_IOCTL_TYPE, CNDM_IOCTL_BASE + 2)
|
||||
|
||||
#endif
|
||||
@@ -52,9 +52,9 @@ static int cndm_common_probe(struct cndm_dev *cdev)
|
||||
devlink_register(devlink, dev);
|
||||
#endif
|
||||
|
||||
cdev->port_count = ioread32(cdev->bar + 0x0100);
|
||||
cdev->port_offset = ioread32(cdev->bar + 0x0104);
|
||||
cdev->port_stride = ioread32(cdev->bar + 0x0108);
|
||||
cdev->port_count = ioread32(cdev->hw_addr + 0x0100);
|
||||
cdev->port_offset = ioread32(cdev->hw_addr + 0x0104);
|
||||
cdev->port_stride = ioread32(cdev->hw_addr + 0x0108);
|
||||
|
||||
dev_info(dev, "Port count: %d", cdev->port_count);
|
||||
dev_info(dev, "Port offset: 0x%x", cdev->port_offset);
|
||||
@@ -63,7 +63,7 @@ static int cndm_common_probe(struct cndm_dev *cdev)
|
||||
for (k = 0; k < cdev->port_count; k++) {
|
||||
struct net_device *ndev;
|
||||
|
||||
ndev = cndm_create_netdev(cdev, k, cdev->bar + cdev->port_offset + (cdev->port_stride*k));
|
||||
ndev = cndm_create_netdev(cdev, k, cdev->hw_addr + cdev->port_offset + (cdev->port_stride*k));
|
||||
if (IS_ERR_OR_NULL(ndev)) {
|
||||
ret = PTR_ERR(ndev);
|
||||
goto fail_netdev;
|
||||
@@ -155,17 +155,18 @@ static int cndm_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
goto fail_regions;
|
||||
}
|
||||
|
||||
cdev->bar_len = pci_resource_len(pdev, 0);
|
||||
cdev->hw_regs_size = pci_resource_len(pdev, 0);
|
||||
cdev->hw_regs_phys = pci_resource_start(pdev, 0);
|
||||
|
||||
dev_info(dev, "BAR size: %llu", cdev->bar_len);
|
||||
cdev->bar = pci_ioremap_bar(pdev, 0);
|
||||
if (!cdev->bar) {
|
||||
dev_info(dev, "Control BAR size: %llu", cdev->hw_regs_size);
|
||||
cdev->hw_addr = pci_ioremap_bar(pdev, 0);
|
||||
if (!cdev->hw_addr) {
|
||||
ret = -ENOMEM;
|
||||
dev_err(dev, "Failed to map BAR 0");
|
||||
dev_err(dev, "Failed to map control BAR");
|
||||
goto fail_map_bars;
|
||||
}
|
||||
|
||||
if (ioread32(cdev->bar + 0x0000) == 0xffffffff) {
|
||||
if (ioread32(cdev->hw_addr + 0x0000) == 0xffffffff) {
|
||||
ret = -EIO;
|
||||
dev_err(dev, "Device needs to be reset");
|
||||
goto fail_map_bars;
|
||||
@@ -187,8 +188,8 @@ fail_common:
|
||||
cndm_irq_deinit_pcie(cdev);
|
||||
fail_init_irq:
|
||||
fail_map_bars:
|
||||
if (cdev->bar)
|
||||
pci_iounmap(pdev, cdev->bar);
|
||||
if (cdev->hw_addr)
|
||||
pci_iounmap(pdev, cdev->hw_addr);
|
||||
pci_release_regions(pdev);
|
||||
fail_regions:
|
||||
pci_clear_master(pdev);
|
||||
@@ -211,8 +212,8 @@ static void cndm_pci_remove(struct pci_dev *pdev)
|
||||
cndm_common_remove(cdev);
|
||||
|
||||
cndm_irq_deinit_pcie(cdev);
|
||||
if (cdev->bar)
|
||||
pci_iounmap(pdev, cdev->bar);
|
||||
if (cdev->hw_addr)
|
||||
pci_iounmap(pdev, cdev->hw_addr);
|
||||
pci_release_regions(pdev);
|
||||
pci_clear_master(pdev);
|
||||
pci_disable_device(pdev);
|
||||
|
||||
Reference in New Issue
Block a user