Commit d5f43c1e authored by Erwan Bracq's avatar Erwan Bracq Committed by David S. Miller

caif-spi: Bugfix for dump upon device removal

Fix dump upon device removal, by moving deinitialization from
platform-device-remove to network-interface-uninit.
Signed-off-by: default avatarSjur Brændeland <sjur.brandeland@stericsson.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9e998a75
...@@ -226,7 +226,7 @@ static ssize_t dbgfs_frame(struct file *file, char __user *user_buf, ...@@ -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); "Tx data (Len: %d):\n", cfspi->tx_cpck_len);
len += print_frame((buf + len), (DEBUGFS_BUF_SIZE - 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); (cfspi->tx_cpck_len + SPI_CMD_SZ), 100);
len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len), len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
...@@ -599,48 +599,11 @@ static int cfspi_close(struct net_device *dev) ...@@ -599,48 +599,11 @@ static int cfspi_close(struct net_device *dev)
netif_stop_queue(dev); netif_stop_queue(dev);
return 0; 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); 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. */ /* Set flow info. */
cfspi->flow_off_sent = 0; cfspi->flow_off_sent = 0;
...@@ -656,16 +619,11 @@ int cfspi_spi_probe(struct platform_device *pdev) ...@@ -656,16 +619,11 @@ int cfspi_spi_probe(struct platform_device *pdev)
cfspi->slave_talked = false; 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. */ /* Allocate DMA buffers. */
cfspi->xfer.va_tx = dma_alloc(&cfspi->xfer.pa_tx); cfspi->xfer.va_tx[0] = dma_alloc(&cfspi->xfer.pa_tx[0]);
if (!cfspi->xfer.va_tx) { if (!cfspi->xfer.va_tx[0]) {
res = -ENODEV; res = -ENODEV;
goto err_dma_alloc_tx; goto err_dma_alloc_tx_0;
} }
cfspi->xfer.va_rx = dma_alloc(&cfspi->xfer.pa_rx); cfspi->xfer.va_rx = dma_alloc(&cfspi->xfer.pa_rx);
...@@ -714,59 +672,105 @@ int cfspi_spi_probe(struct platform_device *pdev) ...@@ -714,59 +672,105 @@ int cfspi_spi_probe(struct platform_device *pdev)
/* Schedule the work queue. */ /* Schedule the work queue. */
queue_work(cfspi->wq, &cfspi->work); queue_work(cfspi->wq, &cfspi->work);
/* Register network device. */ return 0;
res = register_netdev(ndev);
if (res) {
printk(KERN_ERR "CFSPI: Reg. error: %d.\n", res);
goto err_net_reg;
}
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: err_create_wq:
dma_free(cfspi->xfer.va_rx, cfspi->xfer.pa_rx); dma_free(cfspi->xfer.va_rx, cfspi->xfer.pa_rx);
err_dma_alloc_rx: err_dma_alloc_rx:
dma_free(cfspi->xfer.va_tx, cfspi->xfer.pa_tx); dma_free(cfspi->xfer.va_tx[0], cfspi->xfer.pa_tx[0]);
err_dma_alloc_tx: err_dma_alloc_tx_0:
free_netdev(ndev);
return res; return res;
} }
int cfspi_spi_remove(struct platform_device *pdev) static void cfspi_uninit(struct net_device *dev)
{ {
struct list_head *list_node; struct cfspi *cfspi = netdev_priv(dev);
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. */ /* Remove from list. */
list_del(list_node); spin_lock(&cfspi_list_lock);
list_del(&cfspi->list);
spin_unlock(&cfspi_list_lock);
cfspi->ndev = NULL;
/* Free DMA buffers. */ /* Free DMA buffers. */
dma_free(cfspi->xfer.va_rx, cfspi->xfer.pa_rx); dma_free(cfspi->xfer.va_rx, cfspi->xfer.pa_rx);
dma_free(cfspi->xfer.va_tx, cfspi->xfer.pa_tx); dma_free(cfspi->xfer.va_tx[0], cfspi->xfer.pa_tx[0]);
set_bit(SPI_TERMINATE, &cfspi->state); set_bit(SPI_TERMINATE, &cfspi->state);
wake_up_interruptible(&cfspi->wait); wake_up_interruptible(&cfspi->wait);
destroy_workqueue(cfspi->wq); destroy_workqueue(cfspi->wq);
/* Destroy debugfs directory and files. */ /* Destroy debugfs directory and files. */
dev_debugfs_rem(cfspi); dev_debugfs_rem(cfspi);
unregister_netdev(cfspi->ndev); return;
spin_unlock(&cfspi_list_lock); }
return 0;
} static const struct net_device_ops cfspi_ops = {
} .ndo_open = cfspi_open,
spin_unlock(&cfspi_list_lock); .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; 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) {
printk(KERN_ERR "CFSPI: Reg. error: %d.\n", res);
goto err_net_reg;
}
return res;
err_net_reg:
free_netdev(ndev);
return res;
}
int cfspi_spi_remove(struct platform_device *pdev)
{
/* Everything is done in cfspi_uninit(). */
return 0;
} }
static void __exit cfspi_exit_module(void) static void __exit cfspi_exit_module(void)
...@@ -777,7 +781,7 @@ static void __exit cfspi_exit_module(void) ...@@ -777,7 +781,7 @@ static void __exit cfspi_exit_module(void)
list_for_each_safe(list_node, n, &cfspi_list) { list_for_each_safe(list_node, n, &cfspi_list) {
cfspi = list_entry(list_node, struct cfspi, list); cfspi = list_entry(list_node, struct cfspi, list);
platform_device_unregister(cfspi->pdev); unregister_netdev(cfspi->ndev);
} }
/* Destroy sysfs files. */ /* Destroy sysfs files. */
......
...@@ -55,8 +55,8 @@ ...@@ -55,8 +55,8 @@
struct cfspi_xfer { struct cfspi_xfer {
u16 tx_dma_len; u16 tx_dma_len;
u16 rx_dma_len; u16 rx_dma_len;
void *va_tx; void *va_tx[2];
dma_addr_t pa_tx; dma_addr_t pa_tx[2];
void *va_rx; void *va_rx;
dma_addr_t pa_rx; dma_addr_t pa_rx;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment