I've been building a RTDM UART driver by using the Linux version as an example. The UART base address is supposed to be 0x80070000, and when using the linux driver there is no problem as dmesg show:
80070000.serial: ttyAPP3 at MMIO 0x80070000 (irq = 234, base_baud = 1500000) is a 80070000.serial
mxs-auart 80070000.serial: Found APPUART 3.1.0
However, when I'm using the driver I'm builing I get a different adress each time I'm loading the module (such as 0xc8df6000) and none of them are correct.
Here's the probe function I'm using:
static int rt_mxs_auart_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
of_match_device(mxs_auart_dt_ids, &pdev->dev);
int ret;
struct resource *r;
struct rtdm_device *dev;
struct rt_mxs_auart_port *s;
//allocate managed kernel memory
s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
if (!s)
return -ENOMEM;
ret = rt_serial_mxs_probe_dt(s, pdev);
if (ret < 0){
return ret;
}
if (of_id) {
pdev->id_entry = of_id->data;
s->devtype = pdev->id_entry->driver_data;
}
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r)
return -ENXIO;
//get irq line
s->irq = platform_get_irq(pdev, 0);
if (s->irq < 0)
return -ENODEV;
//base memory
s->membase = ioremap(r->start, resource_size(r));
if (IS_ERR(s->membase))
return PTR_ERR(s->membase);
/*define the rtdm_device*/
dev = &s->rtdm_dev;
dev->driver = &ida_driver;
dev->label = "xeno_ida";
dev->device_data = s;
ret = mxs_get_clks(s, pdev); //activate clocks
if (ret)
return ret;
s->uartclk = clk_get_rate(s->clk);
s->fifosize = MXS_AUART_FIFO_SIZE;
mxs_init_regs(s);
ret = rtdm_dev_register(dev); //register driver in RTDM space
if (ret)
return ret;
platform_set_drvdata(pdev, s); //add device-related data to device struct
pr_info("Probe: Successful\n");
pr_info("%s on IMX UART%d: membase=0x%p irq=%d uartclk=%d\n",
dev->name, pdev->id, s->membase, s->irq, s->uartclk);
return 0;
}
which is based on mxs-auart.c and rt_imx_uart.c.
For membase I'm using the same code as mxs-auart.c which is why I don't understand why I'm having this issue. My driver also freezes after some time when I try to rmmod it so I wonder if it is caused by this.
Would appreciate any help!
The return value of ioremap is a virtual address, not a physical one. It could be anywhere in the virtual address space.
The physical address is stored in r->start (the input of ioremap).
Related
I'm working on a device driver that needs to preform mem to mem copies via dma on a Beaglebone Black (ARM) with Linux Kernel 5.4.106. So far I've managed to successfully request a mem to mem compatible channel (and release it when I'm done), but I'm unable to perform the actual transfer.
#include <linux/module.h>
#include <linux/init.h>
#include <linux/dmaengine.h>
struct dma_chan *chan;
void *src;
void *dst;
static int __init mod_init(void)
{
dma_cap_mask_t mask;
int ret;
struct dma_async_tx_descriptor *tx = NULL;
dma_cookie_t cookie;
int *writer;
enum dma_status status;
printk("mod_init called\n");
dma_cap_zero(mask);
dma_cap_set(DMA_MEMCPY, mask);
chan = dma_request_channel(mask, NULL, NULL);
if(!chan){
printk("no mem2mem channels available");
ret = -EAGAIN;
goto fail_chan;
}
printk("requested channel");
src = kzalloc(16,GFP_KERNEL);
if(src == NULL){
ret = -ENOMEM;
goto fail_m1;
}
dst = kzalloc(16,GFP_KERNEL);
if(dst == NULL){
ret = -ENOMEM;
goto fail_m2;
}
writer = (int *)src;
*writer = 20;
tx = chan->device->device_prep_dma_memcpy(chan, virt_to_phys(dst), virt_to_phys(src), 16, DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
if (!tx) {
printk("prep error");
}
printk("slave configured");
cookie = tx->tx_submit(tx);
if (dma_submit_error(cookie)) {
printk("submit error");
}
dma_async_issue_pending(chan);
status = dma_async_is_tx_complete(chan, cookie, NULL, NULL);
if(status != DMA_COMPLETE){
printk("something went wrong");
}
printk("dst: %d, src: %d", *(int *)dst, *(int *)src);
printk("done");
return 0;
fail_m2:
kfree(src);
fail_m1:
dma_release_channel(chan);
fail_chan:
return ret;
}
static void __exit mod_exit(void)
{
printk("mod_exit called\n");
dma_release_channel(chan);
printk("dst: %d, src: %d", *(int *)dst, *(int *)src);
kfree(src);
kfree(dst);
printk("released channel");
}
module_init( mod_init );
module_exit( mod_exit );
MODULE_AUTHOR("Me");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("DMA engine test.");
This kernel module compiles without any issues and when installed does not cause any errors. Eventho the cookie returns a DMA_COMPLETE status, the value in dst stays 0 (it should become 20).
Most of the code is based on the dmatest driver, which preforms flawlessly, but my copy is missing the mark.
What could be the issue here? Am I missing a step?
Try adding GFP_DMA flag to your kzalloc() calls - the memory you allocate should be suitable for DMA transfers, that is platform-dependent.
I am writing a dummy PHY driver as a LKM. This is a platform driver
and I can't call the driver probe since it depends on the compatible string.
How can I make my driver invoke probe in my host machine, which is running
Ubuntu 18.04, kernel version - 5.3.0-40-generic. My machine is X86. I am installing this phy driver on my X86 machine.
Here is my code:
static int phy_platform_probe(struct platform_device *pdev) {
struct custom_port_phy_platform_local *lp;
int ret;
printk(KERN_ALERT "abc..phy_platform_probe..Invoked\r\n");
lp = devm_kzalloc(&pdev->dev,sizeof(struct custom_port_phy_platform_local),GFP_KERNEL);
if (!lp) {
dev_err(&(pdev->dev),"Failed to allocatate platform_local\n");
return -ENOMEM;
}
platform_set_drvdata(pdev, lp);
lp->dev = &pdev->dev;
ret = custom_port_phy_mdio_setup(lp, pdev->dev.of_node);
if (ret < 0) {
dev_err(&(pdev->dev),"Failed to setup MDIO bus\n");
return ret;
}
return 0;
}
static int phy_platform_remove(struct platform_device *pdev) {
struct custom_port_phy_platform_local *lp = platform_get_drvdata(pdev);
dev_info(&pdev->dev,"%s Enter\n",__func__);
custom_port_phy_mdio_teardown(lp);
return 0;
}
static struct phy_driver custom_phy_driver = {
.phy_id = 0x00000002,
.phy_id_mask = 0xffffffff,
.name = "custom_port_phy",
};
static struct platform_driver custom_phy_platform_driver = {
.probe = phy_platform_probe,
.remove = phy_platform_remove,
#if 1
.driver = {
.name = "custom_port_phy"
.of_match_table = port_phy_of_match,
}
#endif
};
#if 1
/* Match table for of_platform binding */
static struct of_device_id port_phy_of_match[] = {
{ .compatible = "custom,custom-port-phy", },
{},
};
#endif
static int __init phy_init(void)
{
int ret = 0;
printk(KERN_ALERT "abc >>> phy_driver_register started\r\n");
ret = phy_driver_register(&custom_phy_driver, THIS_MODULE);
printk(KERN_ALERT "abc >>> phy_driver_register END\r\n");
if(ret < 0) {
printk(KERN_ALERT "custom phy driver registration failed\r\n");
return ret;
}
ret = platform_driver_register(&custom_phy_platform_driver);
if(ret < 0) {
phy_driver_unregister(&custom_phy_driver);
printk("%s: Failed to register as Platform Driver\r\n", __func__);
return ret;
}
return ret;
}
static void __exit phy_exit(void)
{
pr_info("Goodbye phy_driver .\n");
phy_driver_unregister(&custom_phy_driver);
platform_driver_unregister(&custom_phy_platform_driver);
}
module_init(phy_init);
module_exit(phy_exit);
MODULE_LICENSE("GPL");
My code doesn't do probe since it can't find compatible flag.
How can I make it work on my host machine? I know I need dtb file. Even if
I have dtb file, how do I supply it and how to write it that way?
I am adding an IOctl call from the native OpenGL framework on an Android device such that I can log frame information in the kernel via a tracing kernel module. In my kernel module I am creating the cdev for the IOctl calls but am having the problem that my dev's default permissions are 6000 and since the user-land IOctl calls are coming from a non-root process the open call is unable to open the file decriptor required for the ioctl call.
My cdev approach is very much standard and as follows (note devnode is an attempt to fix permissions, see this).
static dev_t dev;
static struct cdev c_dev;
static struct class *cl;
static char *device_node(struct device *dev, umode_t *mode)
{
if(!mode)
return NULL;
*mode=0666;
return kasprintf(GFP_KERNEL, "%s", dev_name(dev));
}
static int IOctlInit(void)
{
int ret;
struct device *dev_ret;
if((ret = alloc_chrdev_region(&dev, FIRST_MINOR, MINOR_CNT, EGL_SYSLOGGER_NAME)))
return ret;
cdev_init(&c_dev, &syslog_EGL_fops);
if((ret = cdev_add(&c_dev, dev, MINOR_CNT)) < 0)
return ret;
if(IS_ERR( cl = class_create(THIS_MODULE, EGL_SYSLOGGER_NAME "char")))
{
cdev_del(&c_dev);
unregister_chrdev_region(dev, MINOR_CNT);
return PTR_ERR(cl);
}
cl->devnode = device_node;
if(IS_ERR(dev_ret = device_create(cl, NULL, dev, NULL, EGL_SYSLOGGER_NAME)))
{
class_destroy(cl);
cdev_del(&c_dev);
unregister_chrdev_region(dev, MINOR_CNT);
return PTR_ERR(cl);
}
return 0;
}
And similarly using a misc dev with .mode=0666 I have the same problem
static struct miscdevice misc_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = EGL_SYSLOGGER_NAME,
.fops = &syslog_EGL_fops,
/** .mode = S_IRWXUGO, */
.mode = 0666,
};
static `enter code here`int IOctlInit(void)
{
int ret;
ret = misc_register(&misc_dev);
if(ret)
printk("Unable to register EGL IOctl misc dev\n");
printk("Misc dev registered\n");
return 0;
}
Both approaches work once running chmod 666 /dev/$EGL_SYSLOGGER_NAME but I am hoping to find a solution that does not need this intervention. According to this post the misc dev approach should solve my problem but I have not had any success.
I am not sure what I have missed and would greatly appreciate some tips.
Cheers
I am developing a PCIE device driver for Openwrt, which is also a linux system. Here is a weird situation. After Initializing the driver in probe function, I can read(by ioread32) correct data (preset value:123456) from the buffer address obtained from ioremap_nocache. Then when I try to read it every 1 second in periodic timer interrupt handler, the function ioread32 will crash and the serial console presents a Data bus error. Below are code details.
// content of function my_driver_request_mem, this function is called in probe function
int my_driver_request_mem(struct gps_time *gt) {
u32 start, len;
int ret;
int bar = 0;
u32 flags;
ret = pcim_iomap_regions(gt->pdev, BIT(0), "My Driver");
if (ret) {
gt_log("Fail to request IO mem: err: %d\n", ret);
return ret;
}
// gt is a custom struct, and gt->pdev is the pci_dev struct
// obtained from probe function
start = pci_resource_start(gt->pdev, bar);
len = pci_resource_len(gt->pdev, bar);
flags = pci_resource_flags(gt->pdev, bar);
printk(KERN_ALERT "region start: 0x%x, len: %u\n", start, len);
printk(KERN_ALERT "region flags: 0x%x\n", flags);
gt->buffer = ioremap_nocache(start, len);
gt->buffer_len = len;
gt->buffer_start = start;
return 0;
}
Afte the function above is invoked, I read data through gt->buffer:
u32 d = 0;
d = ioread32(gt->buffer); // this operation does not cause fatal error
printk(KERN_ALERT "initial value is: %u", d);
By reading the console output, the ioread32 here is successful, and the right value 123456 is printed. Then I start a timer to read data multiple times
setup_timer(>->g_timer, _gps_timer_handler, gt);
mod_timer(>->g_timer, jiffies + msecs_to_jiffies(20000));
printk(KERN_ALERT "GPS_TIME: timer created.\n");
The handler function is quit simple:
void _gps_timer_handler(unsigned long data) {
struct gps_time *gt = (struct gps_time*)data;
u32 d;
d = ioread32(gt->buffer); // fatal error in this line
printk(KERN_ALERT "Value: %u\n", d);
mod_timer(>->g_timer, jiffies + msecs_to_jiffies(1000));
}
The ioread32 here will cause a fatal error here, and the error info is:
Data bus error, epc == 82db8030, ra == 8009a000
Oops[#1]
CPU: 0 PID: 853 Comm: dropbearkey Tainted: G W 4.4.14 #2
task: 82dd1900 ti:8209a000 task.ti: 8209a000
...
(bunch of numbers)
...
Status: 1100d403 KERNEL EXL IE
Cause : 8080001c (ExcCode 07)
PrId: 0001974c (MIPS 74Kc)
...
First I though this is because IO process should not be done in interrupt context, so I put ioread32 in a tasklet, and invoke that tasklet by tasklet_schedule, but it still fails.
======== Update
A. Below are my ->probe function:
static int gps_time_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
int ret = 0;
struct gps_time *gt;
u8 tmp = 0;
u32 bar_val = 0;
u8 csz = 0;
unsigned long start, end, len, flag;
int bar = 0;
if (gps_time_global_time) {
printk(KERN_ALERT "GPS_TIME: more than one device detected\n");
return -1;
}
gt = gps_time_alloc();
if (gt == NULL) {
printk(KERN_WARNING "GPS_TIME: out of memory\n");
return -ENOMEM;
}
gt->pdev = pdev;
gt->irq = pdev->irq;
ret = pcim_enable_device(pdev);
if (ret) {
printk(KERN_ALERT "GPS_TIME: Fail to enable device %d\n", ret);
goto err;
}
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret) {
printk(KERN_WARNING "GPS_TIME: 32-bit DMA not available\n");
return ret;
}
ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret) {
printk(KERN_WARNING "GPS_TIME: 32-bit DMA consistent DMA enable failed\n");
return ret;
}
my_driver_request_mem(gt);
ret = pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &tmp);
if (ret) {
printk(KERN_ALERT "GPS_TIME: Fail to read cache line size\n");
goto err;
}
if (tmp == 0) {
printk(KERN_ALERT "GPS_TIME: Write pci cache line size\n");
pci_write_config_byte(
pdev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES / sizeof(u32));
}
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8);
pci_set_master(pdev);
pci_set_drvdata(pdev, gt);
// This function is very simple. I just create timer here. The first ioread32 is also included in this function.
gps_time_init_device(gt);
ret = request_irq(pdev->irq, gps_time_isq, IRQF_SHARED, "gps_time", gt);
if (ret) {
printk(KERN_ALERT "GPS_TIME: Fail to request IRQ: %d", ret);
goto err_irq;
}
return 0;
err_region:
pci_release_regions(pdev);
err_irq:
err:
gps_time_free(gt);
return ret;
}
B. More info about the device:
This device is a self-designed chip with PCIE interface. It is built around a Altera Cyclone IV FPGA. The firmware in the chip does nothing except writing constant 123456 into its memory.
I'm new to Linux USB driver development, and I absolutely love it so far! I'm currently creating a driver for an Xbox One controller, and I have a question for you guys. In the below code, you will see that I fill an interrupt IN URB in the open function, and I would like to print the contents of the URB buffer in the xb1_int_in_callback() function. What would be the best way to do this? At the moment, I'm using printk(KERN_INFO "int_in_buffer: %s", dev->int_in_buffer), however I don't see the entire URB buffer contents printed, and get a weird string printed to dmesg.
Sorry if this is a simple question, I'm new to programming and C, so I'm still learning as I go, but I absolutely love it so far!
Code:
static void xb1_int_in_callback(struct urb *int_in_urb) {
struct xb1_controller *dev = int_in_urb->context;
printk(KERN_INFO "xb1_int_in_callback successfully called");
printk(KERN_INFO "int_in_buffer: %s", dev->int_in_buffer);
}
static int xb1_open(struct inode *inode, struct file *file) {
printk(KERN_INFO "open function called..");
struct xb1_controller *dev;
struct usb_interface *interface;
int subminor;
int retval = 0;
subminor = iminor(inode);
interface = usb_find_interface(&xb1_driver, subminor);
if(!interface) {
printk(KERN_INFO "Unable to locate interface in open
function");
retval = -ENODEV;
goto exit;
}
dev = usb_get_intfdata(interface);
if(!dev) {
printk(KERN_INFO "Unable to locate dev structure in open
function");
retval = -ENODEV;
goto exit;
}
usb_fill_int_urb(dev->int_in_urb, dev->udev, usb_rcvintpipe(dev-
>udev, dev->int_in_endpoint->bEndpointAddress),
dev->int_in_buffer, dev->int_in_endpoint-
>wMaxPacketSize, xb1_int_in_callback,
dev, dev->int_in_endpoint->bInterval);
dev->int_in_running = 1;
retval = usb_submit_urb(dev->int_in_urb, GFP_KERNEL);
if(retval) {
printk(KERN_INFO "Unable to submit int_in_urb in open
function");
dev->int_in_running = 0;
goto exit;
}
file->private_data = dev;
exit:
return retval;
}
static int xb1_probe(struct usb_interface *interface, const struct
usb_device_id *id) {
struct usb_device *udev = interface_to_usbdev(interface);
struct xb1_controller *dev = NULL;
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
int i;
int retval = -ENODEV;
if(!udev) {
printk(KERN_INFO "udev is NULL in probe function");
xb1_abort(dev);
return retval;
}
dev = kzalloc(sizeof(struct xb1_controller), GFP_KERNEL);
if(!dev) {
printk(KERN_INFO "Unable to allocate memory for dev in probe
function");
xb1_abort(dev);
return retval;
}
dev->udev = udev;
dev->interface = interface;
iface_desc = interface->cur_altsetting;
for(i=0; i<iface_desc->desc.bNumEndpoints; i++) {
endpoint = &iface_desc->endpoint[i].desc;
if(((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
USB_DIR_IN)
&& ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_INT)) {
dev->int_in_endpoint = endpoint;
}
}
if(!dev->int_in_endpoint) {
printk(KERN_INFO "Unable to locate interrupt in endpoint for
interface in probe function");
xb1_abort(dev);
return retval;
}
else {
printk(KERN_INFO "Interrupt in endpoint found!");
}
For printing a small buffers (up to 64 bytes long) use printk format:
Raw buffer as a hex string:
%*ph 00 01 02 ... 3f
%*phC 00:01:02: ... :3f
%*phD 00-01-02- ... -3f
%*phN 000102 ... 3f
For larger buffers use print_hex_dump(). Reference here.