This version is much much better.
On Sun, Jul 15, 2018 at 12:34:28PM -0400, Jacob Feder wrote:
> +static ssize_t sysfs_write(struct device *dev, const char *buf,
> + size_t count, unsigned int addr_offset)
> +{
> + struct axis_fifo *fifo = dev_get_drvdata(dev);
> + unsigned long tmp;
> +
> + if (kstrtoul(buf, 0, &tmp))
> + return -EINVAL;
It's better to preserve the error code from kstrtoul(). I wouldn't
comment on this except there are a bunch of places which need to
preserve the error code.
> +
> + iowrite32(tmp, fifo->base_addr + addr_offset);
> +
> + return count;
> +}
> +
> +static ssize_t sysfs_read(struct device *dev, char *buf,
> + unsigned int addr_offset)
> +{
> + struct axis_fifo *fifo = dev_get_drvdata(dev);
> + unsigned int read_val;
> + unsigned int strlen;
> + char tmp[32];
> +
> + read_val = ioread32(fifo->base_addr + addr_offset);
> +
> + strlen = snprintf(tmp, 32, "0x%08x\n", read_val);
> + if (strlen < 0)
> + return -EINVAL;
Kernel snprintf() won't ever return error codes, so this check is not
required... Just delete it. Or at least preserve the error code.
> +
> + memcpy(buf, tmp, strlen);
> +
> + return strlen;
> +}
> +
> +static void reset_ip_core(struct axis_fifo *fifo)
> +{
> + iowrite32(XLLF_SRR_RESET_MASK,
> + fifo->base_addr + XLLF_SRR_OFFSET);
> + iowrite32(XLLF_TDFR_RESET_MASK,
> + fifo->base_addr + XLLF_TDFR_OFFSET);
> + iowrite32(XLLF_RDFR_RESET_MASK,
> + fifo->base_addr + XLLF_RDFR_OFFSET);
These can fit in 80 characters now.
iowrite32(XLLF_RDFR_RESET_MASK, fifo->base_addr + XLLF_RDFR_OFFSET);
> + iowrite32(XLLF_INT_TC_MASK | XLLF_INT_RC_MASK | XLLF_INT_RPURE_MASK |
> + XLLF_INT_RPORE_MASK | XLLF_INT_RPUE_MASK |
> + XLLF_INT_TPOE_MASK | XLLF_INT_TSE_MASK,
> + fifo->base_addr + XLLF_IER_OFFSET);
> + iowrite32(XLLF_INT_ALL_MASK,
> + fifo->base_addr + XLLF_ISR_OFFSET);
> +}
> +
> +/* reads a single packet from the fifo as dictated by the tlast signal */
> +static ssize_t axis_fifo_read(struct file *f, char __user *buf,
> + size_t len, loff_t *off)
> +{
> + struct axis_fifo *fifo = (struct axis_fifo *)f->private_data;
> + unsigned int bytes_available;
> + unsigned int words_available;
> + unsigned int copied;
> + unsigned int copy;
> + unsigned int i;
> + int ret;
> + u32 tmp_buf[READ_BUF_SIZE];
> +
> + if (fifo->read_flags & O_NONBLOCK) {
> + /* opened in non-blocking mode
> + * return if there are no packets available
> + */
> + if (!ioread32(fifo->base_addr + XLLF_RDFO_OFFSET))
> + return -EAGAIN;
> + } else {
> + /* opened in blocking mode
> + * wait for a packet available interrupt (or timeout)
> + * if nothing is currently available
> + */
> + spin_lock_irq(&fifo->read_queue_lock);
> + if (read_timeout < 0) {
> + ret = wait_event_interruptible_lock_irq_timeout(
> + fifo->read_queue,
> + ioread32(fifo->base_addr + XLLF_RDFO_OFFSET),
> + fifo->read_queue_lock, MAX_SCHEDULE_TIMEOUT);
> + } else {
> + ret = wait_event_interruptible_lock_irq_timeout(
> + fifo->read_queue,
> + ioread32(fifo->base_addr + XLLF_RDFO_OFFSET),
> + fifo->read_queue_lock,
> + msecs_to_jiffies(read_timeout));
> + }
I'm not a huge fan of ternaries but they would help here:
ret = wait_event_interruptible_lock_irq_timeout(
fifo->read_queue,
ioread32(fifo->base_addr + XLLF_RDFO_OFFSET),
fifo->read_queue_lock,
(read_timeout >= 0) ? msecs_to_jiffies(read_timeout) :
MAX_SCHEDULE_TIMEOUT);
> + spin_unlock_irq(&fifo->read_queue_lock);
> +
> + if (ret == 0) {
> + /* timeout occurred */
> + dev_dbg(fifo->dt_device, "read timeout");
> + return -EAGAIN;
> + } else if (ret == -ERESTARTSYS) {
> + /* signal received */
> + return -ERESTARTSYS;
> + } else if (ret < 0) {
> + dev_err(fifo->dt_device,
> "wait_event_interruptible_timeout() error in read (ret=%i)\n",
> + ret);
> + return ret;
> + }
> + }
> +
> + bytes_available = ioread32(fifo->base_addr + XLLF_RLR_OFFSET);
> + if (!bytes_available) {
> + dev_err(fifo->dt_device, "received a packet of length 0 - fifo
> core will be reset\n");
> + reset_ip_core(fifo);
> + return -EIO;
> + }
> +
> + if (bytes_available > len) {
> + dev_err(fifo->dt_device, "user read buffer too small (available
> bytes=%u user buffer bytes=%u) - fifo core will be reset\n",
> + bytes_available, len);
> + reset_ip_core(fifo);
> + return -EINVAL;
> + }
> +
> + if (bytes_available % sizeof(u32)) {
> + /* this probably can't happen unless IP
> + * registers were previously mishandled
> + */
> + dev_err(fifo->dt_device, "received a packet that isn't
> word-aligned - fifo core will be reset\n");
> + reset_ip_core(fifo);
> + return -EIO;
> + }
> +
> + words_available = bytes_available / sizeof(u32);
> +
> + /* read data into an intermediate buffer, copying the contents
> + * to userspace when the buffer is full
> + */
> + copied = 0;
> + while (words_available > 0) {
> + copy = min(words_available, READ_BUF_SIZE);
> +
> + for (i = 0; i < copy; i++) {
> + tmp_buf[i] = ioread32(fifo->base_addr +
> + XLLF_RDFD_OFFSET);
> + }
> +
> + if (copy_to_user(buf + copied * sizeof(u32), tmp_buf,
> + copy * sizeof(u32))) {
> + reset_ip_core(fifo);
> + return -EFAULT;
> + }
> +
> + copied += copy;
> + words_available -= copy;
> + }
> +
> + return bytes_available;
> +}
> +
> +static ssize_t axis_fifo_write(struct file *f, const char __user *buf,
> + size_t len, loff_t *off)
> +{
> + struct axis_fifo *fifo = (struct axis_fifo *)f->private_data;
> + unsigned int words_to_write;
> + unsigned int copied;
> + unsigned int copy;
> + unsigned int i;
> + int ret;
> + u32 tmp_buf[WRITE_BUF_SIZE];
> +
> + if (len % sizeof(u32)) {
> + dev_err(fifo->dt_device,
> + "tried to send a packet that isn't word-aligned\n");
> + return -EINVAL;
> + }
> +
> + words_to_write = len / sizeof(u32);
> +
> + if (!words_to_write) {
> + dev_err(fifo->dt_device,
> + "tried to send a packet of length 0\n");
> + return -EINVAL;
> + }
> +
> + if (words_to_write > fifo->tx_fifo_depth) {
> + dev_err(fifo->dt_device, "tried to write more words [%u] than
> slots in the fifo buffer [%u]\n",
> + words_to_write, fifo->tx_fifo_depth);
> + return -EINVAL;
> + }
> +
> + if (fifo->write_flags & O_NONBLOCK) {
> + /* opened in non-blocking mode
> + * return if there is not enough room available in the fifo
> + */
> + if (words_to_write > ioread32(fifo->base_addr +
> + XLLF_TDFV_OFFSET)) {
> + return -EAGAIN;
> + }
> + } else {
> + /* opened in blocking mode */
> +
> + /* wait for an interrupt (or timeout) if there isn't
> + * currently enough room in the fifo
> + */
> + spin_lock_irq(&fifo->write_queue_lock);
> + if (write_timeout < 0) {
> + ret = wait_event_interruptible_lock_irq_timeout(
> + fifo->write_queue,
> + ioread32(fifo->base_addr +
> + XLLF_TDFV_OFFSET) >=
> + words_to_write,
> + fifo->write_queue_lock,
> + MAX_SCHEDULE_TIMEOUT);
> + } else {
> + ret = wait_event_interruptible_lock_irq_timeout(
> + fifo->write_queue,
> + ioread32(fifo->base_addr +
> + XLLF_TDFV_OFFSET) >=
> + words_to_write,
> + fifo->write_queue_lock,
> + msecs_to_jiffies(write_timeout));
> + }
ret = wait_event_interruptible_lock_irq_timeout(
fifo->write_queue,
ioread32(fifo->base_addr + XLLF_TDFV_OFFSET)
>= words_to_write,
fifo->write_queue_lock,
(write_timeout < 0) ? MAX_SCHEDULE_TIMEOUT :
msecs_to_jiffies(write_timeout));
> + spin_unlock_irq(&fifo->write_queue_lock);
> +
> + if (ret == 0) {
> + /* timeout occurred */
> + dev_dbg(fifo->dt_device, "write timeout\n");
> + return -EAGAIN;
> + } else if (ret == -ERESTARTSYS) {
> + /* signal received */
> + return -ERESTARTSYS;
> + } else if (ret < 0) {
> + /* unknown error */
> + dev_err(fifo->dt_device,
> + "wait_event_interruptible_timeout() error in
> write (ret=%i)\n",
> + ret);
> + return ret;
> + }
> + }
> +
> + /* write data from an intermediate buffer into the fifo IP, refilling
> + * the buffer with userspace data as needed
> + */
> + copied = 0;
> + while (words_to_write > 0) {
> + copy = min(words_to_write, WRITE_BUF_SIZE);
> +
> + if (copy_from_user(tmp_buf, buf + copied * sizeof(u32),
> + copy * sizeof(u32))) {
> + reset_ip_core(fifo);
> + return -EFAULT;
> + }
> +
> + for (i = 0; i < copy; i++)
> + iowrite32(tmp_buf[i], fifo->base_addr +
> + XLLF_TDFD_OFFSET);
> +
> + copied += copy;
> + words_to_write -= copy;
> + }
> +
> + /* write packet size to fifo */
> + iowrite32(copied * sizeof(u32), fifo->base_addr + XLLF_TLR_OFFSET);
> +
> + return (ssize_t)copied * sizeof(u32);
> +}
> +
> +/* read named property from the device tree */
> +static int get_dts_property(struct axis_fifo *fifo,
> + char *name, unsigned int *var)
> +{
> + if (of_property_read_u32(fifo->dt_device->of_node,
> + name, var) < 0) {
> + dev_err(fifo->dt_device,
> + "couldn't read IP dts property '%s'", name);
> + return -1;
Preserve the error code. Plus it looks nicer:
rc = of_property_read_u32(fifo->dt_device->of_node, name, var);
if (rc) {
dev_err(fifo->dt_device, "couldn't read IP dts property '%s'",
name);
return rc;
}
> + }
> + dev_dbg(fifo->dt_device, "dts property '%s' = %u\n",
> + name, *var);
> +
> + return 0;
> +}
> +
> +static int axis_fifo_probe(struct platform_device *pdev)
> +{
> + struct resource *r_irq; /* interrupt resources */
> + struct resource *r_mem; /* IO mem resources */
> + struct device *dev = &pdev->dev; /* OS device (from device tree) */
> + struct axis_fifo *fifo = NULL;
> +
> + char device_name[32];
> +
> + int rc = 0; /* error return value */
> +
> + /* IP properties from device tree */
> + unsigned int rxd_tdata_width;
> + unsigned int txc_tdata_width;
> + unsigned int txd_tdata_width;
> + unsigned int tdest_width;
> + unsigned int tid_width;
> + unsigned int tuser_width;
> + unsigned int data_interface_type;
> + unsigned int has_tdest;
> + unsigned int has_tid;
> + unsigned int has_tkeep;
> + unsigned int has_tstrb;
> + unsigned int has_tuser;
> + unsigned int rx_fifo_depth;
> + unsigned int rx_programmable_empty_threshold;
> + unsigned int rx_programmable_full_threshold;
> + unsigned int axi_id_width;
> + unsigned int axi4_data_width;
> + unsigned int select_xpm;
> + unsigned int tx_fifo_depth;
> + unsigned int tx_programmable_empty_threshold;
> + unsigned int tx_programmable_full_threshold;
> + unsigned int use_rx_cut_through;
> + unsigned int use_rx_data;
> + unsigned int use_tx_control;
> + unsigned int use_tx_cut_through;
> + unsigned int use_tx_data;
> +
> + /* ----------------------------
> + * init wrapper device
> + * ----------------------------
> + */
> +
> + /* allocate device wrapper memory */
> + fifo = devm_kmalloc(dev, sizeof(*fifo), GFP_KERNEL);
> + if (!fifo)
> + return -ENOMEM;
> +
> + dev_set_drvdata(dev, fifo);
> + fifo->dt_device = dev;
> +
> + init_waitqueue_head(&fifo->read_queue);
> + init_waitqueue_head(&fifo->write_queue);
> +
> + dev_dbg(fifo->dt_device, "initialized queues\n");
This print doesn't tell you anything except that the function was
called. Just remove it and use ftrace.
> +
> + spin_lock_init(&fifo->read_queue_lock);
> + spin_lock_init(&fifo->write_queue_lock);
> +
> + dev_dbg(fifo->dt_device, "initialized spinlocks\n");
Delete.
> +
> + /* ----------------------------
> + * init device memory space
> + * ----------------------------
> + */
> +
> + /* get iospace for the device */
> + r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!r_mem) {
> + dev_err(fifo->dt_device, "invalid address\n");
> + rc = -ENODEV;
> + goto err_initial;
> + }
> +
> + fifo->mem_start = r_mem->start;
> + fifo->mem_end = r_mem->end;
Why not just save r_mem?
> +
> + /* request physical memory */
> + if (!request_mem_region(fifo->mem_start,
> + fifo->mem_end -
> + fifo->mem_start + 1,
resource_size(r_mem),
> + DRIVER_NAME)) {
> + dev_err(fifo->dt_device,
> + "couldn't lock memory region at %p\n",
> + (void *)fifo->mem_start);
> + rc = -EBUSY;
> + goto err_initial;
> + }
> + dev_dbg(fifo->dt_device,
> + "got memory location [0x%x - 0x%x]\n",
> + fifo->mem_start, fifo->mem_end);
> +
> + /* map physical memory to kernel virtual address space */
> + fifo->base_addr = ioremap(fifo->mem_start, fifo->mem_end -
> + fifo->mem_start + 1);
fifo->base_addr = ioremap(fifo->mem_start, resource_size(r_mem));
Fits on one line.
> +
> + if (!fifo->base_addr) {
> + dev_err(fifo->dt_device,
> + "couldn't map physical memory\n");
> + rc = -EIO;
For ioremap() failure the "rc = -ENOMEM;".
> + goto err_mem;
> + }
> + dev_dbg(fifo->dt_device, "remapped memory to 0x%x\n",
> + (unsigned int)fifo->base_addr);
Use %p. Casting a pointer to (unsigned int) will generate a GCC
warning. Plus casting is ugly.
> +
> + /* create unique device name */
> + snprintf(device_name, 32, DRIVER_NAME "_%x",
> + (unsigned int)fifo->mem_start);
Get rid of the magic 32 and the cast.
snprintf(device_name, sizeof(device_name) "%s_%x",
DRIVER_NAME, fifo->mem_start);
> +
> + dev_dbg(fifo->dt_device, "device name [%s]\n", device_name);
> +
> + /* ----------------------------
> + * init IP
> + * ----------------------------
> + */
> +
> + /* retrieve device tree properties */
> + if (get_dts_property(fifo, "xlnx,axi-str-rxd-tdata-width",
> + &rxd_tdata_width)) {
> + rc = -EIO;
> + goto err_mem;
After the ioremap() succeeds all the gotos should be goto unmap; until
we get to the next allocation. Also preserve the error code:
rc = get_dts_property(fifo, "xlnx,axi-str-rxd-tdata-width",
&rxd_tdata_width);
if (rc)
goto unmap;
> + }
> + if (get_dts_property(fifo, "xlnx,axi-str-txc-tdata-width",
> + &txc_tdata_width)) {
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (get_dts_property(fifo, "xlnx,axi-str-txd-tdata-width",
> + &txd_tdata_width)) {
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (get_dts_property(fifo, "xlnx,axis-tdest-width",
> + &tdest_width)) {
This will fit on one line:
rc = get_dts_property(fifo, "xlnx,axis-tdest-width", &tdest_width);
if (rc)
goto unmap;
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (get_dts_property(fifo, "xlnx,axis-tid-width",
> + &tid_width)) {
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (get_dts_property(fifo, "xlnx,axis-tuser-width",
> + &tuser_width)) {
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (get_dts_property(fifo, "xlnx,data-interface-type",
> + &data_interface_type)) {
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (get_dts_property(fifo, "xlnx,has-axis-tdest",
> + &has_tdest)) {
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (get_dts_property(fifo, "xlnx,has-axis-tid",
> + &has_tid)) {
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (get_dts_property(fifo, "xlnx,has-axis-tkeep",
> + &has_tkeep)) {
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (get_dts_property(fifo, "xlnx,has-axis-tstrb",
> + &has_tstrb)) {
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (get_dts_property(fifo, "xlnx,has-axis-tuser",
> + &has_tuser)) {
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (get_dts_property(fifo, "xlnx,rx-fifo-depth",
> + &rx_fifo_depth)) {
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (get_dts_property(fifo, "xlnx,rx-fifo-pe-threshold",
> + &rx_programmable_empty_threshold)) {
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (get_dts_property(fifo, "xlnx,rx-fifo-pf-threshold",
> + &rx_programmable_full_threshold)) {
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (get_dts_property(fifo, "xlnx,s-axi-id-width",
> + &axi_id_width)) {
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (get_dts_property(fifo, "xlnx,s-axi4-data-width",
> + &axi4_data_width)) {
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (get_dts_property(fifo, "xlnx,select-xpm",
> + &select_xpm)) {
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (get_dts_property(fifo, "xlnx,tx-fifo-depth",
> + &tx_fifo_depth)) {
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (get_dts_property(fifo, "xlnx,tx-fifo-pe-threshold",
> + &tx_programmable_empty_threshold)) {
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (get_dts_property(fifo, "xlnx,tx-fifo-pf-threshold",
> + &tx_programmable_full_threshold)) {
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (get_dts_property(fifo, "xlnx,use-rx-cut-through",
> + &use_rx_cut_through)) {
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (get_dts_property(fifo, "xlnx,use-rx-data",
> + &use_rx_data)) {
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (get_dts_property(fifo, "xlnx,use-tx-ctrl",
> + &use_tx_control)) {
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (get_dts_property(fifo, "xlnx,use-tx-cut-through",
> + &use_tx_cut_through)) {
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (get_dts_property(fifo, "xlnx,use-tx-data",
> + &use_tx_data)) {
> + rc = -EIO;
> + goto err_mem;
> + }
> +
> + /* check validity of device tree properties */
> + if (rxd_tdata_width != 32) {
> + dev_err(fifo->dt_device,
> + "rxd_tdata_width width [%u] unsupported\n",
> + rxd_tdata_width);
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (txd_tdata_width != 32) {
> + dev_err(fifo->dt_device,
> + "txd_tdata_width width [%u] unsupported\n",
> + txd_tdata_width);
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (has_tdest) {
> + dev_err(fifo->dt_device, "tdest not supported\n");
> + rc = -EIO;
> + goto err_mem;
> + }
Just out of curiosity, what would happen if we remove this check?
> + if (has_tid) {
> + dev_err(fifo->dt_device, "tid not supported\n");
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (has_tkeep) {
> + dev_err(fifo->dt_device, "tkeep not supported\n");
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (has_tstrb) {
> + dev_err(fifo->dt_device, "tstrb not supported\n");
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (has_tuser) {
> + dev_err(fifo->dt_device, "tuser not supported\n");
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (use_rx_cut_through) {
> + dev_err(fifo->dt_device,
> + "rx cut-through not supported\n");
Fits on one line:
dev_err(fifo->dt_device, "rx cut-through not supported\n");
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (use_tx_cut_through) {
> + dev_err(fifo->dt_device,
> + "tx cut-through not supported\n");
> + rc = -EIO;
> + goto err_mem;
> + }
> + if (use_tx_control) {
> + dev_err(fifo->dt_device,
> + "tx control not supported\n");
> + rc = -EIO;
> + goto err_mem;
> + }
> +
> + /* TODO
> + * these exist in the device tree but it's unclear what they do
> + * - select-xpm
> + * - data-interface-type
> + */
> +
> + /* set device wrapper properties based on IP config */
> + fifo->rx_fifo_depth = rx_fifo_depth;
> + /* IP sets TDFV to fifo depth - 4 so we will do the same */
> + fifo->tx_fifo_depth = tx_fifo_depth - 4;
> + fifo->has_rx_fifo = use_rx_data;
> + fifo->has_tx_fifo = use_tx_data;
> +
> + reset_ip_core(fifo);
> +
> + /* ----------------------------
> + * init device interrupts
> + * ----------------------------
> + */
> +
> + /* get IRQ resource */
> + r_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> + if (!r_irq) {
> + dev_err(fifo->dt_device,
> + "no IRQ found at 0x%08x mapped to 0x%08x\n",
> + (unsigned int __force)fifo->mem_start,
> + (unsigned int __force)fifo->base_addr);
No need for __force. Just get rid to the casts actually.
> + rc = -EIO;
> + goto err_mem;
> + }
> + dev_dbg(fifo->dt_device, "found IRQ\n");
> +
> + /* request IRQ */
> + fifo->irq = r_irq->start;
> + rc = request_irq(fifo->irq, &axis_fifo_irq, 0,
> + DRIVER_NAME, fifo);
> + if (rc) {
> + dev_err(fifo->dt_device,
> + "couldn't allocate interrupt %i\n",
> + fifo->irq);
> + rc = -EIO;
Just leave rc as is.
> + goto err_mem;
> + }
> + dev_dbg(fifo->dt_device,
> + "initialized IRQ %i\n",
> + fifo->irq);
Fits on one line.
> +
> + /* ----------------------------
> + * init char device
> + * ----------------------------
> + */
> +
> + /* allocate device number */
> + if (alloc_chrdev_region(&fifo->devt, 0, 1, DRIVER_NAME) < 0) {
> + dev_err(fifo->dt_device, "couldn't allocate dev_t\n");
> + rc = -EIO;
> + goto err_irq;
> + }
rc = alloc_chrdev_region(&fifo->devt, 0, 1, DRIVER_NAME);
if (rc)
goto err_irq;
Most of these functions have their own printks built in so there isn't
really a need to have a printk here.
> + dev_dbg(fifo->dt_device,
> + "allocated device number major %i minor %i\n",
> + MAJOR(fifo->devt), MINOR(fifo->devt));
> +
> + /* create driver file */
> + fifo->device = NULL;
Delete this line.
> + fifo->device = device_create(axis_fifo_driver_class, NULL, fifo->devt,
> + NULL, device_name);
> + if (!fifo->device) {
> + dev_err(fifo->dt_device,
> + "couldn't create driver file\n");
> + rc = -EIO;
rc = -ENOMEM;
> + goto err_chrdev_region;
> + }
> + dev_set_drvdata(fifo->device, fifo);
> + dev_dbg(fifo->dt_device, "created device file\n");
Just delete these debugging lines. It's obviously to the point where
it's working and you can test it now.
> +
> + /* create character device */
> + cdev_init(&fifo->char_device, &fops);
> + if (cdev_add(&fifo->char_device,
> + fifo->devt, 1) < 0) {
> + dev_err(fifo->dt_device,
> + "couldn't create character device\n");
> + rc = -EIO;
> + goto err_dev;
> + }
Preserve the code.
> + dev_dbg(fifo->dt_device, "created character device\n");
> +
> + /* create sysfs entries */
> + if (sysfs_create_group(&fifo->device->kobj,
> + &axis_fifo_attrs_group) < 0) {
> + dev_err(fifo->dt_device,
> + "couldn't register sysfs group\n");
> + rc = -EIO;
> + goto err_cdev;
> + }
> +
> + dev_info(fifo->dt_device,
> + "axis-fifo created at 0x%08x mapped to 0x%08x, irq=%i,
> major=%i, minor=%i\n",
> + (unsigned int __force)fifo->mem_start,
> + (unsigned int __force)fifo->base_addr,
> + fifo->irq, MAJOR(fifo->devt),
> + MINOR(fifo->devt));
> +
> + return 0;
> +
> +err_cdev:
> + cdev_del(&fifo->char_device);
> +err_dev:
> + dev_set_drvdata(fifo->device, NULL);
This hopefully isn't required since we delete fifo->device on the
next line.
> + device_destroy(axis_fifo_driver_class, fifo->devt);
> +err_chrdev_region:
> + unregister_chrdev_region(fifo->devt, 1);
> +err_irq:
> + free_irq(fifo->irq, fifo);
> +err_mem:
> + release_mem_region(fifo->mem_start,
> + fifo->mem_end -
> + fifo->mem_start + 1);
> +err_initial:
> + dev_set_drvdata(dev, NULL);
> + return rc;
> +}
> +
> +static int axis_fifo_remove(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct axis_fifo *fifo = dev_get_drvdata(dev);
> +
> + dev_info(dev, "removing\n");
Delete. ftrace.
> +
> + sysfs_remove_group(&fifo->device->kobj,
> + &axis_fifo_attrs_group);
One line:
sysfs_remove_group(&fifo->device->kobj, &axis_fifo_attrs_group);
> + cdev_del(&fifo->char_device);
> + dev_set_drvdata(fifo->device, NULL);
> + device_destroy(axis_fifo_driver_class, fifo->devt);
> + unregister_chrdev_region(fifo->devt, 1);
> + free_irq(fifo->irq, fifo);
Don't forget to do an iounmap() here as well.
> + release_mem_region(fifo->mem_start,
> + fifo->mem_end -
> + fifo->mem_start + 1);
> + dev_set_drvdata(dev, NULL);
> + return 0;
> +}
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id axis_fifo_of_match[] = {
> + { .compatible = "xlnx,axi-fifo-mm-s-4.1", },
> + { },
> +};
> +MODULE_DEVICE_TABLE(of, axis_fifo_of_match);
> +#else
> +# define axis_fifo_of_match
> +#endif
> +
> +static struct platform_driver axis_fifo_driver = {
> + .driver = {
> + .name = DRIVER_NAME,
> + .owner = THIS_MODULE,
> + .of_match_table = axis_fifo_of_match,
> + },
> + .probe = axis_fifo_probe,
> + .remove = axis_fifo_remove,
> +};
> +
> +static int __init axis_fifo_init(void)
> +{
> + printk(KERN_INFO "axis-fifo driver loaded with parameters read_timeout
> = %i, write_timeout = %i\n",
> + read_timeout, write_timeout);
Delete. Or update to use pr_info() at least.
> + axis_fifo_driver_class = class_create(THIS_MODULE, DRIVER_NAME);
> + return platform_driver_register(&axis_fifo_driver);
> +}
> +
> +module_init(axis_fifo_init);
> +
> +static void __exit axis_fifo_exit(void)
> +{
> + platform_driver_unregister(&axis_fifo_driver);
> + class_destroy(axis_fifo_driver_class);
> + printk(KERN_INFO "axis-fifo driver exit\n");
Delete.
> +}
> +
regards,
dan carpenter
_______________________________________________
devel mailing list
[email protected]
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel