Что нужно сделать в ядре Linux для инициализации коммутатора Broadcom L2 через PCI-E?

У меня есть специальная плата с Armada 370 SoC, в которой коммутатор Broadcom L2 теперь добавляется через сокет PCI-E к Soc.
Доска работает на Linux. Я хочу просто инициализировать регистры переключателя L2.
Мне просто нужен очень минимальный доступ, чтобы я мог получить доступ к регистрам коммутатора L2 (используя программу, которая использует /dev/mem - у меня есть приложение).
Я новичок, и я хотел бы знать, что нужно сделать в драйверах PCI-E, menuconfig и т. Д.
Я был бы счастлив, если бы кто-то мог указать на ресурс, который объясняет все это с нуля, потому что я хочу узнать больше. Смогу ли я получить доступ к регистрам, если правильно выполню отображение памяти? Нужно ли делать что-то еще?

1 ответ

Решение

Это должно помочь вам. Он устанавливает BAR0 для доступа. Все, что вам нужно сделать, это выяснить, как программное обеспечение должно обращаться к драйверу, и реализовать эти обработчики: чтение / запись / открытие / закрытие /ioctl и т. Д.

#include <linux/cdev.h>
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ioctl.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/pci.h>
#include <linux/tty.h>
#include <linux/version.h>

void error_msg (const char *msg, ...);  /* provide by calling possibly kprintf() */

static dev_t        dev_num;        /* major/minor device numbers */
static struct cdev  c_dev, pci_dev;     /* character device structure */
static const char   DEVICE_NAME[] = "mydevice"; /* name for /dev/... */

static unsigned long        bar0_len;
static unsigned char __iomem    *bar0_mem;

static struct file_operations mydevice_fops = {
    .owner      = THIS_MODULE,
//  .open       = (function to handle open),
//  .read       = (function to handle read),
//  .write      = (function to handle write),
//  .close      = (function to handle close),
//  .unlocked_ioctl = (function to handle ioctl),
};

static int mydevice_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
{
    int     ret;
    char        name[20];
    dev_t       unit_num;
    struct device   *dev_p;

    ret = pci_enable_device (dev);
    if (ret)
    {
        error_msg ("error %d enabling device");
        return ret;
    }
    bar0_len = pci_resource_len (dev, 0);
    bar0_mem = pci_iomap (dev, 0, bar0_len);
    if (!bar0_len  ||  !bar0_mem)       /* device not there */
    {
        error_msg ("device bar0 missing");
        return -1;
    }
    snprintf (name, sizeof name, "%s%d", DEVICE_NAME, 1);  /* create device name */
    unit_num = MKDEV(MAJOR(dev_num), 1);
    dev_p = device_create (NULL, NULL, unit_num, NULL, name);
    if (IS_ERR(dev_p))
    {
        error_msg ("error creating pci device %s", name);
        return -1;
    }
    cdev_init (&pci_dev, &mydevice_fops);
    mydevice_fops.owner = THIS_MODULE;
    ret = cdev_add (&pci_dev, unit_num, 1);
    if (ret < 0)
    {
        error_msg ("error adding pci device");
        device_destroy (NULL, unit_num);
        return ret;
    }

    pci_set_master (dev);
    return 0;
}

static void mydevice_pci_remove (struct pci_dev *dev)
{
    cdev_del (&c_dev);
    device_destroy (NULL, dev_num);
    pci_iounmap (dev, bar0_mem);
    pci_disable_device (dev);
}


static struct pci_device_id mydevice_ids[] = {
{
    0xabcd,     /* vendor/manufacturer ID */
    0x1234,     /* device/vendor device ID */
    PCI_ANY_ID, /* subvendor:  don't care */
    PCI_ANY_ID, /* subdevice:  don't care */
    0,      /* class:  don't care */
    0,      /* class_mask:  don't care */
    0,      /* ulong_t driver_data:  private driver data */
    },

    {}      /* end of pci device IDs */
};

static struct pci_driver mydriver_ops = {
    .name       = DEVICE_NAME,
    .id_table   = mydevice_ids,
    .probe      = mydevice_pci_probe,
    .remove     = mydevice_pci_remove,
    /*
     * For pci bus error recovery, see
     * https://www.kernel.org/doc/Documentation/PCI/pcieaer-howto.txt
     */
};

static struct file_operations mydriver_fops = {
    .owner = THIS_MODULE,
};


static int __init mydriver_init (void)
{
    struct device  *mydriver_device;

    int ret = alloc_chrdev_region (&dev_num, 0, 1, DEVICE_NAME);
    if (ret)
    {
        error_msg ("unable to allocate major/minor device number");
        return ret;
    }

    mydriver_device = device_create (NULL, NULL, dev_num, NULL, DEVICE_NAME);
    if (IS_ERR(mydriver_device))
    {
        error_msg ("error creating device");
        unregister_chrdev_region (dev_num, 1);
        return -ENODEV;
    }

    cdev_init (&c_dev, &mydevice_fops);
    c_dev.owner = THIS_MODULE;
    ret = cdev_add (&c_dev, dev_num, 1);
    if (ret < 0)
    {
        error_msg ("error adding device");
        device_destroy (NULL, dev_num);
        unregister_chrdev_region (dev_num, 1);
        return ret;
    }

    ret = pci_register_driver (&mydriver_ops);  // this is key to PCI devices
    if (ret < 0)
    {
        error_msg ("error %d from pci_register_driver", ret);
        cdev_del (&c_dev);
        device_destroy (NULL, dev_num);
        unregister_chrdev_region (dev_num, 1);
        return ret;
    }
    return 0;
}

static void __exit mydriver_exit (void)
{
    device_destroy (NULL, dev_num);
    unregister_chrdev (MAJOR(dev_num), DEVICE_NAME);
    unregister_chrdev_region (dev_num, 1);
}

module_init(mydriver_init);
module_exit(mydriver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your name <youremail@example.com>");
Другие вопросы по тегам