diff options
-rw-r--r-- | drivers/net/caif/caif_serial.c | 1 | ||||
-rw-r--r-- | drivers/net/caif/caif_shmcore.c | 15 | ||||
-rw-r--r-- | drivers/net/caif/caif_spi.c | 176 | ||||
-rw-r--r-- | drivers/net/caif/caif_spi_slave.c | 8 | ||||
-rw-r--r-- | include/net/caif/caif_spi.h | 5 | ||||
-rw-r--r-- | include/net/caif/cfserl.h | 1 | ||||
-rw-r--r-- | net/caif/cfcnfg.c | 2 | ||||
-rw-r--r-- | net/caif/cfserl.c | 6 |
8 files changed, 115 insertions, 99 deletions
diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c index 23406e62c0b..1738685d586 100644 --- a/drivers/net/caif/caif_serial.c +++ b/drivers/net/caif/caif_serial.c @@ -182,6 +182,7 @@ static void ldisc_receive(struct tty_struct *tty, const u8 *data, * This is not yet handled. */ + BUG_ON(ser->dev == NULL); /* * Workaround for garbage at start of transmission, diff --git a/drivers/net/caif/caif_shmcore.c b/drivers/net/caif/caif_shmcore.c index d4b26fb24ed..d20711f3a13 100644 --- a/drivers/net/caif/caif_shmcore.c +++ b/drivers/net/caif/caif_shmcore.c @@ -238,11 +238,11 @@ int caif_shmdrv_rx_cb(u32 mbx_msg, void *priv) if ((avail_emptybuff > HIGH_WATERMARK) && (!pshm_drv->tx_empty_available)) { pshm_drv->tx_empty_available = 1; + spin_unlock_irqrestore(&pshm_drv->lock, flags); pshm_drv->cfdev.flowctrl (pshm_drv->pshm_dev->pshm_netdev, CAIF_FLOW_ON); - spin_unlock_irqrestore(&pshm_drv->lock, flags); /* Schedule the work queue. if required */ if (!work_pending(&pshm_drv->shm_tx_work)) @@ -285,6 +285,7 @@ static void shm_rx_work_func(struct work_struct *rx_work) list_entry(pshm_drv->rx_full_list.next, struct buf_list, list); list_del_init(&pbuf->list); + spin_unlock_irqrestore(&pshm_drv->lock, flags); /* Retrieve pointer to start of the packet descriptor area. */ pck_desc = (struct shm_pck_desc *) pbuf->desc_vptr; @@ -360,6 +361,7 @@ static void shm_rx_work_func(struct work_struct *rx_work) pck_desc++; } + spin_lock_irqsave(&pshm_drv->lock, flags); list_add_tail(&pbuf->list, &pshm_drv->rx_pend_list); spin_unlock_irqrestore(&pshm_drv->lock, flags); @@ -412,7 +414,6 @@ static void shm_tx_work_func(struct work_struct *tx_work) if (skb == NULL) goto send_msg; - /* Check the available no. of buffers in the empty list */ list_for_each(pos, &pshm_drv->tx_empty_list) avail_emptybuff++; @@ -421,9 +422,11 @@ static void shm_tx_work_func(struct work_struct *tx_work) pshm_drv->tx_empty_available) { /* Update blocking condition. */ pshm_drv->tx_empty_available = 0; + spin_unlock_irqrestore(&pshm_drv->lock, flags); pshm_drv->cfdev.flowctrl (pshm_drv->pshm_dev->pshm_netdev, CAIF_FLOW_OFF); + spin_lock_irqsave(&pshm_drv->lock, flags); } /* * We simply return back to the caller if we do not have space @@ -469,6 +472,8 @@ static void shm_tx_work_func(struct work_struct *tx_work) } skb = skb_dequeue(&pshm_drv->sk_qhead); + if (skb == NULL) + break; /* Copy in CAIF frame. */ skb_copy_bits(skb, 0, pbuf->desc_vptr + pbuf->frm_ofs + SHM_HDR_LEN + @@ -512,16 +517,11 @@ send_msg: static int shm_netdev_tx(struct sk_buff *skb, struct net_device *shm_netdev) { struct shmdrv_layer *pshm_drv; - unsigned long flags = 0; pshm_drv = netdev_priv(shm_netdev); - spin_lock_irqsave(&pshm_drv->lock, flags); - skb_queue_tail(&pshm_drv->sk_qhead, skb); - spin_unlock_irqrestore(&pshm_drv->lock, flags); - /* Schedule Tx work queue. for deferred processing of skbs*/ if (!work_pending(&pshm_drv->shm_tx_work)) queue_work(pshm_drv->pshm_tx_workqueue, &pshm_drv->shm_tx_work); @@ -606,6 +606,7 @@ int caif_shmcore_probe(struct shmdev_layer *pshm_dev) pshm_drv->shm_rx_addr = pshm_dev->shm_base_addr + (NR_TX_BUF * TX_BUF_SZ); + spin_lock_init(&pshm_drv->lock); INIT_LIST_HEAD(&pshm_drv->tx_empty_list); INIT_LIST_HEAD(&pshm_drv->tx_pend_list); INIT_LIST_HEAD(&pshm_drv->tx_full_list); diff --git a/drivers/net/caif/caif_spi.c b/drivers/net/caif/caif_spi.c index 0f8defc7330..40fb6249c0d 100644 --- a/drivers/net/caif/caif_spi.c +++ b/drivers/net/caif/caif_spi.c @@ -226,7 +226,7 @@ static ssize_t dbgfs_frame(struct file *file, char __user *user_buf, "Tx data (Len: %d):\n", cfspi->tx_cpck_len); len += print_frame((buf + len), (DEBUGFS_BUF_SIZE - len), - cfspi->xfer.va_tx, + cfspi->xfer.va_tx[0], (cfspi->tx_cpck_len + SPI_CMD_SZ), 100); len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len), @@ -599,48 +599,11 @@ static int cfspi_close(struct net_device *dev) netif_stop_queue(dev); return 0; } -static const struct net_device_ops cfspi_ops = { - .ndo_open = cfspi_open, - .ndo_stop = cfspi_close, - .ndo_start_xmit = cfspi_xmit -}; -static void cfspi_setup(struct net_device *dev) +static int cfspi_init(struct net_device *dev) { + int res = 0; struct cfspi *cfspi = netdev_priv(dev); - dev->features = 0; - dev->netdev_ops = &cfspi_ops; - dev->type = ARPHRD_CAIF; - dev->flags = IFF_NOARP | IFF_POINTOPOINT; - dev->tx_queue_len = 0; - dev->mtu = SPI_MAX_PAYLOAD_SIZE; - dev->destructor = free_netdev; - skb_queue_head_init(&cfspi->qhead); - skb_queue_head_init(&cfspi->chead); - cfspi->cfdev.link_select = CAIF_LINK_HIGH_BANDW; - cfspi->cfdev.use_frag = false; - cfspi->cfdev.use_stx = false; - cfspi->cfdev.use_fcs = false; - cfspi->ndev = dev; -} - -int cfspi_spi_probe(struct platform_device *pdev) -{ - struct cfspi *cfspi = NULL; - struct net_device *ndev; - struct cfspi_dev *dev; - int res; - dev = (struct cfspi_dev *)pdev->dev.platform_data; - - ndev = alloc_netdev(sizeof(struct cfspi), - "cfspi%d", cfspi_setup); - if (!ndev) - return -ENOMEM; - - cfspi = netdev_priv(ndev); - netif_stop_queue(ndev); - cfspi->ndev = ndev; - cfspi->pdev = pdev; /* Set flow info. */ cfspi->flow_off_sent = 0; @@ -656,18 +619,13 @@ int cfspi_spi_probe(struct platform_device *pdev) cfspi->slave_talked = false; } - /* Assign the SPI device. */ - cfspi->dev = dev; - /* Assign the device ifc to this SPI interface. */ - dev->ifc = &cfspi->ifc; - /* Allocate DMA buffers. */ - cfspi->xfer.va_tx = dma_alloc(&cfspi->xfer.pa_tx); - if (!cfspi->xfer.va_tx) { + cfspi->xfer.va_tx[0] = dma_alloc(&cfspi->xfer.pa_tx[0]); + if (!cfspi->xfer.va_tx[0]) { printk(KERN_WARNING "CFSPI: failed to allocate dma TX buffer.\n"); res = -ENODEV; - goto err_dma_alloc_tx; + goto err_dma_alloc_tx_0; } cfspi->xfer.va_rx = dma_alloc(&cfspi->xfer.pa_rx); @@ -718,6 +676,87 @@ int cfspi_spi_probe(struct platform_device *pdev) /* Schedule the work queue. */ queue_work(cfspi->wq, &cfspi->work); + return 0; + + err_create_wq: + dma_free(cfspi->xfer.va_rx, cfspi->xfer.pa_rx); + err_dma_alloc_rx: + dma_free(cfspi->xfer.va_tx[0], cfspi->xfer.pa_tx[0]); + err_dma_alloc_tx_0: + return res; +} + +static void cfspi_uninit(struct net_device *dev) +{ + struct cfspi *cfspi = netdev_priv(dev); + + /* Remove from list. */ + spin_lock(&cfspi_list_lock); + list_del(&cfspi->list); + spin_unlock(&cfspi_list_lock); + + cfspi->ndev = NULL; + /* Free DMA buffers. */ + dma_free(cfspi->xfer.va_rx, cfspi->xfer.pa_rx); + dma_free(cfspi->xfer.va_tx[0], cfspi->xfer.pa_tx[0]); + set_bit(SPI_TERMINATE, &cfspi->state); + wake_up_interruptible(&cfspi->wait); + destroy_workqueue(cfspi->wq); + /* Destroy debugfs directory and files. */ + dev_debugfs_rem(cfspi); + return; +} + +static const struct net_device_ops cfspi_ops = { + .ndo_open = cfspi_open, + .ndo_stop = cfspi_close, + .ndo_init = cfspi_init, + .ndo_uninit = cfspi_uninit, + .ndo_start_xmit = cfspi_xmit +}; + +static void cfspi_setup(struct net_device *dev) +{ + struct cfspi *cfspi = netdev_priv(dev); + dev->features = 0; + dev->netdev_ops = &cfspi_ops; + dev->type = ARPHRD_CAIF; + dev->flags = IFF_NOARP | IFF_POINTOPOINT; + dev->tx_queue_len = 0; + dev->mtu = SPI_MAX_PAYLOAD_SIZE; + dev->destructor = free_netdev; + skb_queue_head_init(&cfspi->qhead); + skb_queue_head_init(&cfspi->chead); + cfspi->cfdev.link_select = CAIF_LINK_HIGH_BANDW; + cfspi->cfdev.use_frag = false; + cfspi->cfdev.use_stx = false; + cfspi->cfdev.use_fcs = false; + cfspi->ndev = dev; +} + +int cfspi_spi_probe(struct platform_device *pdev) +{ + struct cfspi *cfspi = NULL; + struct net_device *ndev; + struct cfspi_dev *dev; + int res; + dev = (struct cfspi_dev *)pdev->dev.platform_data; + + ndev = alloc_netdev(sizeof(struct cfspi), + "cfspi%d", cfspi_setup); + if (!dev) + return -ENODEV; + + cfspi = netdev_priv(ndev); + netif_stop_queue(ndev); + cfspi->ndev = ndev; + cfspi->pdev = pdev; + + /* Assign the SPI device. */ + cfspi->dev = dev; + /* Assign the device ifc to this SPI interface. */ + dev->ifc = &cfspi->ifc; + /* Register network device. */ res = register_netdev(ndev); if (res) { @@ -727,15 +766,6 @@ int cfspi_spi_probe(struct platform_device *pdev) return res; err_net_reg: - dev_debugfs_rem(cfspi); - set_bit(SPI_TERMINATE, &cfspi->state); - wake_up_interruptible(&cfspi->wait); - destroy_workqueue(cfspi->wq); - err_create_wq: - dma_free(cfspi->xfer.va_rx, cfspi->xfer.pa_rx); - err_dma_alloc_rx: - dma_free(cfspi->xfer.va_tx, cfspi->xfer.pa_tx); - err_dma_alloc_tx: free_netdev(ndev); return res; @@ -743,34 +773,8 @@ int cfspi_spi_probe(struct platform_device *pdev) int cfspi_spi_remove(struct platform_device *pdev) { - struct list_head *list_node; - struct list_head *n; - struct cfspi *cfspi = NULL; - struct cfspi_dev *dev; - - dev = (struct cfspi_dev *)pdev->dev.platform_data; - spin_lock(&cfspi_list_lock); - list_for_each_safe(list_node, n, &cfspi_list) { - cfspi = list_entry(list_node, struct cfspi, list); - /* Find the corresponding device. */ - if (cfspi->dev == dev) { - /* Remove from list. */ - list_del(list_node); - /* Free DMA buffers. */ - dma_free(cfspi->xfer.va_rx, cfspi->xfer.pa_rx); - dma_free(cfspi->xfer.va_tx, cfspi->xfer.pa_tx); - set_bit(SPI_TERMINATE, &cfspi->state); - wake_up_interruptible(&cfspi->wait); - destroy_workqueue(cfspi->wq); - /* Destroy debugfs directory and files. */ - dev_debugfs_rem(cfspi); - unregister_netdev(cfspi->ndev); - spin_unlock(&cfspi_list_lock); - return 0; - } - } - spin_unlock(&cfspi_list_lock); - return -ENODEV; + /* Everything is done in cfspi_uninit(). */ + return 0; } static void __exit cfspi_exit_module(void) @@ -781,7 +785,7 @@ static void __exit cfspi_exit_module(void) list_for_each_safe(list_node, n, &cfspi_list) { cfspi = list_entry(list_node, struct cfspi, list); - platform_device_unregister(cfspi->pdev); + unregister_netdev(cfspi->ndev); } /* Destroy sysfs files. */ diff --git a/drivers/net/caif/caif_spi_slave.c b/drivers/net/caif/caif_spi_slave.c index e139e133fc7..3baa572407c 100644 --- a/drivers/net/caif/caif_spi_slave.c +++ b/drivers/net/caif/caif_spi_slave.c @@ -85,13 +85,13 @@ void cfspi_xfer(struct work_struct *work) #if CFSPI_DBG_PREFILL /* Prefill buffers for easier debugging. */ - memset(cfspi->xfer.va_tx, 0xFF, SPI_DMA_BUF_LEN); + memset(cfspi->xfer.va_tx[0], 0xFF, SPI_DMA_BUF_LEN); memset(cfspi->xfer.va_rx, 0xFF, SPI_DMA_BUF_LEN); #endif /* CFSPI_DBG_PREFILL */ cfspi_dbg_state(cfspi, CFSPI_STATE_AWAKE); - /* Check whether we have a committed frame. */ + /* Check whether we have a committed frame. */ if (cfspi->tx_cpck_len) { int len; @@ -102,7 +102,7 @@ void cfspi_xfer(struct work_struct *work) ptr += SPI_IND_SZ; len = cfspi_xmitfrm(cfspi, ptr, cfspi->tx_cpck_len); WARN_ON(len != cfspi->tx_cpck_len); - } + } cfspi_dbg_state(cfspi, CFSPI_STATE_GET_NEXT); @@ -115,7 +115,7 @@ void cfspi_xfer(struct work_struct *work) * Add indication and length at the beginning of the frame, * using little endian. */ - ptr = (u8 *) cfspi->xfer.va_tx; + ptr = (u8 *) cfspi->xfer.va_tx[0]; *ptr++ = SPI_CMD_IND; *ptr++ = (SPI_CMD_IND & 0xFF00) >> 8; *ptr++ = cfspi->tx_npck_len & 0x00FF; diff --git a/include/net/caif/caif_spi.h b/include/net/caif/caif_spi.h index 87c3d11b8e5..914810614d0 100644 --- a/include/net/caif/caif_spi.h +++ b/include/net/caif/caif_spi.h @@ -55,10 +55,11 @@ struct cfspi_xfer { u16 tx_dma_len; u16 rx_dma_len; - void *va_tx; - dma_addr_t pa_tx; + void *va_tx[2]; + dma_addr_t pa_tx[2]; void *va_rx; dma_addr_t pa_rx; + int idx_tx; }; /* Structure implemented by the SPI interface. */ diff --git a/include/net/caif/cfserl.h b/include/net/caif/cfserl.h index b8374321b36..8ac284c5de2 100644 --- a/include/net/caif/cfserl.h +++ b/include/net/caif/cfserl.h @@ -9,4 +9,5 @@ #include <net/caif/caif_layer.h> struct cflayer *cfserl_create(int type, int instance, bool use_stx); +void cfserl_destroy(struct cflayer *layer); #endif /* CFSERL_H_ */ diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c index 52fe33bee02..7debfd4a031 100644 --- a/net/caif/cfcnfg.c +++ b/net/caif/cfcnfg.c @@ -521,6 +521,8 @@ got_phyid: frml = cffrml_create(phyid, fcs); if (!frml) { + if (phy_driver) + cfserl_destroy(phy_driver); pr_warn("Out of memory\n"); kfree(phyinfo); goto out; diff --git a/net/caif/cfserl.c b/net/caif/cfserl.c index 2715c84cfa8..403d57ad305 100644 --- a/net/caif/cfserl.c +++ b/net/caif/cfserl.c @@ -190,3 +190,9 @@ static void cfserl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, { layr->up->ctrlcmd(layr->up, ctrl, phyid); } + +void cfserl_destroy(struct cflayer *layer) +{ + struct cfserl *cfserl = container_obj(layer); + kfree(cfserl); +} |