diff options
-rw-r--r-- | driver/aim-cdev/Makefile | 18 | ||||
-rw-r--r-- | driver/aim-cdev/cdev.c | 18 | ||||
-rw-r--r-- | driver/aim-network/Makefile | 18 | ||||
-rw-r--r-- | driver/aim-network/networking.c | 307 | ||||
-rw-r--r-- | driver/aim-sound/Makefile | 18 | ||||
-rw-r--r-- | driver/aim-sound/sound.c | 125 | ||||
-rw-r--r-- | driver/aim-v4l2/Makefile | 18 | ||||
-rw-r--r-- | driver/hdm-dim2/Makefile | 18 | ||||
-rw-r--r-- | driver/hdm-dim2/dim2_hal.c | 33 | ||||
-rw-r--r-- | driver/hdm-dim2/dim2_hdm.c | 105 | ||||
-rw-r--r-- | driver/hdm-dim2/dim2_hdm.h | 9 | ||||
-rw-r--r-- | driver/hdm-dim2/dim2_reg.h | 1 | ||||
-rw-r--r-- | driver/hdm-i2c/Makefile | 17 | ||||
-rw-r--r-- | driver/hdm-i2c/hdm_i2c.c | 151 | ||||
-rw-r--r-- | driver/hdm-usb/Makefile | 17 | ||||
-rw-r--r-- | driver/hdm-usb/hdm_usb.c | 122 | ||||
-rw-r--r-- | driver/include/mostcore.h | 17 | ||||
-rw-r--r-- | driver/include/networking.h | 21 | ||||
-rw-r--r-- | driver/mostcore/Makefile | 18 | ||||
-rw-r--r-- | driver/mostcore/core.c | 260 |
20 files changed, 556 insertions, 755 deletions
diff --git a/driver/aim-cdev/Makefile b/driver/aim-cdev/Makefile deleted file mode 100644 index c49a1f3..0000000 --- a/driver/aim-cdev/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# Makefile -# - -SRC := $(shell pwd) - -obj-m += aim_cdev.o -aim_cdev-y := cdev.o -CFLAGS_cdev.o := -I$(src)/../include/ - -all: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules - -modules_install: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install - -clean: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) clean - diff --git a/driver/aim-cdev/cdev.c b/driver/aim-cdev/cdev.c index 7f51024..ce0f9fc 100644 --- a/driver/aim-cdev/cdev.c +++ b/driver/aim-cdev/cdev.c @@ -99,11 +99,16 @@ static void destroy_cdev(struct aim_channel *c) device_destroy(aim_class, c->devno); cdev_del(&c->cdev); - kfifo_free(&c->fifo); spin_lock_irqsave(&ch_list_lock, flags); list_del(&c->list); spin_unlock_irqrestore(&ch_list_lock, flags); +} + +static void destroy_channel(struct aim_channel *c) +{ ida_simple_remove(&minor_id, MINOR(c->devno)); + kfifo_free(&c->fifo); + kfree(c); } /** @@ -170,9 +175,8 @@ static int aim_close(struct inode *inode, struct file *filp) stop_channel(c); mutex_unlock(&c->io_mutex); } else { - destroy_cdev(c); mutex_unlock(&c->io_mutex); - kfree(c); + destroy_channel(c); } return 0; } @@ -242,7 +246,7 @@ static ssize_t aim_read(struct file *filp, char __user *buf, size_t count, loff_t *offset) { size_t to_copy, not_copied, copied; - struct mbo *mbo; + struct mbo *mbo = NULL; struct aim_channel *c = filp->private_data; mutex_lock(&c->io_mutex); @@ -337,14 +341,14 @@ static int aim_disconnect_channel(struct most_interface *iface, int channel_id) spin_lock(&c->unlink); c->dev = NULL; spin_unlock(&c->unlink); + destroy_cdev(c); if (c->access_ref) { stop_channel(c); wake_up_interruptible(&c->wq); mutex_unlock(&c->io_mutex); } else { - destroy_cdev(c); mutex_unlock(&c->io_mutex); - kfree(c); + destroy_channel(c); } return 0; } @@ -546,7 +550,7 @@ static void __exit mod_exit(void) list_for_each_entry_safe(c, tmp, &channel_list, list) { destroy_cdev(c); - kfree(c); + destroy_channel(c); } class_destroy(aim_class); unregister_chrdev_region(aim_devno, 1); diff --git a/driver/aim-network/Makefile b/driver/aim-network/Makefile deleted file mode 100644 index 93d6570..0000000 --- a/driver/aim-network/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# Makefile -# - -SRC := $(shell pwd) - -obj-m := aim_network.o -aim_network-y := networking.o -CFLAGS_networking.o := -I$(src)/../include/ - -all: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules - -modules_install: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install - -clean: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) clean - diff --git a/driver/aim-network/networking.c b/driver/aim-network/networking.c index ce1764c..936f013 100644 --- a/driver/aim-network/networking.c +++ b/driver/aim-network/networking.c @@ -22,7 +22,6 @@ #include <linux/wait.h> #include <linux/kobject.h> #include "mostcore.h" -#include "networking.h" #define MEP_HDR_LEN 8 #define MDP_HDR_LEN 16 @@ -65,17 +64,16 @@ struct net_dev_channel { struct net_dev_context { struct most_interface *iface; - bool channels_opened; bool is_mamac; struct net_device *dev; struct net_dev_channel rx; struct net_dev_channel tx; - struct completion mac_compl; struct list_head list; }; static struct list_head net_devices = LIST_HEAD_INIT(net_devices); -static struct spinlock list_lock; +static struct mutex probe_disc_mt; /* ch->linked = true, most_nd_open */ +static struct spinlock list_lock; /* list_head, ch->linked = false, dev_hold */ static struct most_aim aim; static int skb_to_mamac(const struct sk_buff *skb, struct mbo *mbo) @@ -157,14 +155,12 @@ static int skb_to_mep(const struct sk_buff *skb, struct mbo *mbo) static int most_nd_set_mac_address(struct net_device *dev, void *p) { - struct net_dev_context *nd = dev->ml_priv; + struct net_dev_context *nd = netdev_priv(dev); int err = eth_mac_addr(dev, p); if (err) return err; - BUG_ON(nd->dev != dev); - nd->is_mamac = (dev->dev_addr[0] == 0 && dev->dev_addr[1] == 0 && dev->dev_addr[2] == 0 && dev->dev_addr[3] == 0); @@ -178,71 +174,52 @@ static int most_nd_set_mac_address(struct net_device *dev, void *p) return 0; } +static void on_netinfo(struct most_interface *iface, + unsigned char link_stat, unsigned char *mac_addr); + static int most_nd_open(struct net_device *dev) { - struct net_dev_context *nd = dev->ml_priv; - long ret; - - netdev_info(dev, "open net device\n"); - - BUG_ON(nd->dev != dev); + struct net_dev_context *nd = netdev_priv(dev); + int ret = 0; - if (nd->channels_opened) - return -EFAULT; - - BUG_ON(!nd->tx.linked || !nd->rx.linked); + mutex_lock(&probe_disc_mt); if (most_start_channel(nd->iface, nd->rx.ch_id, &aim)) { netdev_err(dev, "most_start_channel() failed\n"); - return -EBUSY; + ret = -EBUSY; + goto unlock; } if (most_start_channel(nd->iface, nd->tx.ch_id, &aim)) { netdev_err(dev, "most_start_channel() failed\n"); most_stop_channel(nd->iface, nd->rx.ch_id, &aim); - return -EBUSY; + ret = -EBUSY; + goto unlock; } - if (!is_valid_ether_addr(dev->dev_addr)) { - nd->iface->request_netinfo(nd->iface, nd->tx.ch_id); - ret = wait_for_completion_interruptible_timeout( - &nd->mac_compl, msecs_to_jiffies(5000)); - if (!ret) { - netdev_err(dev, "mac timeout\n"); - ret = -EBUSY; - goto err; - } - - if (ret < 0) { - netdev_warn(dev, "mac waiting interrupted\n"); - goto err; - } - } - - nd->channels_opened = true; + netif_carrier_off(dev); + if (is_valid_ether_addr(dev->dev_addr)) + netif_dormant_off(dev); + else + netif_dormant_on(dev); netif_wake_queue(dev); - return 0; + if (nd->iface->request_netinfo) + nd->iface->request_netinfo(nd->iface, nd->tx.ch_id, on_netinfo); -err: - most_stop_channel(nd->iface, nd->tx.ch_id, &aim); - most_stop_channel(nd->iface, nd->rx.ch_id, &aim); +unlock: + mutex_unlock(&probe_disc_mt); return ret; } static int most_nd_stop(struct net_device *dev) { - struct net_dev_context *nd = dev->ml_priv; - - netdev_info(dev, "stop net device\n"); + struct net_dev_context *nd = netdev_priv(dev); - BUG_ON(nd->dev != dev); netif_stop_queue(dev); - - if (nd->channels_opened) { - most_stop_channel(nd->iface, nd->rx.ch_id, &aim); - most_stop_channel(nd->iface, nd->tx.ch_id, &aim); - nd->channels_opened = false; - } + if (nd->iface->request_netinfo) + nd->iface->request_netinfo(nd->iface, nd->tx.ch_id, NULL); + most_stop_channel(nd->iface, nd->rx.ch_id, &aim); + most_stop_channel(nd->iface, nd->tx.ch_id, &aim); return 0; } @@ -250,12 +227,10 @@ static int most_nd_stop(struct net_device *dev) static netdev_tx_t most_nd_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct net_dev_context *nd = dev->ml_priv; + struct net_dev_context *nd = netdev_priv(dev); struct mbo *mbo; int ret; - BUG_ON(nd->dev != dev); - mbo = most_get_mbo(nd->iface, nd->tx.ch_id, &aim); if (!mbo) { @@ -296,33 +271,29 @@ static void most_nd_setup(struct net_device *dev) dev->netdev_ops = &most_nd_ops; } -static void most_net_rm_netdev_safe(struct net_dev_context *nd) +static struct net_dev_context *get_net_dev(struct most_interface *iface) { - if (!nd->dev) - return; - - pr_info("remove net device %p\n", nd->dev); + struct net_dev_context *nd; - unregister_netdev(nd->dev); - free_netdev(nd->dev); - nd->dev = NULL; + list_for_each_entry(nd, &net_devices, list) + if (nd->iface == iface) + return nd; + return NULL; } -static struct net_dev_context *get_net_dev_context( - struct most_interface *iface) +static struct net_dev_context *get_net_dev_hold(struct most_interface *iface) { - struct net_dev_context *nd, *tmp; + struct net_dev_context *nd; unsigned long flags; spin_lock_irqsave(&list_lock, flags); - list_for_each_entry_safe(nd, tmp, &net_devices, list) { - if (nd->iface == iface) { - spin_unlock_irqrestore(&list_lock, flags); - return nd; - } - } + nd = get_net_dev(iface); + if (nd && nd->rx.linked && nd->tx.linked) + dev_hold(nd->dev); + else + nd = NULL; spin_unlock_irqrestore(&list_lock, flags); - return NULL; + return nd; } static int aim_probe_channel(struct most_interface *iface, int channel_idx, @@ -331,7 +302,9 @@ static int aim_probe_channel(struct most_interface *iface, int channel_idx, { struct net_dev_context *nd; struct net_dev_channel *ch; + struct net_device *dev; unsigned long flags; + int ret = 0; if (!iface) return -EINVAL; @@ -339,54 +312,45 @@ static int aim_probe_channel(struct most_interface *iface, int channel_idx, if (ccfg->data_type != MOST_CH_ASYNC) return -EINVAL; - nd = get_net_dev_context(iface); - + mutex_lock(&probe_disc_mt); + nd = get_net_dev(iface); if (!nd) { - nd = kzalloc(sizeof(*nd), GFP_KERNEL); - if (!nd) - return -ENOMEM; + dev = alloc_netdev(sizeof(struct net_dev_context), "meth%d", + NET_NAME_UNKNOWN, most_nd_setup); + if (!dev) { + ret = -ENOMEM; + goto unlock; + } - init_completion(&nd->mac_compl); + nd = netdev_priv(dev); nd->iface = iface; + nd->dev = dev; spin_lock_irqsave(&list_lock, flags); list_add(&nd->list, &net_devices); spin_unlock_irqrestore(&list_lock, flags); - } - ch = ccfg->direction == MOST_CH_TX ? &nd->tx : &nd->rx; - if (ch->linked) { - pr_err("only one channel per instance & direction allowed\n"); - return -EINVAL; - } - - if (nd->tx.linked || nd->rx.linked) { - struct net_device *dev = - alloc_netdev(0, "meth%d", NET_NAME_UNKNOWN, - most_nd_setup); - - if (!dev) { - pr_err("no memory for net_device\n"); - return -ENOMEM; + ch = ccfg->direction == MOST_CH_TX ? &nd->tx : &nd->rx; + } else { + ch = ccfg->direction == MOST_CH_TX ? &nd->tx : &nd->rx; + if (ch->linked) { + pr_err("direction is allocated\n"); + ret = -EINVAL; + goto unlock; } - nd->dev = dev; - ch->ch_id = channel_idx; - ch->linked = true; - - dev->ml_priv = nd; - if (register_netdev(dev)) { - pr_err("registering net device failed\n"); - ch->linked = false; - free_netdev(dev); - return -EINVAL; + if (register_netdev(nd->dev)) { + pr_err("register_netdev() failed\n"); + ret = -EINVAL; + goto unlock; } } - ch->ch_id = channel_idx; ch->linked = true; - return 0; +unlock: + mutex_unlock(&probe_disc_mt); + return ret; } static int aim_disconnect_channel(struct most_interface *iface, @@ -395,34 +359,45 @@ static int aim_disconnect_channel(struct most_interface *iface, struct net_dev_context *nd; struct net_dev_channel *ch; unsigned long flags; + int ret = 0; - nd = get_net_dev_context(iface); - if (!nd) - return -EINVAL; + mutex_lock(&probe_disc_mt); + nd = get_net_dev(iface); + if (!nd) { + ret = -EINVAL; + goto unlock; + } - if (nd->rx.linked && channel_idx == nd->rx.ch_id) + if (nd->rx.linked && channel_idx == nd->rx.ch_id) { ch = &nd->rx; - else if (nd->tx.linked && channel_idx == nd->tx.ch_id) + } else if (nd->tx.linked && channel_idx == nd->tx.ch_id) { ch = &nd->tx; - else - return -EINVAL; - - ch->linked = false; + } else { + ret = -EINVAL; + goto unlock; + } - /* - * do not call most_stop_channel() here, because channels are - * going to be closed in ndo_stop() after unregister_netdev() - */ - most_net_rm_netdev_safe(nd); + if (nd->rx.linked && nd->tx.linked) { + spin_lock_irqsave(&list_lock, flags); + ch->linked = false; + spin_unlock_irqrestore(&list_lock, flags); - if (!nd->rx.linked && !nd->tx.linked) { + /* + * do not call most_stop_channel() here, because channels are + * going to be closed in ndo_stop() after unregister_netdev() + */ + unregister_netdev(nd->dev); + } else { spin_lock_irqsave(&list_lock, flags); list_del(&nd->list); spin_unlock_irqrestore(&list_lock, flags); - kfree(nd); + + free_netdev(nd->dev); } - return 0; +unlock: + mutex_unlock(&probe_disc_mt); + return ret; } static int aim_resume_tx_channel(struct most_interface *iface, @@ -430,14 +405,17 @@ static int aim_resume_tx_channel(struct most_interface *iface, { struct net_dev_context *nd; - nd = get_net_dev_context(iface); - if (!nd || !nd->channels_opened || nd->tx.ch_id != channel_idx) + nd = get_net_dev_hold(iface); + if (!nd) return 0; - if (!nd->dev) - return 0; + if (nd->tx.ch_id != channel_idx) + goto put_nd; netif_wake_queue(nd->dev); + +put_nd: + dev_put(nd->dev); return 0; } @@ -450,25 +428,31 @@ static int aim_rx_data(struct mbo *mbo) struct sk_buff *skb; struct net_device *dev; unsigned int skb_len; + int ret = 0; - nd = get_net_dev_context(mbo->ifp); - if (!nd || !nd->channels_opened || nd->rx.ch_id != mbo->hdm_channel_id) + nd = get_net_dev_hold(mbo->ifp); + if (!nd) return -EIO; - dev = nd->dev; - if (!dev) { - pr_err_once("drop packet: missing net_device\n"); - return -EIO; + if (nd->rx.ch_id != mbo->hdm_channel_id) { + ret = -EIO; + goto put_nd; } + dev = nd->dev; + if (nd->is_mamac) { - if (!PMS_IS_MAMAC(buf, len)) - return -EIO; + if (!PMS_IS_MAMAC(buf, len)) { + ret = -EIO; + goto put_nd; + } skb = dev_alloc_skb(len - MDP_HDR_LEN + 2 * ETH_ALEN + 2); } else { - if (!PMS_IS_MEP(buf, len)) - return -EIO; + if (!PMS_IS_MEP(buf, len)) { + ret = -EIO; + goto put_nd; + } skb = dev_alloc_skb(len - MEP_HDR_LEN); } @@ -486,11 +470,11 @@ static int aim_rx_data(struct mbo *mbo) ether_addr_copy(skb_put(skb, ETH_ALEN), dev->dev_addr); /* src */ - memcpy(skb_put(skb, 4), &zero, 4); - memcpy(skb_put(skb, 2), buf + 5, 2); + skb_put_data(skb, &zero, 4); + skb_put_data(skb, buf + 5, 2); /* eth type */ - memcpy(skb_put(skb, 2), buf + 10, 2); + skb_put_data(skb, buf + 10, 2); buf += MDP_HDR_LEN; len -= MDP_HDR_LEN; @@ -499,7 +483,7 @@ static int aim_rx_data(struct mbo *mbo) len -= MEP_HDR_LEN; } - memcpy(skb_put(skb, len), buf, len); + skb_put_data(skb, buf, len); skb->protocol = eth_type_trans(skb, dev); skb_len = skb->len; if (netif_rx(skb) == NET_RX_SUCCESS) { @@ -511,7 +495,10 @@ static int aim_rx_data(struct mbo *mbo) out: most_put_mbo(mbo); - return 0; + +put_nd: + dev_put(nd->dev); + return ret; } static struct most_aim aim = { @@ -524,68 +511,54 @@ static struct most_aim aim = { static int __init most_net_init(void) { - pr_info("most_net_init()\n"); spin_lock_init(&list_lock); + mutex_init(&probe_disc_mt); return most_register_aim(&aim); } static void __exit most_net_exit(void) { - struct net_dev_context *nd, *tmp; - unsigned long flags; - - spin_lock_irqsave(&list_lock, flags); - list_for_each_entry_safe(nd, tmp, &net_devices, list) { - list_del(&nd->list); - spin_unlock_irqrestore(&list_lock, flags); - /* - * do not call most_stop_channel() here, because channels are - * going to be closed in ndo_stop() after unregister_netdev() - */ - most_net_rm_netdev_safe(nd); - kfree(nd); - spin_lock_irqsave(&list_lock, flags); - } - spin_unlock_irqrestore(&list_lock, flags); - most_deregister_aim(&aim); - pr_info("most_net_exit()\n"); } /** - * most_deliver_netinfo - callback for HDM to be informed about HW's MAC + * on_netinfo - callback for HDM to be informed about HW's MAC * @param iface - most interface instance * @param link_stat - link status * @param mac_addr - MAC address */ -void most_deliver_netinfo(struct most_interface *iface, - unsigned char link_stat, unsigned char *mac_addr) +static void on_netinfo(struct most_interface *iface, + unsigned char link_stat, unsigned char *mac_addr) { struct net_dev_context *nd; struct net_device *dev; const u8 *m = mac_addr; - nd = get_net_dev_context(iface); + nd = get_net_dev_hold(iface); if (!nd) return; dev = nd->dev; - if (!dev) - return; + + if (link_stat) + netif_carrier_on(dev); + else + netif_carrier_off(dev); if (m && is_valid_ether_addr(m)) { if (!is_valid_ether_addr(dev->dev_addr)) { netdev_info(dev, "set mac %02x-%02x-%02x-%02x-%02x-%02x\n", m[0], m[1], m[2], m[3], m[4], m[5]); ether_addr_copy(dev->dev_addr, m); - complete(&nd->mac_compl); + netif_dormant_off(dev); } else if (!ether_addr_equal(dev->dev_addr, m)) { netdev_warn(dev, "reject mac %02x-%02x-%02x-%02x-%02x-%02x\n", m[0], m[1], m[2], m[3], m[4], m[5]); } } + + dev_put(nd->dev); } -EXPORT_SYMBOL(most_deliver_netinfo); module_init(most_net_init); module_exit(most_net_exit); diff --git a/driver/aim-sound/Makefile b/driver/aim-sound/Makefile deleted file mode 100644 index 5c07108..0000000 --- a/driver/aim-sound/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# Makefile -# - -SRC := $(shell pwd) - -obj-m += aim_sound.o -aim_sound-y := sound.o -CFLAGS_sound.o := -I$(src)/../include/ - -all: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules - -modules_install: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install - -clean: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) clean - diff --git a/driver/aim-sound/sound.c b/driver/aim-sound/sound.c index e4198e5..6a290ff 100644 --- a/driver/aim-sound/sound.c +++ b/driver/aim-sound/sound.c @@ -429,7 +429,7 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) return 0; default: - pr_info("pcm_trigger(), invalid\n"); + pr_info("%s(), invalid\n", __func__); return -EINVAL; } return 0; @@ -466,21 +466,68 @@ static const struct snd_pcm_ops pcm_ops = { .mmap = snd_pcm_lib_mmap_vmalloc, }; -static int split_arg_list(char *buf, char **card_name, char **pcm_format) +static int split_arg_list(char *buf, char **card_name, u16 *ch_num, + char **sample_res) { + char *num; + int ret; + *card_name = strsep(&buf, "."); - if (!*card_name) - return -EIO; - *pcm_format = strsep(&buf, ".\n"); - if (!*pcm_format) + if (!*card_name) { + pr_err("Missing sound card name\n"); return -EIO; + } + num = strsep(&buf, "x"); + if (!num) + goto err; + ret = kstrtou16(num, 0, ch_num); + if (ret) + goto err; + *sample_res = strsep(&buf, ".\n"); + if (!*sample_res) + goto err; return 0; + +err: + pr_err("Bad PCM format\n"); + return -EIO; } +static const struct sample_resolution_info { + const char *sample_res; + int bytes; + u64 formats; +} sinfo[] = { + { "8", 1, SNDRV_PCM_FMTBIT_S8 }, + { "16", 2, SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE }, + { "24", 3, SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE }, + { "32", 4, SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE }, +}; + static int audio_set_hw_params(struct snd_pcm_hardware *pcm_hw, - char *pcm_format, + u16 ch_num, char *sample_res, struct most_channel_config *cfg) { + int i; + + for (i = 0; i < ARRAY_SIZE(sinfo); i++) { + if (!strcmp(sample_res, sinfo[i].sample_res)) + goto found; + } + pr_err("Unsupported PCM format\n"); + return -EIO; + +found: + if (!ch_num) { + pr_err("Bad number of channels\n"); + return -EINVAL; + } + + if (cfg->subbuffer_size != ch_num * sinfo[i].bytes) { + pr_err("Audio resolution doesn't fit subbuffer size\n"); + return -EINVAL; + } + pcm_hw->info = MOST_PCM_INFO; pcm_hw->rates = SNDRV_PCM_RATE_48000; pcm_hw->rate_min = 48000; @@ -490,54 +537,10 @@ static int audio_set_hw_params(struct snd_pcm_hardware *pcm_hw, pcm_hw->period_bytes_max = cfg->buffer_size; pcm_hw->periods_min = 1; pcm_hw->periods_max = cfg->num_buffers; - - if (!strcmp(pcm_format, "1x8")) { - if (cfg->subbuffer_size != 1) - goto error; - pr_info("PCM format is 8-bit mono\n"); - pcm_hw->channels_min = 1; - pcm_hw->channels_max = 1; - pcm_hw->formats = SNDRV_PCM_FMTBIT_S8; - } else if (!strcmp(pcm_format, "2x16")) { - if (cfg->subbuffer_size != 4) - goto error; - pr_info("PCM format is 16-bit stereo\n"); - pcm_hw->channels_min = 2; - pcm_hw->channels_max = 2; - pcm_hw->formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S16_BE; - } else if (!strcmp(pcm_format, "2x24")) { - if (cfg->subbuffer_size != 6) - goto error; - pr_info("PCM format is 24-bit stereo\n"); - pcm_hw->channels_min = 2; - pcm_hw->channels_max = 2; - pcm_hw->formats = SNDRV_PCM_FMTBIT_S24_3LE | - SNDRV_PCM_FMTBIT_S24_3BE; - } else if (!strcmp(pcm_format, "2x32")) { - if (cfg->subbuffer_size != 8) - goto error; - pr_info("PCM format is 32-bit stereo\n"); - pcm_hw->channels_min = 2; - pcm_hw->channels_max = 2; - pcm_hw->formats = SNDRV_PCM_FMTBIT_S32_LE | - SNDRV_PCM_FMTBIT_S32_BE; - } else if (!strcmp(pcm_format, "6x16")) { - if (cfg->subbuffer_size != 12) - goto error; - pr_info("PCM format is 16-bit 5.1 multi channel\n"); - pcm_hw->channels_min = 6; - pcm_hw->channels_max = 6; - pcm_hw->formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S16_BE; - } else { - pr_err("PCM format %s not supported\n", pcm_format); - return -EIO; - } + pcm_hw->channels_min = ch_num; + pcm_hw->channels_max = ch_num; + pcm_hw->formats = sinfo[i].formats; return 0; -error: - pr_err("Audio resolution doesn't fit subbuffer size\n"); - return -EINVAL; } /** @@ -565,7 +568,8 @@ static int audio_probe_channel(struct most_interface *iface, int channel_id, int ret; int direction; char *card_name; - char *pcm_format; + u16 ch_num; + char *sample_res; if (!iface) return -EINVAL; @@ -589,13 +593,11 @@ static int audio_probe_channel(struct most_interface *iface, int channel_id, direction = SNDRV_PCM_STREAM_CAPTURE; } - ret = split_arg_list(arg_list, &card_name, &pcm_format); - if (ret < 0) { - pr_info("PCM format missing\n"); + ret = split_arg_list(arg_list, &card_name, &ch_num, &sample_res); + if (ret < 0) return ret; - } - ret = snd_card_new(NULL, -1, card_name, THIS_MODULE, + ret = snd_card_new(iface->dev, -1, card_name, THIS_MODULE, sizeof(*channel), &card); if (ret < 0) return ret; @@ -607,7 +609,8 @@ static int audio_probe_channel(struct most_interface *iface, int channel_id, channel->id = channel_id; init_waitqueue_head(&channel->playback_waitq); - ret = audio_set_hw_params(&channel->pcm_hardware, pcm_format, cfg); + ret = audio_set_hw_params(&channel->pcm_hardware, ch_num, sample_res, + cfg); if (ret) goto err_free_card; diff --git a/driver/aim-v4l2/Makefile b/driver/aim-v4l2/Makefile deleted file mode 100644 index 106ed2a..0000000 --- a/driver/aim-v4l2/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# Makefile -# - -SRC := $(shell pwd) - -obj-m += aim_v4l2.o -aim_v4l2-y := video.o -CFLAGS_video.o := -Idrivers/media/video -I$(src)/../include/ - -all: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules - -modules_install: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install - -clean: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) clean - diff --git a/driver/hdm-dim2/Makefile b/driver/hdm-dim2/Makefile deleted file mode 100644 index 8ffaa23..0000000 --- a/driver/hdm-dim2/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# Makefile -# - -SRC := $(shell pwd) - -obj-m += hdm_dim2.o -hdm_dim2-y := dim2_hdm.o dim2_hal.o dim2_sysfs.o -CFLAGS_dim2_hdm.o := -I$(src)/../include/ - -all: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules - -modules_install: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install - -clean: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) clean - diff --git a/driver/hdm-dim2/dim2_hal.c b/driver/hdm-dim2/dim2_hal.c index 0b9816c..28eaa2a 100644 --- a/driver/hdm-dim2/dim2_hal.c +++ b/driver/hdm-dim2/dim2_hal.c @@ -18,6 +18,7 @@ #include "dim2_errors.h" #include "dim2_reg.h" #include <linux/stddef.h> +#include <linux/kernel.h> /* * Size factor for isochronous DBR buffer. @@ -49,7 +50,7 @@ #define DBR_SIZE (16 * 1024) /* specified by IP */ #define DBR_BLOCK_SIZE (DBR_SIZE / 32 / DBR_MAP_SIZE) -#define ROUND_UP_TO(x, d) (((x) + (d) - 1) / (d) * (d)) +#define ROUND_UP_TO(x, d) (DIV_ROUND_UP(x, (d)) * (d)) /* -------------------------------------------------------------------------- */ /* generic helper functions and macros */ @@ -117,7 +118,7 @@ static int alloc_dbr(u16 size) return DBR_SIZE; /* out of memory */ for (i = 0; i < DBR_MAP_SIZE; i++) { - u32 const blocks = (size + DBR_BLOCK_SIZE - 1) / DBR_BLOCK_SIZE; + u32 const blocks = DIV_ROUND_UP(size, DBR_BLOCK_SIZE); u32 mask = ~((~(u32)0) << blocks); do { @@ -137,7 +138,7 @@ static int alloc_dbr(u16 size) static void free_dbr(int offs, int size) { int block_idx = offs / DBR_BLOCK_SIZE; - u32 const blocks = (size + DBR_BLOCK_SIZE - 1) / DBR_BLOCK_SIZE; + u32 const blocks = DIV_ROUND_UP(size, DBR_BLOCK_SIZE); u32 mask = ~((~(u32)0) << blocks); mask <<= block_idx % 32; @@ -216,12 +217,15 @@ static inline void dim2_clear_ctr(u32 ctr_addr) } static void dim2_configure_cat(u8 cat_base, u8 ch_addr, u8 ch_type, - bool read_not_write, bool sync_mfe) + bool read_not_write) { + bool isoc_fce = ch_type == CAT_CT_VAL_ISOC; + bool sync_mfe = ch_type == CAT_CT_VAL_SYNC; u16 const cat = (read_not_write << CAT_RNW_BIT) | (ch_type << CAT_CT_SHIFT) | (ch_addr << CAT_CL_SHIFT) | + (isoc_fce << CAT_FCE_BIT) | (sync_mfe << CAT_MFE_BIT) | (false << CAT_MT_BIT) | (true << CAT_CE_BIT); @@ -349,13 +353,13 @@ static void dim2_clear_ctram(void) static void dim2_configure_channel( u8 ch_addr, u8 type, u8 is_tx, u16 dbr_address, u16 hw_buffer_size, - u16 packet_length, bool sync_mfe) + u16 packet_length) { dim2_configure_cdt(ch_addr, dbr_address, hw_buffer_size, packet_length); - dim2_configure_cat(MLB_CAT, ch_addr, type, is_tx ? 1 : 0, sync_mfe); + dim2_configure_cat(MLB_CAT, ch_addr, type, is_tx ? 1 : 0); dim2_configure_adt(ch_addr); - dim2_configure_cat(AHB_CAT, ch_addr, type, is_tx ? 0 : 1, sync_mfe); + dim2_configure_cat(AHB_CAT, ch_addr, type, is_tx ? 0 : 1); /* unmask interrupt for used channel, enable mlb_sys_int[0] interrupt */ dimcb_io_write(&g.dim2->ACMR0, @@ -762,7 +766,8 @@ static u8 init_ctrl_async(struct dim_channel *ch, u8 type, u8 is_tx, if (!check_channel_address(ch_address)) return DIM_INIT_ERR_CHANNEL_ADDRESS; - ch->dbr_size = ROUND_UP_TO(hw_buffer_size, DBR_BLOCK_SIZE); + if (!ch->dbr_size) + ch->dbr_size = ROUND_UP_TO(hw_buffer_size, DBR_BLOCK_SIZE); ch->dbr_addr = alloc_dbr(ch->dbr_size); if (ch->dbr_addr >= DBR_SIZE) return DIM_INIT_ERR_OUT_OF_MEMORY; @@ -770,7 +775,7 @@ static u8 init_ctrl_async(struct dim_channel *ch, u8 type, u8 is_tx, channel_init(ch, ch_address / 2); dim2_configure_channel(ch->addr, type, is_tx, - ch->dbr_addr, ch->dbr_size, 0, false); + ch->dbr_addr, ch->dbr_size, 0); return DIM_NO_ERROR; } @@ -848,7 +853,8 @@ u8 dim_init_isoc(struct dim_channel *ch, u8 is_tx, u16 ch_address, if (!check_packet_length(packet_length)) return DIM_ERR_BAD_CONFIG; - ch->dbr_size = packet_length * ISOC_DBR_FACTOR; + if (!ch->dbr_size) + ch->dbr_size = packet_length * ISOC_DBR_FACTOR; ch->dbr_addr = alloc_dbr(ch->dbr_size); if (ch->dbr_addr >= DBR_SIZE) return DIM_INIT_ERR_OUT_OF_MEMORY; @@ -856,7 +862,7 @@ u8 dim_init_isoc(struct dim_channel *ch, u8 is_tx, u16 ch_address, isoc_init(ch, ch_address / 2, packet_length); dim2_configure_channel(ch->addr, CAT_CT_VAL_ISOC, is_tx, ch->dbr_addr, - ch->dbr_size, packet_length, false); + ch->dbr_size, packet_length); return DIM_NO_ERROR; } @@ -875,7 +881,8 @@ u8 dim_init_sync(struct dim_channel *ch, u8 is_tx, u16 ch_address, if (!check_bytes_per_frame(bytes_per_frame)) return DIM_ERR_BAD_CONFIG; - ch->dbr_size = bytes_per_frame << bd_factor; + if (!ch->dbr_size) + ch->dbr_size = bytes_per_frame << bd_factor; ch->dbr_addr = alloc_dbr(ch->dbr_size); if (ch->dbr_addr >= DBR_SIZE) return DIM_INIT_ERR_OUT_OF_MEMORY; @@ -884,7 +891,7 @@ u8 dim_init_sync(struct dim_channel *ch, u8 is_tx, u16 ch_address, dim2_clear_dbr(ch->dbr_addr, ch->dbr_size); dim2_configure_channel(ch->addr, CAT_CT_VAL_SYNC, is_tx, - ch->dbr_addr, ch->dbr_size, 0, true); + ch->dbr_addr, ch->dbr_size, 0); return DIM_NO_ERROR; } diff --git a/driver/hdm-dim2/dim2_hdm.c b/driver/hdm-dim2/dim2_hdm.c index 35aee9f..893b8e4 100644 --- a/driver/hdm-dim2/dim2_hdm.c +++ b/driver/hdm-dim2/dim2_hdm.c @@ -1,7 +1,7 @@ /* * dim2_hdm.c - MediaLB DIM2 Hardware Dependent Module * - * Copyright (C) 2015-2016, Microchip Technology Germany II GmbH & Co. KG + * Copyright (C) 2015-2017, Microchip Technology Germany II GmbH & Co. KG * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -26,7 +26,6 @@ #include <linux/kthread.h> #include <mostcore.h> -#include <networking.h> #include "dim2_hal.h" #include "dim2_hdm.h" #include "dim2_errors.h" @@ -39,11 +38,6 @@ #define MAX_BUF_SIZE_PACKET 2048 #define MAX_BUF_SIZE_STREAMING (8 * 1024) -/* command line parameter to select clock speed */ -static char *clock_speed; -module_param(clock_speed, charp, 0); -MODULE_PARM_DESC(clock_speed, "MediaLB Clock Speed"); - /* * The parameter representing the number of frames per sub-buffer for * synchronous channels. Valid values: [0 .. 6]. @@ -52,7 +46,7 @@ MODULE_PARM_DESC(clock_speed, "MediaLB Clock Speed"); * sub-buffer 1, 2, 4, 8, 16, 32, 64. */ static u8 fcnt = 4; /* (1 << fcnt) frames per subbuffer */ -module_param(fcnt, byte, 0); +module_param(fcnt, byte, 0000); MODULE_PARM_DESC(fcnt, "Num of frames per sub-buffer for sync channels as a power of 2"); static DEFINE_SPINLOCK(dim_lock); @@ -73,6 +67,7 @@ struct hdm_channel { char name[sizeof "caNNN"]; bool is_initialized; struct dim_channel ch; + u16 *reset_dbr_size; struct list_head pending_list; /* before dim_enqueue_buffer() */ struct list_head started_list; /* after dim_enqueue_buffer() */ enum most_channel_direction direction; @@ -85,7 +80,6 @@ struct hdm_channel { * @most_iface: most interface structure * @capabilities: an array of channel capability data * @io_base: I/O register base address - * @clk_speed: user selectable (through command line parameter) clock speed * @netinfo_task: thread to deliver network status * @netinfo_waitq: waitq for the thread to sleep * @deliver_netinfo: to identify whether network status received @@ -99,7 +93,6 @@ struct dim2_hdm { struct most_interface most_iface; char name[16 + sizeof "dim2-"]; void __iomem *io_base; - int clk_speed; struct task_struct *netinfo_task; wait_queue_head_t netinfo_waitq; int deliver_netinfo; @@ -107,6 +100,8 @@ struct dim2_hdm { unsigned char link_state; int atx_idx; struct medialb_bus bus; + void (*on_netinfo)(struct most_interface *, + unsigned char, unsigned char *); }; #define iface_to_hdm(iface) container_of(iface, struct dim2_hdm, most_iface) @@ -162,52 +157,25 @@ void dimcb_on_error(u8 error_id, const char *error_message) /** * startup_dim - initialize the dim2 interface * @pdev: platform device - * - * Get the value of command line parameter "clock_speed" if given or use the - * default value, enable the clock and PLL, and initialize the dim2 interface. */ static int startup_dim(struct platform_device *pdev) { struct dim2_hdm *dev = platform_get_drvdata(pdev); struct dim2_platform_data *pdata = pdev->dev.platform_data; u8 hal_ret; + int ret; - dev->clk_speed = -1; - - if (clock_speed) { - if (!strcmp(clock_speed, "256fs")) - dev->clk_speed = CLK_256FS; - else if (!strcmp(clock_speed, "512fs")) - dev->clk_speed = CLK_512FS; - else if (!strcmp(clock_speed, "1024fs")) - dev->clk_speed = CLK_1024FS; - else if (!strcmp(clock_speed, "2048fs")) - dev->clk_speed = CLK_2048FS; - else if (!strcmp(clock_speed, "3072fs")) - dev->clk_speed = CLK_3072FS; - else if (!strcmp(clock_speed, "4096fs")) - dev->clk_speed = CLK_4096FS; - else if (!strcmp(clock_speed, "6144fs")) - dev->clk_speed = CLK_6144FS; - else if (!strcmp(clock_speed, "8192fs")) - dev->clk_speed = CLK_8192FS; - } - - if (dev->clk_speed == -1) { - pr_info("Bad or missing clock speed parameter, using default value: 3072fs\n"); - dev->clk_speed = CLK_3072FS; - } else { - pr_info("Selected clock speed: %s\n", clock_speed); + if (!pdata) { + pr_err("missing platform data\n"); + return -EINVAL; } - if (pdata && pdata->init) { - int ret = pdata->init(pdata, dev->io_base, dev->clk_speed); - if (ret) - return ret; - } + ret = pdata->init ? pdata->init(pdata, dev->io_base) : 0; + if (ret) + return ret; pr_info("sync: num of frames per sub-buffer: %u\n", fcnt); - hal_ret = dim_startup(dev->io_base, dev->clk_speed, fcnt); + hal_ret = dim_startup(dev->io_base, pdata->clk_speed, fcnt); if (hal_ret != DIM_NO_ERROR) { pr_err("dim_startup failed: %d\n", hal_ret); if (pdata && pdata->destroy) @@ -287,8 +255,11 @@ static int deliver_netinfo_thread(void *data) if (dev->deliver_netinfo) { dev->deliver_netinfo--; - most_deliver_netinfo(&dev->most_iface, dev->link_state, - dev->mac_addrs); + if (dev->on_netinfo) { + dev->on_netinfo(&dev->most_iface, + dev->link_state, + dev->mac_addrs); + } } } @@ -529,6 +500,12 @@ static int configure_channel(struct most_interface *most_iface, int ch_idx, if (hdm_ch->is_initialized) return -EPERM; + /* do not reset if the property was set by user, see poison_channel */ + hdm_ch->reset_dbr_size = ccfg->dbr_size ? NULL : &ccfg->dbr_size; + + /* zero value is default dbr_size, see dim2 hal */ + hdm_ch->ch.dbr_size = ccfg->dbr_size; + switch (ccfg->data_type) { case MOST_CH_CONTROL: new_size = dim_norm_ctrl_async_buffer_size(buf_size); @@ -609,6 +586,7 @@ static int configure_channel(struct most_interface *most_iface, int ch_idx, dev->atx_idx = ch_idx; spin_unlock_irqrestore(&dim_lock, flags); + ccfg->dbr_size = hdm_ch->ch.dbr_size; return 0; } @@ -654,12 +632,18 @@ static int enqueue(struct most_interface *most_iface, int ch_idx, * Send a command to INIC which triggers retrieving of network info by means of * "Message exchange over MDP/MEP". Return 0 on success, negative on failure. */ -static void request_netinfo(struct most_interface *most_iface, int ch_idx) +static void request_netinfo(struct most_interface *most_iface, int ch_idx, + void (*on_netinfo)(struct most_interface *, + unsigned char, unsigned char *)) { struct dim2_hdm *dev = iface_to_hdm(most_iface); struct mbo *mbo; u8 *data; + dev->on_netinfo = on_netinfo; + if (!on_netinfo) + return; + if (dev->atx_idx < 0) { pr_err("Async Tx Not initialized\n"); return; @@ -718,10 +702,22 @@ static int poison_channel(struct most_interface *most_iface, int ch_idx) complete_all_mbos(&hdm_ch->started_list); complete_all_mbos(&hdm_ch->pending_list); + if (hdm_ch->reset_dbr_size) + *hdm_ch->reset_dbr_size = 0; return ret; } +static void *dma_alloc(struct mbo *mbo, u32 size) +{ + return dma_alloc_coherent(NULL, size, &mbo->bus_address, GFP_KERNEL); +} + +static void dma_free(struct mbo *mbo, u32 size) +{ + dma_free_coherent(NULL, size, mbo->virt_address, mbo->bus_address); +} + /* * dim2_probe - dim2 probe handler * @pdev: platform device structure @@ -751,8 +747,8 @@ static int dim2_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(&pdev->dev, "failed to get ahb0_int irq\n"); - return -ENODEV; + dev_err(&pdev->dev, "failed to get ahb0_int irq: %d\n", irq); + return irq; } ret = devm_request_irq(&pdev->dev, irq, dim2_ahb_isr, 0, @@ -764,8 +760,8 @@ static int dim2_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 1); if (irq < 0) { - dev_err(&pdev->dev, "failed to get mlb_int irq\n"); - return -ENODEV; + dev_err(&pdev->dev, "failed to get mlb_int irq: %d\n", irq); + return irq; } ret = devm_request_irq(&pdev->dev, irq, dim2_mlb_isr, 0, @@ -820,8 +816,11 @@ static int dim2_probe(struct platform_device *pdev) dev->most_iface.channel_vector = dev->capabilities; dev->most_iface.configure = configure_channel; dev->most_iface.enqueue = enqueue; + dev->most_iface.dma_alloc = dma_alloc; + dev->most_iface.dma_free = dma_free; dev->most_iface.poison_channel = poison_channel; dev->most_iface.request_netinfo = request_netinfo; + dev->most_iface.extra_attrs = DBR_ATTRS; kobj = most_register_interface(&dev->most_iface); if (IS_ERR(kobj)) { @@ -884,7 +883,7 @@ static int dim2_remove(struct platform_device *pdev) return 0; } -static struct platform_device_id dim2_id[] = { +static const struct platform_device_id dim2_id[] = { { "medialb_dim2" }, { }, /* Terminating entry */ }; diff --git a/driver/hdm-dim2/dim2_hdm.h b/driver/hdm-dim2/dim2_hdm.h index 4050e7c..e2a780f 100644 --- a/driver/hdm-dim2/dim2_hdm.h +++ b/driver/hdm-dim2/dim2_hdm.h @@ -1,7 +1,7 @@ /* * dim2_hdm.h - MediaLB DIM2 HDM Header * - * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG + * Copyright (C) 2015-2017, Microchip Technology Germany II GmbH & Co. KG * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,14 +14,15 @@ #ifndef DIM2_HDM_H #define DIM2_HDM_H +#include <linux/types.h> + struct device; /* platform dependent data for dim2 interface */ struct dim2_platform_data { - int (*init)(struct dim2_platform_data *pd, void __iomem *io_base, - int clk_speed); + int (*init)(struct dim2_platform_data *pd, void __iomem *io_base); void (*destroy)(struct dim2_platform_data *pd); - void *priv; + u8 clk_speed; }; #endif /* DIM2_HDM_H */ diff --git a/driver/hdm-dim2/dim2_reg.h b/driver/hdm-dim2/dim2_reg.h index 01fe499..f7d9fbc 100644 --- a/driver/hdm-dim2/dim2_reg.h +++ b/driver/hdm-dim2/dim2_reg.h @@ -141,6 +141,7 @@ enum { ADT1_CTRL_ASYNC_BD_MASK = DIM2_MASK(11), ADT1_ISOC_SYNC_BD_MASK = DIM2_MASK(13), + CAT_FCE_BIT = 14, CAT_MFE_BIT = 14, CAT_MT_BIT = 13, diff --git a/driver/hdm-i2c/Makefile b/driver/hdm-i2c/Makefile deleted file mode 100644 index 5117dbe..0000000 --- a/driver/hdm-i2c/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# Makefile -# - -SRC := $(shell pwd) - -obj-m += hdm_i2c.o -CFLAGS_hdm_i2c.o := -I$(src)/../include/ - -all: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules - -modules_install: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install - -clean: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) clean - diff --git a/driver/hdm-i2c/hdm_i2c.c b/driver/hdm-i2c/hdm_i2c.c index ba0263b..3caa599 100644 --- a/driver/hdm-i2c/hdm_i2c.c +++ b/driver/hdm-i2c/hdm_i2c.c @@ -1,7 +1,7 @@ /* * hdm_i2c.c - Hardware Dependent Module for I2C Interface * - * Copyright (C) 2013-2015, Microchip Technology Germany II GmbH & Co. KG + * Copyright (C) 2013-2017, Microchip Technology Germany II GmbH & Co. KG * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -17,7 +17,6 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/i2c.h> -#include <linux/sched.h> #include <linux/interrupt.h> #include <linux/err.h> @@ -35,33 +34,28 @@ enum { CH_RX, CH_TX, NUM_CHANNELS }; #define list_first_mbo(ptr) \ list_first_entry(ptr, struct mbo, list) -/* IRQ / Polling option */ -static bool polling_req; -module_param(polling_req, bool, S_IRUGO); -MODULE_PARM_DESC(polling_req, "Request Polling. Default = 0 (use irq)"); - -/* Polling Rate */ -static int scan_rate = 100; -module_param(scan_rate, int, 0644); -MODULE_PARM_DESC(scan_rate, "Polling rate in times/sec. Default = 100"); +static unsigned int polling_rate; +module_param(polling_rate, uint, 0644); +MODULE_PARM_DESC(polling_rate, "Polling rate [Hz]. Default = 0 (use IRQ)"); struct hdm_i2c { - bool is_open[NUM_CHANNELS]; - bool polling_mode; struct most_interface most_iface; struct most_channel_capability capabilities[NUM_CHANNELS]; struct i2c_client *client; struct rx { struct delayed_work dwork; - wait_queue_head_t waitq; struct list_head list; - struct mutex list_mutex; + bool int_disabled; + unsigned int delay; } rx; char name[64]; }; #define to_hdm(iface) container_of(iface, struct hdm_i2c, most_iface) +static irqreturn_t most_irq_handler(int, void *); +static void pending_rx_work(struct work_struct *); + /** * configure_channel - called from MOST core to configure a channel * @iface: interface the channel belongs to @@ -77,10 +71,11 @@ static int configure_channel(struct most_interface *most_iface, int ch_idx, struct most_channel_config *channel_config) { + int ret; struct hdm_i2c *dev = to_hdm(most_iface); + unsigned int delay, pr; BUG_ON(ch_idx < 0 || ch_idx >= NUM_CHANNELS); - BUG_ON(dev->is_open[ch_idx]); if (channel_config->data_type != MOST_CH_CONTROL) { pr_err("bad data type for channel %d\n", ch_idx); @@ -92,11 +87,27 @@ static int configure_channel(struct most_interface *most_iface, return -EPERM; } - if ((channel_config->direction == MOST_CH_RX) && (dev->polling_mode)) { - schedule_delayed_work(&dev->rx.dwork, - msecs_to_jiffies(MSEC_PER_SEC / 4)); + if (channel_config->direction == MOST_CH_RX) { + if (!polling_rate) { + if (dev->client->irq <= 0) { + pr_err("bad irq: %d\n", dev->client->irq); + return -ENOENT; + } + dev->rx.int_disabled = false; + ret = request_irq(dev->client->irq, most_irq_handler, 0, + dev->client->name, dev); + if (ret) { + pr_err("request_irq(%d) failed: %d\n", + dev->client->irq, ret); + return ret; + } + } else { + delay = msecs_to_jiffies(MSEC_PER_SEC / polling_rate); + dev->rx.delay = delay ? delay : 1; + pr = MSEC_PER_SEC / jiffies_to_msecs(dev->rx.delay); + pr_info("polling rate is %u Hz\n", pr); + } } - dev->is_open[ch_idx] = true; return 0; } @@ -119,14 +130,17 @@ static int enqueue(struct most_interface *most_iface, int ret; BUG_ON(ch_idx < 0 || ch_idx >= NUM_CHANNELS); - BUG_ON(!dev->is_open[ch_idx]); if (ch_idx == CH_RX) { /* RX */ - mutex_lock(&dev->rx.list_mutex); + if (!polling_rate) + disable_irq(dev->client->irq); + cancel_delayed_work_sync(&dev->rx.dwork); list_add_tail(&mbo->list, &dev->rx.list); - mutex_unlock(&dev->rx.list_mutex); - wake_up_interruptible(&dev->rx.waitq); + if (dev->rx.int_disabled || polling_rate) + pending_rx_work(&dev->rx.dwork.work); + if (!polling_rate) + enable_irq(dev->client->irq); } else { /* TX */ ret = i2c_master_send(dev->client, mbo->virt_address, @@ -161,41 +175,30 @@ static int poison_channel(struct most_interface *most_iface, struct mbo *mbo; BUG_ON(ch_idx < 0 || ch_idx >= NUM_CHANNELS); - BUG_ON(!dev->is_open[ch_idx]); - - dev->is_open[ch_idx] = false; if (ch_idx == CH_RX) { - mutex_lock(&dev->rx.list_mutex); + if (!polling_rate) + free_irq(dev->client->irq, dev); + cancel_delayed_work_sync(&dev->rx.dwork); + while (!list_empty(&dev->rx.list)) { mbo = list_first_mbo(&dev->rx.list); list_del(&mbo->list); - mutex_unlock(&dev->rx.list_mutex); mbo->processed_length = 0; mbo->status = MBO_E_CLOSE; mbo->complete(mbo); - - mutex_lock(&dev->rx.list_mutex); } - mutex_unlock(&dev->rx.list_mutex); - wake_up_interruptible(&dev->rx.waitq); } return 0; } -static void request_netinfo(struct most_interface *most_iface, - int ch_idx) -{ - pr_info("request_netinfo()\n"); -} - static void do_rx_work(struct hdm_i2c *dev) { struct mbo *mbo; unsigned char msg[MAX_BUF_SIZE_CONTROL]; - int ret, ch_idx = CH_RX; + int ret; u16 pml, data_size; /* Read PML (2 bytes) */ @@ -218,32 +221,8 @@ static void do_rx_work(struct hdm_i2c *dev) return; } - for (;;) { - /* Conditions to wait for: poisoned channel or free buffer - * available for reading - */ - if (wait_event_interruptible(dev->rx.waitq, - !dev->is_open[ch_idx] || - !list_empty(&dev->rx.list))) { - pr_err("wait_event_interruptible() failed\n"); - return; - } - - if (!dev->is_open[ch_idx]) - return; - - mutex_lock(&dev->rx.list_mutex); - - /* list may be empty if poison or remove is called */ - if (!list_empty(&dev->rx.list)) - break; - - mutex_unlock(&dev->rx.list_mutex); - } - mbo = list_first_mbo(&dev->rx.list); list_del(&mbo->list); - mutex_unlock(&dev->rx.list_mutex); mbo->processed_length = min(data_size, mbo->buffer_length); memcpy(mbo->virt_address, msg, mbo->processed_length); @@ -261,14 +240,15 @@ static void pending_rx_work(struct work_struct *work) { struct hdm_i2c *dev = container_of(work, struct hdm_i2c, rx.dwork.work); + if (list_empty(&dev->rx.list)) + return; + do_rx_work(dev); - if (dev->polling_mode) { - if (dev->is_open[CH_RX]) - schedule_delayed_work(&dev->rx.dwork, - msecs_to_jiffies(MSEC_PER_SEC - / scan_rate)); + if (polling_rate) { + schedule_delayed_work(&dev->rx.dwork, dev->rx.delay); } else { + dev->rx.int_disabled = false; enable_irq(dev->client->irq); } } @@ -296,7 +276,7 @@ static irqreturn_t most_irq_handler(int irq, void *_dev) struct hdm_i2c *dev = _dev; disable_irq_nosync(irq); - + dev->rx.int_disabled = true; schedule_delayed_work(&dev->rx.dwork, 0); return IRQ_HANDLED; @@ -314,7 +294,7 @@ static irqreturn_t most_irq_handler(int irq, void *_dev) static int i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct hdm_i2c *dev; - int ret, i; + int i; struct kobject *kobj; dev = kzalloc(sizeof(*dev), GFP_KERNEL); @@ -326,7 +306,6 @@ static int i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) client->adapter->nr, client->addr); for (i = 0; i < NUM_CHANNELS; i++) { - dev->is_open[i] = false; dev->capabilities[i].data_type = MOST_CH_CONTROL; dev->capabilities[i].num_buffers_packet = MAX_BUFFERS_CONTROL; dev->capabilities[i].buffer_size_packet = MAX_BUF_SIZE_CONTROL; @@ -343,11 +322,8 @@ static int i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) dev->most_iface.configure = configure_channel; dev->most_iface.enqueue = enqueue; dev->most_iface.poison_channel = poison_channel; - dev->most_iface.request_netinfo = request_netinfo; INIT_LIST_HEAD(&dev->rx.list); - mutex_init(&dev->rx.list_mutex); - init_waitqueue_head(&dev->rx.waitq); INIT_DELAYED_WORK(&dev->rx.dwork, pending_rx_work); @@ -361,21 +337,6 @@ static int i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) return PTR_ERR(kobj); } - dev->polling_mode = polling_req || client->irq <= 0; - if (!dev->polling_mode) { - pr_info("Requesting IRQ: %d\n", client->irq); - ret = request_irq(client->irq, most_irq_handler, 0, - client->name, dev); - if (ret) { - pr_info("IRQ request failed: %d, falling back to polling\n", - ret); - dev->polling_mode = true; - } - } - - if (dev->polling_mode) - pr_info("Using polling at rate: %d times/sec\n", scan_rate); - return 0; } @@ -390,17 +351,8 @@ static int i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) static int i2c_remove(struct i2c_client *client) { struct hdm_i2c *dev = i2c_get_clientdata(client); - int i; - - if (!dev->polling_mode) - free_irq(client->irq, dev); most_deregister_interface(&dev->most_iface); - - for (i = 0 ; i < NUM_CHANNELS; i++) - if (dev->is_open[i]) - poison_channel(&dev->most_iface, i); - cancel_delayed_work_sync(&dev->rx.dwork); kfree(dev); return 0; @@ -424,7 +376,6 @@ static struct i2c_driver i2c_driver = { module_i2c_driver(i2c_driver); -MODULE_AUTHOR("Jain Roy Ambi <JainRoy.Ambi@microchip.com>"); MODULE_AUTHOR("Andrey Shvetsov <andrey.shvetsov@k2l.de>"); MODULE_DESCRIPTION("I2C Hardware Dependent Module"); MODULE_LICENSE("GPL"); diff --git a/driver/hdm-usb/Makefile b/driver/hdm-usb/Makefile deleted file mode 100644 index 28ab832..0000000 --- a/driver/hdm-usb/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# Makefile -# - -SRC := $(shell pwd) - -obj-m += hdm_usb.o -CFLAGS_hdm_usb.o := -I$(src)/../include/ - -all: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules - -modules_install: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install - -clean: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) clean - diff --git a/driver/hdm-usb/hdm_usb.c b/driver/hdm-usb/hdm_usb.c index 3433646..5b0af88 100644 --- a/driver/hdm-usb/hdm_usb.c +++ b/driver/hdm-usb/hdm_usb.c @@ -30,7 +30,6 @@ #include <linux/etherdevice.h> #include <linux/uaccess.h> #include "mostcore.h" -#include "networking.h" #define USB_MTU 512 #define NO_ISOCHRONOUS_URB 0 @@ -126,6 +125,8 @@ struct most_dev { struct mutex io_mutex; struct timer_list link_stat_timer; struct work_struct poll_work_obj; + void (*on_netinfo)(struct most_interface *, unsigned char, + unsigned char *); }; #define to_mdev(d) container_of(d, struct most_dev, iface) @@ -145,7 +146,7 @@ static void wq_netinfo(struct work_struct *wq_obj); static inline int drci_rd_reg(struct usb_device *dev, u16 reg, u16 *buf) { int retval; - u16 *dma_buf = kzalloc(sizeof(u16), GFP_KERNEL); + __le16 *dma_buf = kzalloc(sizeof(*dma_buf), GFP_KERNEL); u8 req_type = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE; if (!dma_buf) @@ -154,7 +155,7 @@ static inline int drci_rd_reg(struct usb_device *dev, u16 reg, u16 *buf) retval = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), DRCI_READ_REQ, req_type, 0x0000, - reg, dma_buf, sizeof(u16), 5 * HZ); + reg, dma_buf, sizeof(*dma_buf), 5 * HZ); *buf = le16_to_cpu(*dma_buf); kfree(dma_buf); @@ -281,7 +282,6 @@ static int hdm_add_padding(struct most_dev *mdev, int channel, struct mbo *mbo) struct most_channel_config *conf = &mdev->conf[channel]; unsigned int frame_size = get_stream_frame_size(conf); unsigned int j, num_frames; - u16 rd_addr, wr_addr; if (!frame_size) return -EIO; @@ -293,13 +293,10 @@ static int hdm_add_padding(struct most_dev *mdev, int channel, struct mbo *mbo) return -EIO; } - for (j = 1; j < num_frames; j++) { - wr_addr = (num_frames - j) * USB_MTU; - rd_addr = (num_frames - j) * frame_size; - memmove(mbo->virt_address + wr_addr, - mbo->virt_address + rd_addr, + for (j = num_frames - 1; j > 0; j--) + memmove(mbo->virt_address + j * USB_MTU, + mbo->virt_address + j * frame_size, frame_size); - } mbo->buffer_length = num_frames * USB_MTU; return 0; } @@ -490,7 +487,7 @@ static void hdm_write_completion(struct urb *urb) * disconnect. In the interval before the hub driver starts disconnect * processing, devices may receive such fault reports for every request. * - * See <https://www.kernel.org/doc/Documentation/usb/error-codes.txt> + * See <https://www.kernel.org/doc/Documentation/driver-api/usb/error-codes.rst> */ static void hdm_read_completion(struct urb *urb) { @@ -629,19 +626,42 @@ _error: return retval; } +static void *hdm_dma_alloc(struct mbo *mbo, u32 size) +{ + struct most_dev *mdev = to_mdev(mbo->ifp); + + return usb_alloc_coherent(mdev->usb_device, size, GFP_KERNEL, + &mbo->bus_address); +} + +static void hdm_dma_free(struct mbo *mbo, u32 size) +{ + struct most_dev *mdev = to_mdev(mbo->ifp); + + usb_free_coherent(mdev->usb_device, size, mbo->virt_address, + mbo->bus_address); +} + /** * hdm_configure_channel - receive channel configuration from core * @iface: interface * @channel: channel ID * @conf: structure that holds the configuration information + * + * The attached network interface controller (NIC) supports a padding mode + * to avoid short packets on USB, hence increasing the performance due to a + * lower interrupt load. This mode is default for synchronous data and can + * be switched on for isochronous data. In case padding is active the + * driver needs to know the frame size of the payload in order to calculate + * the number of bytes it needs to pad when transmitting or to cut off when + * receiving data. + * */ static int hdm_configure_channel(struct most_interface *iface, int channel, struct most_channel_config *conf) { unsigned int num_frames; unsigned int frame_size; - unsigned int temp_size; - unsigned int tail_space; struct most_dev *mdev = to_mdev(iface); struct device *dev = &mdev->usb_device->dev; @@ -667,11 +687,15 @@ static int hdm_configure_channel(struct most_interface *iface, int channel, !(conf->data_type == MOST_CH_ISOC && conf->packets_per_xact != 0xFF)) { mdev->padding_active[channel] = false; + /* + * Since the NIC's padding mode is not going to be + * used, we can skip the frame size calculations and + * move directly on to exit. + */ goto exit; } mdev->padding_active[channel] = true; - temp_size = conf->buffer_size; frame_size = get_stream_frame_size(conf); if (frame_size == 0 || frame_size > USB_MTU) { @@ -679,25 +703,19 @@ static int hdm_configure_channel(struct most_interface *iface, int channel, return -EINVAL; } + num_frames = conf->buffer_size / frame_size; + if (conf->buffer_size % frame_size) { - u16 tmp_val; - - tmp_val = conf->buffer_size / frame_size; - conf->buffer_size = tmp_val * frame_size; - dev_notice(dev, - "Channel %d - rounding buffer size to %d bytes, channel config says %d bytes\n", - channel, - conf->buffer_size, - temp_size); - } + u16 old_size = conf->buffer_size; - num_frames = conf->buffer_size / frame_size; - tail_space = num_frames * (USB_MTU - frame_size); - temp_size += tail_space; + conf->buffer_size = num_frames * frame_size; + dev_warn(dev, "%s: fixed buffer size (%d -> %d)\n", + mdev->suffix[channel], old_size, conf->buffer_size); + } /* calculate extra length to comply w/ HW padding */ - conf->extra_len = (DIV_ROUND_UP(temp_size, USB_MTU) * USB_MTU) - - conf->buffer_size; + conf->extra_len = num_frames * (USB_MTU - frame_size); + exit: mdev->conf[channel] = *conf; if (conf->data_type == MOST_CH_ASYNC) { @@ -718,12 +736,19 @@ exit: * polls for the NI state of the INIC every 2 seconds. * */ -static void hdm_request_netinfo(struct most_interface *iface, int channel) +static void hdm_request_netinfo(struct most_interface *iface, int channel, + void (*on_netinfo)(struct most_interface *, + unsigned char, + unsigned char *)) { struct most_dev *mdev; BUG_ON(!iface); mdev = to_mdev(iface); + mdev->on_netinfo = on_netinfo; + if (!on_netinfo) + return; + mdev->link_stat_timer.expires = jiffies + HZ; mod_timer(&mdev->link_stat_timer, mdev->link_stat_timer.expires); } @@ -785,7 +810,8 @@ static void wq_netinfo(struct work_struct *wq_obj) hw_addr[4] = lo >> 8; hw_addr[5] = lo; - most_deliver_netinfo(&mdev->iface, link, hw_addr); + if (mdev->on_netinfo) + mdev->on_netinfo(&mdev->iface, link, hw_addr); } /** @@ -822,7 +848,7 @@ static const struct file_operations hdm_usb_fops = { /** * usb_device_id - ID table for HCD device probing */ -static struct usb_device_id usbid[] = { +static const struct usb_device_id usbid[] = { { USB_DEVICE(USB_VENDOR_ID_SMSC, USB_DEV_ID_BRDG), }, { USB_DEVICE(USB_VENDOR_ID_SMSC, USB_DEV_ID_OS81118), }, { USB_DEVICE(USB_VENDOR_ID_SMSC, USB_DEV_ID_OS81119), }, @@ -832,15 +858,15 @@ static struct usb_device_id usbid[] = { #define MOST_DCI_RO_ATTR(_name) \ struct most_dci_attribute most_dci_attr_##_name = \ - __ATTR(_name, S_IRUGO, show_value, NULL) + __ATTR(_name, 0444, show_value, NULL) #define MOST_DCI_ATTR(_name) \ struct most_dci_attribute most_dci_attr_##_name = \ - __ATTR(_name, S_IRUGO | S_IWUSR, show_value, store_value) + __ATTR(_name, 0644, show_value, store_value) #define MOST_DCI_WO_ATTR(_name) \ struct most_dci_attribute most_dci_attr_##_name = \ - __ATTR(_name, S_IWUSR, NULL, store_value) + __ATTR(_name, 0200, NULL, store_value) /** * struct most_dci_attribute - to access the attributes of a dci object @@ -1004,7 +1030,7 @@ static ssize_t store_value(struct most_dci_obj *dci_obj, err = drci_wr_reg(usb_dev, dci_obj->reg_addr, val); else if (!strcmp(name, "sync_ep")) err = start_sync_ep(usb_dev, val); - else if (!get_static_reg_addr(ro_regs, name, ®_addr)) + else if (!get_static_reg_addr(rw_regs, name, ®_addr)) err = drci_wr_reg(usb_dev, reg_addr, val); else return -EFAULT; @@ -1135,13 +1161,17 @@ hdm_probe(struct usb_interface *interface, const struct usb_device_id *id) mdev->link_stat_timer.expires = jiffies + (2 * HZ); mdev->iface.mod = hdm_usb_fops.owner; + mdev->iface.dev = &interface->dev; mdev->iface.interface = ITYPE_USB; mdev->iface.configure = hdm_configure_channel; mdev->iface.request_netinfo = hdm_request_netinfo; mdev->iface.enqueue = hdm_enqueue; mdev->iface.poison_channel = hdm_poison_channel; + mdev->iface.dma_alloc = hdm_dma_alloc; + mdev->iface.dma_free = hdm_dma_free; mdev->iface.description = mdev->description; mdev->iface.num_channels = num_endpoints; + mdev->iface.extra_attrs = XACT_ATTRS; snprintf(mdev->description, sizeof(mdev->description), "usb_device %d-%s:%d.%d", @@ -1291,25 +1321,7 @@ static struct usb_driver hdm_usb = { .disconnect = hdm_disconnect, }; -static int __init hdm_usb_init(void) -{ - pr_info("hdm_usb_init()\n"); - if (usb_register(&hdm_usb)) { - pr_err("could not register hdm_usb driver\n"); - return -EIO; - } - - return 0; -} - -static void __exit hdm_usb_exit(void) -{ - pr_info("hdm_usb_exit()\n"); - usb_deregister(&hdm_usb); -} - -module_init(hdm_usb_init); -module_exit(hdm_usb_exit); +module_usb_driver(hdm_usb); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Gromm <christian.gromm@microchip.com>"); MODULE_DESCRIPTION("HDM_4_USB"); diff --git a/driver/include/mostcore.h b/driver/include/mostcore.h index 5f8339b..dc87121 100644 --- a/driver/include/mostcore.h +++ b/driver/include/mostcore.h @@ -23,8 +23,9 @@ #define __MOST_CORE_H__ #include <linux/types.h> +#include <linux/kobject.h> /* struct kobj_type */ +#include <linux/sysfs.h> /* struct attribute */ -struct kobject; struct module; /** @@ -141,6 +142,7 @@ struct most_channel_config { u16 extra_len; u16 subbuffer_size; u16 packets_per_xact; + u16 dbr_size; }; /* @@ -233,20 +235,31 @@ struct mbo { * The callback returns a negative value on error, otherwise 0. * @request_netinfo: triggers retrieving of network info from the HDM by * means of "Message exchange over MDP/MEP" + * The call of the function request_netinfo with the parameter on_netinfo as + * NULL prohibits use of the previously obtained function pointer. * @priv Private field used by mostcore to store context information. */ struct most_interface { struct module *mod; + struct device *dev; enum most_interface_type interface; const char *description; int num_channels; struct most_channel_capability *channel_vector; + void *(*dma_alloc)(struct mbo *mbo, u32 size); + void (*dma_free)(struct mbo *mbo, u32 size); int (*configure)(struct most_interface *iface, int channel_idx, struct most_channel_config *channel_config); int (*enqueue)(struct most_interface *iface, int channel_idx, struct mbo *mbo); int (*poison_channel)(struct most_interface *iface, int channel_idx); - void (*request_netinfo)(struct most_interface *iface, int channel_idx); + void (*request_netinfo)(struct most_interface *iface, int channel_idx, + void (*on_netinfo)(struct most_interface *iface, + unsigned char link_stat, + unsigned char *mac_addr)); + struct attribute *attrs[14]; + struct kobj_type ktype; + enum { NONE_ATTRS /* default */, XACT_ATTRS, DBR_ATTRS } extra_attrs; void *priv; }; diff --git a/driver/include/networking.h b/driver/include/networking.h deleted file mode 100644 index 6f346d4..0000000 --- a/driver/include/networking.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Networking AIM - Networking Application Interface Module for MostCore - * - * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * This file is licensed under GPLv2. - */ -#ifndef _NETWORKING_H_ -#define _NETWORKING_H_ - -#include "mostcore.h" - -void most_deliver_netinfo(struct most_interface *iface, - unsigned char link_stat, unsigned char *mac_addr); - -#endif diff --git a/driver/mostcore/Makefile b/driver/mostcore/Makefile deleted file mode 100644 index cffcd8e..0000000 --- a/driver/mostcore/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# Makefile -# - -SRC := $(shell pwd) - -obj-m := mostcore.o -mostcore-y := core.o -CFLAGS_core.o := -I$(src)/../include/ - -all: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules - -modules_install: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install - -clean: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) clean - diff --git a/driver/mostcore/core.c b/driver/mostcore/core.c index 4c580d1..4d51441 100644 --- a/driver/mostcore/core.c +++ b/driver/mostcore/core.c @@ -82,7 +82,7 @@ struct most_inst_obj { static const struct { int most_ch_data_type; - char *name; + const char *name; } ch_data_type[] = { { MOST_CH_CONTROL, "control\n" }, { MOST_CH_ASYNC, "async\n" }, @@ -127,10 +127,6 @@ struct most_c_attr { #define to_channel_attr(a) container_of(a, struct most_c_attr, attr) -#define MOST_CHNL_ATTR(_name, _mode, _show, _store) \ - struct most_c_attr most_chnl_attr_##_name = \ - __ATTR(_name, _mode, _show, _store) - /** * channel_attr_show - show function of channel object * @kobj: pointer to its kobject @@ -184,8 +180,10 @@ static void most_free_mbo_coherent(struct mbo *mbo) struct most_c_obj *c = mbo->context; u16 const coherent_buf_size = c->cfg.buffer_size + c->cfg.extra_len; - dma_free_coherent(NULL, coherent_buf_size, mbo->virt_address, - mbo->bus_address); + if (c->iface->dma_free) + c->iface->dma_free(mbo, coherent_buf_size); + else + kfree(mbo->virt_address); kfree(mbo); if (atomic_sub_and_test(1, &c->mbo_ref)) complete(&c->cleanup); @@ -256,7 +254,7 @@ static void most_channel_release(struct kobject *kobj) kfree(c); } -static ssize_t show_available_directions(struct most_c_obj *c, +static ssize_t available_directions_show(struct most_c_obj *c, struct most_c_attr *attr, char *buf) { @@ -271,7 +269,7 @@ static ssize_t show_available_directions(struct most_c_obj *c, return strlen(buf); } -static ssize_t show_available_datatypes(struct most_c_obj *c, +static ssize_t available_datatypes_show(struct most_c_obj *c, struct most_c_attr *attr, char *buf) { @@ -290,10 +288,9 @@ static ssize_t show_available_datatypes(struct most_c_obj *c, return strlen(buf); } -static -ssize_t show_number_of_packet_buffers(struct most_c_obj *c, - struct most_c_attr *attr, - char *buf) +static ssize_t number_of_packet_buffers_show(struct most_c_obj *c, + struct most_c_attr *attr, + char *buf) { unsigned int i = c->channel_id; @@ -301,10 +298,9 @@ ssize_t show_number_of_packet_buffers(struct most_c_obj *c, c->iface->channel_vector[i].num_buffers_packet); } -static -ssize_t show_number_of_stream_buffers(struct most_c_obj *c, - struct most_c_attr *attr, - char *buf) +static ssize_t number_of_stream_buffers_show(struct most_c_obj *c, + struct most_c_attr *attr, + char *buf) { unsigned int i = c->channel_id; @@ -312,10 +308,9 @@ ssize_t show_number_of_stream_buffers(struct most_c_obj *c, c->iface->channel_vector[i].num_buffers_streaming); } -static -ssize_t show_size_of_packet_buffer(struct most_c_obj *c, - struct most_c_attr *attr, - char *buf) +static ssize_t size_of_packet_buffer_show(struct most_c_obj *c, + struct most_c_attr *attr, + char *buf) { unsigned int i = c->channel_id; @@ -323,10 +318,9 @@ ssize_t show_size_of_packet_buffer(struct most_c_obj *c, c->iface->channel_vector[i].buffer_size_packet); } -static -ssize_t show_size_of_stream_buffer(struct most_c_obj *c, - struct most_c_attr *attr, - char *buf) +static ssize_t size_of_stream_buffer_show(struct most_c_obj *c, + struct most_c_attr *attr, + char *buf) { unsigned int i = c->channel_id; @@ -334,32 +328,21 @@ ssize_t show_size_of_stream_buffer(struct most_c_obj *c, c->iface->channel_vector[i].buffer_size_streaming); } -static ssize_t show_channel_starving(struct most_c_obj *c, +static ssize_t channel_starving_show(struct most_c_obj *c, struct most_c_attr *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", c->is_starving); } -#define create_show_channel_attribute(val) \ - static MOST_CHNL_ATTR(val, S_IRUGO, show_##val, NULL) - -create_show_channel_attribute(available_directions); -create_show_channel_attribute(available_datatypes); -create_show_channel_attribute(number_of_packet_buffers); -create_show_channel_attribute(number_of_stream_buffers); -create_show_channel_attribute(size_of_stream_buffer); -create_show_channel_attribute(size_of_packet_buffer); -create_show_channel_attribute(channel_starving); - -static ssize_t show_set_number_of_buffers(struct most_c_obj *c, +static ssize_t set_number_of_buffers_show(struct most_c_obj *c, struct most_c_attr *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", c->cfg.num_buffers); } -static ssize_t store_set_number_of_buffers(struct most_c_obj *c, +static ssize_t set_number_of_buffers_store(struct most_c_obj *c, struct most_c_attr *attr, const char *buf, size_t count) @@ -371,14 +354,14 @@ static ssize_t store_set_number_of_buffers(struct most_c_obj *c, return count; } -static ssize_t show_set_buffer_size(struct most_c_obj *c, +static ssize_t set_buffer_size_show(struct most_c_obj *c, struct most_c_attr *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", c->cfg.buffer_size); } -static ssize_t store_set_buffer_size(struct most_c_obj *c, +static ssize_t set_buffer_size_store(struct most_c_obj *c, struct most_c_attr *attr, const char *buf, size_t count) @@ -390,7 +373,7 @@ static ssize_t store_set_buffer_size(struct most_c_obj *c, return count; } -static ssize_t show_set_direction(struct most_c_obj *c, +static ssize_t set_direction_show(struct most_c_obj *c, struct most_c_attr *attr, char *buf) { @@ -401,7 +384,7 @@ static ssize_t show_set_direction(struct most_c_obj *c, return snprintf(buf, PAGE_SIZE, "unconfigured\n"); } -static ssize_t store_set_direction(struct most_c_obj *c, +static ssize_t set_direction_store(struct most_c_obj *c, struct most_c_attr *attr, const char *buf, size_t count) @@ -421,7 +404,7 @@ static ssize_t store_set_direction(struct most_c_obj *c, return count; } -static ssize_t show_set_datatype(struct most_c_obj *c, +static ssize_t set_datatype_show(struct most_c_obj *c, struct most_c_attr *attr, char *buf) { @@ -434,7 +417,7 @@ static ssize_t show_set_datatype(struct most_c_obj *c, return snprintf(buf, PAGE_SIZE, "unconfigured\n"); } -static ssize_t store_set_datatype(struct most_c_obj *c, +static ssize_t set_datatype_store(struct most_c_obj *c, struct most_c_attr *attr, const char *buf, size_t count) @@ -455,14 +438,14 @@ static ssize_t store_set_datatype(struct most_c_obj *c, return count; } -static ssize_t show_set_subbuffer_size(struct most_c_obj *c, +static ssize_t set_subbuffer_size_show(struct most_c_obj *c, struct most_c_attr *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", c->cfg.subbuffer_size); } -static ssize_t store_set_subbuffer_size(struct most_c_obj *c, +static ssize_t set_subbuffer_size_store(struct most_c_obj *c, struct most_c_attr *attr, const char *buf, size_t count) @@ -474,14 +457,14 @@ static ssize_t store_set_subbuffer_size(struct most_c_obj *c, return count; } -static ssize_t show_set_packets_per_xact(struct most_c_obj *c, +static ssize_t set_packets_per_xact_show(struct most_c_obj *c, struct most_c_attr *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", c->cfg.packets_per_xact); } -static ssize_t store_set_packets_per_xact(struct most_c_obj *c, +static ssize_t set_packets_per_xact_store(struct most_c_obj *c, struct most_c_attr *attr, const char *buf, size_t count) @@ -493,45 +476,41 @@ static ssize_t store_set_packets_per_xact(struct most_c_obj *c, return count; } -#define create_channel_attribute(value) \ - static MOST_CHNL_ATTR(value, S_IRUGO | S_IWUSR, \ - show_##value, \ - store_##value) +static ssize_t set_dbr_size_show(struct most_c_obj *c, + struct most_c_attr *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", c->cfg.dbr_size); +} -create_channel_attribute(set_buffer_size); -create_channel_attribute(set_number_of_buffers); -create_channel_attribute(set_direction); -create_channel_attribute(set_datatype); -create_channel_attribute(set_subbuffer_size); -create_channel_attribute(set_packets_per_xact); +static ssize_t set_dbr_size_store(struct most_c_obj *c, + struct most_c_attr *attr, const char *buf, + size_t count) +{ + int ret = kstrtou16(buf, 0, &c->cfg.dbr_size); -/** - * most_channel_def_attrs - array of default attributes of channel object - */ -static struct attribute *most_channel_def_attrs[] = { - &most_chnl_attr_available_directions.attr, - &most_chnl_attr_available_datatypes.attr, - &most_chnl_attr_number_of_packet_buffers.attr, - &most_chnl_attr_number_of_stream_buffers.attr, - &most_chnl_attr_size_of_packet_buffer.attr, - &most_chnl_attr_size_of_stream_buffer.attr, - &most_chnl_attr_set_number_of_buffers.attr, - &most_chnl_attr_set_buffer_size.attr, - &most_chnl_attr_set_direction.attr, - &most_chnl_attr_set_datatype.attr, - &most_chnl_attr_set_subbuffer_size.attr, - &most_chnl_attr_set_packets_per_xact.attr, - &most_chnl_attr_channel_starving.attr, - NULL, -}; + if (ret) + return ret; + return count; +} -static struct kobj_type most_channel_ktype = { - .sysfs_ops = &most_channel_sysfs_ops, - .release = most_channel_release, - .default_attrs = most_channel_def_attrs, +static struct most_c_attr common_c_attrs[] = { + __ATTR_RO(available_directions), + __ATTR_RO(available_datatypes), + __ATTR_RO(number_of_packet_buffers), + __ATTR_RO(number_of_stream_buffers), + __ATTR_RO(size_of_stream_buffer), + __ATTR_RO(size_of_packet_buffer), + __ATTR_RO(channel_starving), + __ATTR_RW(set_buffer_size), + __ATTR_RW(set_number_of_buffers), + __ATTR_RW(set_direction), + __ATTR_RW(set_datatype), + __ATTR_RW(set_subbuffer_size), }; -static struct kset *most_channel_kset; +static struct most_c_attr xact_c_attr = __ATTR_RW(set_packets_per_xact); + +static struct most_c_attr dbr_c_attr = __ATTR_RW(set_dbr_size); /** * create_most_c_obj - allocates a channel object @@ -541,8 +520,8 @@ static struct kset *most_channel_kset; * This create a channel object and registers it with sysfs. * Returns a pointer to the object or NULL when something went wrong. */ -static struct most_c_obj * -create_most_c_obj(const char *name, struct kobject *parent) +static struct most_c_obj *create_most_c_obj( + struct kobj_type *ktype, const char *name, struct kobject *parent) { struct most_c_obj *c; int retval; @@ -550,9 +529,7 @@ create_most_c_obj(const char *name, struct kobject *parent) c = kzalloc(sizeof(*c), GFP_KERNEL); if (!c) return NULL; - c->kobj.kset = most_channel_kset; - retval = kobject_init_and_add(&c->kobj, &most_channel_ktype, parent, - "%s", name); + retval = kobject_init_and_add(&c->kobj, ktype, parent, "%s", name); if (retval) { kobject_put(&c->kobj); return NULL; @@ -564,9 +541,6 @@ create_most_c_obj(const char *name, struct kobject *parent) /* ___ ___ * ___I N S T A N C E___ */ -#define MOST_INST_ATTR(_name, _mode, _show, _store) \ - struct most_inst_attribute most_inst_attr_##_name = \ - __ATTR(_name, _mode, _show, _store) static struct list_head instance_list; @@ -654,7 +628,7 @@ static void most_inst_release(struct kobject *kobj) kfree(inst); } -static ssize_t show_description(struct most_inst_obj *instance_obj, +static ssize_t description_show(struct most_inst_obj *instance_obj, struct most_inst_attribute *attr, char *buf) { @@ -662,7 +636,7 @@ static ssize_t show_description(struct most_inst_obj *instance_obj, instance_obj->iface->description); } -static ssize_t show_interface(struct most_inst_obj *instance_obj, +static ssize_t interface_show(struct most_inst_obj *instance_obj, struct most_inst_attribute *attr, char *buf) { @@ -689,11 +663,11 @@ static ssize_t show_interface(struct most_inst_obj *instance_obj, return snprintf(buf, PAGE_SIZE, "unknown\n"); } -#define create_inst_attribute(value) \ - static MOST_INST_ATTR(value, S_IRUGO, show_##value, NULL) +static struct most_inst_attribute most_inst_attr_description = + __ATTR_RO(description); -create_inst_attribute(description); -create_inst_attribute(interface); +static struct most_inst_attribute most_inst_attr_interface = + __ATTR_RO(interface); static struct attribute *most_inst_def_attrs[] = { &most_inst_attr_description.attr, @@ -849,9 +823,9 @@ static void most_aim_release(struct kobject *kobj) kfree(aim_obj); } -static ssize_t show_add_link(struct most_aim_obj *aim_obj, - struct most_aim_attribute *attr, - char *buf) +static ssize_t links_show(struct most_aim_obj *aim_obj, + struct most_aim_attribute *attr, + char *buf) { struct most_c_obj *c; struct most_inst_obj *i; @@ -945,7 +919,7 @@ most_c_obj *get_channel_by_name(char *mdev, char *mdev_ch) } /** - * store_add_link - store() function for add_link attribute + * add_link_store - store() function for add_link attribute * @aim_obj: pointer to AIM object * @attr: its attributes * @buf: buffer @@ -966,7 +940,7 @@ most_c_obj *get_channel_by_name(char *mdev, char *mdev_ch) * (1) would create the device node /dev/my_rxchannel * (2) would create the device node /dev/mdev1-ep81 */ -static ssize_t store_add_link(struct most_aim_obj *aim_obj, +static ssize_t add_link_store(struct most_aim_obj *aim_obj, struct most_aim_attribute *attr, const char *buf, size_t len) @@ -1015,11 +989,8 @@ static ssize_t store_add_link(struct most_aim_obj *aim_obj, return len; } -static struct most_aim_attribute most_aim_attr_add_link = - __ATTR(add_link, S_IRUGO | S_IWUSR, show_add_link, store_add_link); - /** - * store_remove_link - store function for remove_link attribute + * remove_link_store - store function for remove_link attribute * @aim_obj: pointer to AIM object * @attr: its attributes * @buf: buffer @@ -1028,7 +999,7 @@ static struct most_aim_attribute most_aim_attr_add_link = * Example: * echo "mdev0:ep81" >remove_link */ -static ssize_t store_remove_link(struct most_aim_obj *aim_obj, +static ssize_t remove_link_store(struct most_aim_obj *aim_obj, struct most_aim_attribute *attr, const char *buf, size_t len) @@ -1058,12 +1029,16 @@ static ssize_t store_remove_link(struct most_aim_obj *aim_obj, return len; } -static struct most_aim_attribute most_aim_attr_remove_link = - __ATTR(remove_link, S_IWUSR, NULL, store_remove_link); +static struct most_aim_attribute most_aim_attrs[] = { + __ATTR_RO(links), + __ATTR_WO(add_link), + __ATTR_WO(remove_link), +}; static struct attribute *most_aim_def_attrs[] = { - &most_aim_attr_add_link.attr, - &most_aim_attr_remove_link.attr, + &most_aim_attrs[0].attr, + &most_aim_attrs[1].attr, + &most_aim_attrs[2].attr, NULL, }; @@ -1274,45 +1249,49 @@ static int arm_mbo_chain(struct most_c_obj *c, int dir, void (*compl)(struct mbo *)) { unsigned int i; - int retval; struct mbo *mbo; + unsigned long flags; u32 coherent_buf_size = c->cfg.buffer_size + c->cfg.extra_len; atomic_set(&c->mbo_nq_level, 0); for (i = 0; i < c->cfg.num_buffers; i++) { mbo = kzalloc(sizeof(*mbo), GFP_KERNEL); - if (!mbo) { - retval = i; - goto _exit; - } + if (!mbo) + goto flush_fifos; + mbo->context = c; mbo->ifp = c->iface; mbo->hdm_channel_id = c->channel_id; - mbo->virt_address = dma_alloc_coherent(NULL, - coherent_buf_size, - &mbo->bus_address, - GFP_KERNEL); - if (!mbo->virt_address) { - pr_info("WARN: No DMA coherent buffer.\n"); - retval = i; - goto _error1; + if (c->iface->dma_alloc) { + mbo->virt_address = + c->iface->dma_alloc(mbo, coherent_buf_size); + } else { + mbo->virt_address = + kzalloc(coherent_buf_size, GFP_KERNEL); } + if (!mbo->virt_address) + goto release_mbo; + mbo->complete = compl; mbo->num_buffers_ptr = &dummy_num_buffers; if (dir == MOST_CH_RX) { nq_hdm_mbo(mbo); atomic_inc(&c->mbo_nq_level); } else { - arm_mbo(mbo); + spin_lock_irqsave(&c->fifo_lock, flags); + list_add_tail(&mbo->list, &c->fifo); + spin_unlock_irqrestore(&c->fifo_lock, flags); } } - return i; + return c->cfg.num_buffers; -_error1: +release_mbo: kfree(mbo); -_exit: - return retval; + +flush_fifos: + flush_channel_fifos(c); + return 0; } /** @@ -1739,6 +1718,27 @@ struct kobject *most_register_interface(struct most_interface *iface) } iface->priv = inst; + iface->ktype.sysfs_ops = &most_channel_sysfs_ops, + iface->ktype.release = most_channel_release, + iface->ktype.default_attrs = iface->attrs; + + BUILD_BUG_ON(ARRAY_SIZE(iface->attrs) < ARRAY_SIZE(common_c_attrs) + 2); + for (i = 0; i < ARRAY_SIZE(common_c_attrs); i++) + iface->attrs[i] = &common_c_attrs[i].attr; + switch (iface->extra_attrs) { + case XACT_ATTRS: + iface->attrs[i] = &xact_c_attr.attr; + i++; + break; + case DBR_ATTRS: + iface->attrs[i] = &dbr_c_attr.attr; + i++; + break; + default: + break; + } + iface->attrs[i] = NULL; + INIT_LIST_HEAD(&inst->channel_list); inst->iface = iface; inst->dev_id = id; @@ -1753,7 +1753,7 @@ struct kobject *most_register_interface(struct most_interface *iface) snprintf(channel_name, STRING_SIZE, "%s", name_suffix); /* this increments the reference count of this instance */ - c = create_most_c_obj(channel_name, &inst->kobj); + c = create_most_c_obj(&iface->ktype, channel_name, &inst->kobj); if (!c) goto free_instance; inst->channel[i] = c; |