Что нужно сделать в ядре 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>");