From 15877e9c8a12ced38ac31d8bf4f93f3634fbea3f Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 8 Jan 2012 12:04:05 +0000 Subject: NET: sa11x0-ir: fix documentation bug Spell the module parameter correctly in comments. Signed-off-by: Russell King --- drivers/net/irda/sa1100_ir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index da2705061a60..751f2a9f283b 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -15,7 +15,7 @@ * This driver takes one kernel command line parameter, sa1100ir=, with * the following options: * max_rate:baudrate - set the maximum baud rate - * power_leve:level - set the transmitter power level + * power_level:level - set the transmitter power level * tx_lpm:0|1 - set transmit low power mode */ #include -- cgit v1.2.3-59-g8ed1b From 22f0bf96de1506081a8b18ad3e0d04d5add70a4a Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 8 Jan 2012 13:55:23 +0000 Subject: NET: sa11x0-ir: handle DMA mapping errors properly Handle DMA mapping errors in the rx skb allocation and tx paths. Signed-off-by: Russell King --- drivers/net/irda/sa1100_ir.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 751f2a9f283b..84fecce078f6 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -82,7 +82,6 @@ static int sa1100_irda_rx_alloc(struct sa1100_irda *si) return 0; si->rxskb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC); - if (!si->rxskb) { printk(KERN_ERR "sa1100_ir: out of memory for RX SKB\n"); return -ENOMEM; @@ -97,6 +96,11 @@ static int sa1100_irda_rx_alloc(struct sa1100_irda *si) si->rxbuf_dma = dma_map_single(si->dev, si->rxskb->data, HPSIR_MAX_RXLEN, DMA_FROM_DEVICE); + if (dma_mapping_error(si->dev, si->rxbuf_dma)) { + dev_kfree_skb_any(si->rxskb); + return -ENOMEM; + } + return 0; } @@ -518,7 +522,8 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev netif_rx(skb); } else { /* - * Remap the buffer. + * Remap the buffer - it was previously mapped, and we + * hope that this succeeds. */ si->rxbuf_dma = dma_map_single(si->dev, si->rxskb->data, HPSIR_MAX_RXLEN, @@ -701,6 +706,13 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) si->txskb = skb; si->txbuf_dma = dma_map_single(si->dev, skb->data, skb->len, DMA_TO_DEVICE); + if (dma_mapping_error(si->dev, si->txbuf_dma)) { + si->txskb = NULL; + netif_wake_queue(dev); + dev->stats.tx_dropped++; + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } sa1100_start_dma(si->txdma, si->txbuf_dma, skb->len); -- cgit v1.2.3-59-g8ed1b From d32386086b4a250bd71125f8d760cfffada0e422 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 8 Jan 2012 12:07:24 +0000 Subject: NET: sa11x0-ir: set netdev's parent struct device Add the missing SET_NETDEV_DEV() call to set the parent device correctly for this network interface. Signed-off-by: Russell King --- drivers/net/irda/sa1100_ir.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 84fecce078f6..149a3b4aaecc 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -919,6 +919,8 @@ static int sa1100_irda_probe(struct platform_device *pdev) if (!dev) goto err_mem_4; + SET_NETDEV_DEV(dev, &pdev->dev); + si = netdev_priv(dev); si->dev = &pdev->dev; si->pdata = pdev->dev.platform_data; -- cgit v1.2.3-59-g8ed1b From e556fdbde38f68d87f689473b112cc65ddacd6a4 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 8 Jan 2012 12:02:17 +0000 Subject: NET: sa11x0-ir: obtain interrupt number from platform resources Convert the sa11x0-ir driver to obtain its interrupt number from the platform device resources, rather than via the asm/irq.h include. Signed-off-by: Russell King --- drivers/net/irda/sa1100_ir.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 149a3b4aaecc..2f5bf0bc8458 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -35,7 +35,6 @@ #include #include -#include #include #include #include @@ -900,11 +899,15 @@ static int sa1100_irda_probe(struct platform_device *pdev) struct net_device *dev; struct sa1100_irda *si; unsigned int baudrate_mask; - int err; + int err, irq; if (!pdev->dev.platform_data) return -EINVAL; + irq = platform_get_irq(pdev, 0); + if (irq <= 0) + return irq < 0 ? irq : -ENXIO; + err = request_mem_region(__PREG(Ser2UTCR0), 0x24, "IrDA") ? 0 : -EBUSY; if (err) goto err_mem_1; @@ -936,7 +939,7 @@ static int sa1100_irda_probe(struct platform_device *pdev) goto err_mem_5; dev->netdev_ops = &sa1100_irda_netdev_ops; - dev->irq = IRQ_Ser2ICP; + dev->irq = irq; irda_init_max_qos_capabilies(&si->qos); -- cgit v1.2.3-59-g8ed1b From 885767ca4ce0800c5d02eb66cc10a0494b7bf312 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 8 Jan 2012 12:53:22 +0000 Subject: NET: sa11x0-ir: containerize DMA data Both the transmit and receive DMA store identical data: the skb, dma address, and the dma registers. Move this data into its own data structure. The following replacements were used: rxskb -> dma_rx.skb rxbuf_dma -> dma_rx.dma rxdma -> dma_rx.regs txskb -> dma_tx.skb txbuf_dma -> dma_tx.dma txdma -> dma_tx.regs Signed-off-by: Russell King --- drivers/net/irda/sa1100_ir.c | 94 ++++++++++++++++++++++---------------------- 1 file changed, 48 insertions(+), 46 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 2f5bf0bc8458..adb7fea78c2d 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -43,6 +43,12 @@ static int power_level = 3; static int tx_lpm; static int max_rate = 4000000; +struct sa1100_buf { + struct sk_buff *skb; + dma_addr_t dma; + dma_regs_t *regs; +}; + struct sa1100_irda { unsigned char hscr0; unsigned char utcr4; @@ -52,12 +58,8 @@ struct sa1100_irda { int speed; int newspeed; - struct sk_buff *txskb; - struct sk_buff *rxskb; - dma_addr_t txbuf_dma; - dma_addr_t rxbuf_dma; - dma_regs_t *txdma; - dma_regs_t *rxdma; + struct sa1100_buf dma_rx; + struct sa1100_buf dma_tx; struct device *dev; struct irda_platform_data *pdata; @@ -77,11 +79,11 @@ struct sa1100_irda { */ static int sa1100_irda_rx_alloc(struct sa1100_irda *si) { - if (si->rxskb) + if (si->dma_rx.skb) return 0; - si->rxskb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC); - if (!si->rxskb) { + si->dma_rx.skb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC); + if (!si->dma_rx.skb) { printk(KERN_ERR "sa1100_ir: out of memory for RX SKB\n"); return -ENOMEM; } @@ -90,13 +92,13 @@ static int sa1100_irda_rx_alloc(struct sa1100_irda *si) * Align any IP headers that may be contained * within the frame. */ - skb_reserve(si->rxskb, 1); + skb_reserve(si->dma_rx.skb, 1); - si->rxbuf_dma = dma_map_single(si->dev, si->rxskb->data, + si->dma_rx.dma = dma_map_single(si->dev, si->dma_rx.skb->data, HPSIR_MAX_RXLEN, DMA_FROM_DEVICE); - if (dma_mapping_error(si->dev, si->rxbuf_dma)) { - dev_kfree_skb_any(si->rxskb); + if (dma_mapping_error(si->dev, si->dma_rx.dma)) { + dev_kfree_skb_any(si->dma_rx.skb); return -ENOMEM; } @@ -109,7 +111,7 @@ static int sa1100_irda_rx_alloc(struct sa1100_irda *si) */ static void sa1100_irda_rx_dma_start(struct sa1100_irda *si) { - if (!si->rxskb) { + if (!si->dma_rx.skb) { printk(KERN_ERR "sa1100_ir: rx buffer went missing\n"); return; } @@ -122,8 +124,8 @@ static void sa1100_irda_rx_dma_start(struct sa1100_irda *si) /* * Enable the DMA, receiver and receive interrupt. */ - sa1100_clear_dma(si->rxdma); - sa1100_start_dma(si->rxdma, si->rxbuf_dma, HPSIR_MAX_RXLEN); + sa1100_clear_dma(si->dma_rx.regs); + sa1100_start_dma(si->dma_rx.regs, si->dma_rx.dma, HPSIR_MAX_RXLEN); Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_RXE; } @@ -144,7 +146,7 @@ static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed) * Stop the receive DMA. */ if (IS_FIR(si)) - sa1100_stop_dma(si->rxdma); + sa1100_stop_dma(si->dma_rx.regs); local_irq_save(flags); @@ -280,8 +282,8 @@ static void sa1100_irda_shutdown(struct sa1100_irda *si) /* * Stop all DMA activity. */ - sa1100_stop_dma(si->rxdma); - sa1100_stop_dma(si->txdma); + sa1100_stop_dma(si->dma_rx.regs); + sa1100_stop_dma(si->dma_tx.regs); /* Disable the port. */ Ser2UTCR3 = 0; @@ -460,7 +462,7 @@ static void sa1100_irda_hpsir_irq(struct net_device *dev) static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev) { - struct sk_buff *skb = si->rxskb; + struct sk_buff *skb = si->dma_rx.skb; dma_addr_t dma_addr; unsigned int len, stat, data; @@ -472,11 +474,11 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev /* * Get the current data position. */ - dma_addr = sa1100_get_dma_pos(si->rxdma); - len = dma_addr - si->rxbuf_dma; + dma_addr = sa1100_get_dma_pos(si->dma_rx.regs); + len = dma_addr - si->dma_rx.dma; if (len > HPSIR_MAX_RXLEN) len = HPSIR_MAX_RXLEN; - dma_unmap_single(si->dev, si->rxbuf_dma, len, DMA_FROM_DEVICE); + dma_unmap_single(si->dev, si->dma_rx.dma, len, DMA_FROM_DEVICE); do { /* @@ -504,7 +506,7 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev } while (Ser2HSSR0 & HSSR0_EIF); if (stat & HSSR1_EOF) { - si->rxskb = NULL; + si->dma_rx.skb = NULL; skb_put(skb, len); skb->dev = dev; @@ -524,7 +526,7 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev * Remap the buffer - it was previously mapped, and we * hope that this succeeds. */ - si->rxbuf_dma = dma_map_single(si->dev, si->rxskb->data, + si->dma_rx.dma = dma_map_single(si->dev, si->dma_rx.skb->data, HPSIR_MAX_RXLEN, DMA_FROM_DEVICE); } @@ -543,7 +545,7 @@ static void sa1100_irda_fir_irq(struct net_device *dev) /* * Stop RX DMA */ - sa1100_stop_dma(si->rxdma); + sa1100_stop_dma(si->dma_rx.regs); /* * Framing error - we throw away the packet completely. @@ -600,9 +602,9 @@ static void sa1100_irda_txdma_irq(void *id) { struct net_device *dev = id; struct sa1100_irda *si = netdev_priv(dev); - struct sk_buff *skb = si->txskb; + struct sk_buff *skb = si->dma_tx.skb; - si->txskb = NULL; + si->dma_tx.skb = NULL; /* * Wait for the transmission to complete. Unfortunately, @@ -620,7 +622,7 @@ static void sa1100_irda_txdma_irq(void *id) /* * Do we need to change speed? Note that we're lazy - * here - we don't free the old rxskb. We don't need + * here - we don't free the old dma_rx.skb. We don't need * to allocate a buffer either. */ if (si->newspeed) { @@ -638,7 +640,7 @@ static void sa1100_irda_txdma_irq(void *id) * Account and free the packet. */ if (skb) { - dma_unmap_single(si->dev, si->txbuf_dma, skb->len, DMA_TO_DEVICE); + dma_unmap_single(si->dev, si->dma_tx.dma, skb->len, DMA_TO_DEVICE); dev->stats.tx_packets ++; dev->stats.tx_bytes += skb->len; dev_kfree_skb_irq(skb); @@ -698,22 +700,22 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) /* * We must not be transmitting... */ - BUG_ON(si->txskb); + BUG_ON(si->dma_tx.skb); netif_stop_queue(dev); - si->txskb = skb; - si->txbuf_dma = dma_map_single(si->dev, skb->data, + si->dma_tx.skb = skb; + si->dma_tx.dma = dma_map_single(si->dev, skb->data, skb->len, DMA_TO_DEVICE); - if (dma_mapping_error(si->dev, si->txbuf_dma)) { - si->txskb = NULL; + if (dma_mapping_error(si->dev, si->dma_tx.dma)) { + si->dma_tx.skb = NULL; netif_wake_queue(dev); dev->stats.tx_dropped++; dev_kfree_skb(skb); return NETDEV_TX_OK; } - sa1100_start_dma(si->txdma, si->txbuf_dma, skb->len); + sa1100_start_dma(si->dma_tx.regs, si->dma_tx.dma, skb->len); /* * If we have a mean turn-around time, impose the specified @@ -785,12 +787,12 @@ static int sa1100_irda_start(struct net_device *dev) goto err_irq; err = sa1100_request_dma(DMA_Ser2HSSPRd, "IrDA receive", - NULL, NULL, &si->rxdma); + NULL, NULL, &si->dma_rx.regs); if (err) goto err_rx_dma; err = sa1100_request_dma(DMA_Ser2HSSPWr, "IrDA transmit", - sa1100_irda_txdma_irq, dev, &si->txdma); + sa1100_irda_txdma_irq, dev, &si->dma_tx.regs); if (err) goto err_tx_dma; @@ -827,9 +829,9 @@ err_irlap: si->open = 0; sa1100_irda_shutdown(si); err_startup: - sa1100_free_dma(si->txdma); + sa1100_free_dma(si->dma_tx.regs); err_tx_dma: - sa1100_free_dma(si->rxdma); + sa1100_free_dma(si->dma_rx.regs); err_rx_dma: free_irq(dev->irq, dev); err_irq: @@ -847,11 +849,11 @@ static int sa1100_irda_stop(struct net_device *dev) * If we have been doing DMA receive, make sure we * tidy that up cleanly. */ - if (si->rxskb) { - dma_unmap_single(si->dev, si->rxbuf_dma, HPSIR_MAX_RXLEN, + if (si->dma_rx.skb) { + dma_unmap_single(si->dev, si->dma_rx.dma, HPSIR_MAX_RXLEN, DMA_FROM_DEVICE); - dev_kfree_skb(si->rxskb); - si->rxskb = NULL; + dev_kfree_skb(si->dma_rx.skb); + si->dma_rx.skb = NULL; } /* Stop IrLAP */ @@ -866,8 +868,8 @@ static int sa1100_irda_stop(struct net_device *dev) /* * Free resources */ - sa1100_free_dma(si->txdma); - sa1100_free_dma(si->rxdma); + sa1100_free_dma(si->dma_tx.regs); + sa1100_free_dma(si->dma_rx.regs); free_irq(dev->irq, dev); sa1100_set_power(si, 0); -- cgit v1.2.3-59-g8ed1b From ba84525bd9015e7dd20f7c97a2a96b0a238b0223 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 8 Jan 2012 15:38:15 +0000 Subject: NET: sa11x0-ir: fix leak of tx skb Ensure that we unmap and free a pending transmit skb when the interface is stopped. We rearrange the code a little bit to give all places a similar layout when freeing the skb in both the completion and interface stop paths - this gives some consistency to the code. Signed-off-by: Russell King --- drivers/net/irda/sa1100_ir.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index adb7fea78c2d..9dc564830c9d 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -602,9 +602,7 @@ static void sa1100_irda_txdma_irq(void *id) { struct net_device *dev = id; struct sa1100_irda *si = netdev_priv(dev); - struct sk_buff *skb = si->dma_tx.skb; - - si->dma_tx.skb = NULL; + struct sk_buff *skb; /* * Wait for the transmission to complete. Unfortunately, @@ -636,14 +634,15 @@ static void sa1100_irda_txdma_irq(void *id) */ sa1100_irda_rx_dma_start(si); - /* - * Account and free the packet. - */ + /* Account and free the packet. */ + skb = si->dma_tx.skb; if (skb) { - dma_unmap_single(si->dev, si->dma_tx.dma, skb->len, DMA_TO_DEVICE); + dma_unmap_single(si->dev, si->dma_tx.dma, skb->len, + DMA_TO_DEVICE); dev->stats.tx_packets ++; dev->stats.tx_bytes += skb->len; dev_kfree_skb_irq(skb); + si->dma_tx.skb = NULL; } /* @@ -841,21 +840,31 @@ err_irq: static int sa1100_irda_stop(struct net_device *dev) { struct sa1100_irda *si = netdev_priv(dev); + struct sk_buff *skb; disable_irq(dev->irq); sa1100_irda_shutdown(si); /* - * If we have been doing DMA receive, make sure we + * If we have been doing any DMA activity, make sure we * tidy that up cleanly. */ - if (si->dma_rx.skb) { + skb = si->dma_rx.skb; + if (skb) { dma_unmap_single(si->dev, si->dma_rx.dma, HPSIR_MAX_RXLEN, DMA_FROM_DEVICE); - dev_kfree_skb(si->dma_rx.skb); + dev_kfree_skb(skb); si->dma_rx.skb = NULL; } + skb = si->dma_tx.skb; + if (skb) { + dma_unmap_single(si->dev, si->dma_tx.dma, skb->len, + DMA_TO_DEVICE); + dev_kfree_skb(skb); + si->dma_tx.skb = NULL; + } + /* Stop IrLAP */ if (si->irlap) { irlap_close(si->irlap); -- cgit v1.2.3-59-g8ed1b From cbe1d24fb70751ef14801338aa945e807ba63a90 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 8 Jan 2012 16:40:07 +0000 Subject: NET: sa11x0-ir: move sa1100_irda_{startup,shutdown,suspend,resume} Places these functions in better locations in the file, near where they are used. This saves some tiresome paging up/down. Signed-off-by: Russell King --- drivers/net/irda/sa1100_ir.c | 262 +++++++++++++++++++++---------------------- 1 file changed, 131 insertions(+), 131 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 9dc564830c9d..32ac4a44ce76 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -230,137 +230,6 @@ sa1100_set_power(struct sa1100_irda *si, unsigned int state) return ret; } -static int sa1100_irda_startup(struct sa1100_irda *si) -{ - int ret; - - /* - * Ensure that the ports for this device are setup correctly. - */ - if (si->pdata->startup) { - ret = si->pdata->startup(si->dev); - if (ret) - return ret; - } - - /* - * Configure PPC for IRDA - we want to drive TXD2 low. - * We also want to drive this pin low during sleep. - */ - PPSR &= ~PPC_TXD2; - PSDR &= ~PPC_TXD2; - PPDR |= PPC_TXD2; - - /* - * Enable HP-SIR modulation, and ensure that the port is disabled. - */ - Ser2UTCR3 = 0; - Ser2HSCR0 = HSCR0_UART; - Ser2UTCR4 = si->utcr4; - Ser2UTCR0 = UTCR0_8BitData; - Ser2HSCR2 = HSCR2_TrDataH | HSCR2_RcDataL; - - /* - * Clear status register - */ - Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID; - - ret = sa1100_irda_set_speed(si, si->speed = 9600); - if (ret) { - Ser2UTCR3 = 0; - Ser2HSCR0 = 0; - - if (si->pdata->shutdown) - si->pdata->shutdown(si->dev); - } - - return ret; -} - -static void sa1100_irda_shutdown(struct sa1100_irda *si) -{ - /* - * Stop all DMA activity. - */ - sa1100_stop_dma(si->dma_rx.regs); - sa1100_stop_dma(si->dma_tx.regs); - - /* Disable the port. */ - Ser2UTCR3 = 0; - Ser2HSCR0 = 0; - - if (si->pdata->shutdown) - si->pdata->shutdown(si->dev); -} - -#ifdef CONFIG_PM -/* - * Suspend the IrDA interface. - */ -static int sa1100_irda_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct net_device *dev = platform_get_drvdata(pdev); - struct sa1100_irda *si; - - if (!dev) - return 0; - - si = netdev_priv(dev); - if (si->open) { - /* - * Stop the transmit queue - */ - netif_device_detach(dev); - disable_irq(dev->irq); - sa1100_irda_shutdown(si); - __sa1100_irda_set_power(si, 0); - } - - return 0; -} - -/* - * Resume the IrDA interface. - */ -static int sa1100_irda_resume(struct platform_device *pdev) -{ - struct net_device *dev = platform_get_drvdata(pdev); - struct sa1100_irda *si; - - if (!dev) - return 0; - - si = netdev_priv(dev); - if (si->open) { - /* - * If we missed a speed change, initialise at the new speed - * directly. It is debatable whether this is actually - * required, but in the interests of continuing from where - * we left off it is desirable. The converse argument is - * that we should re-negotiate at 9600 baud again. - */ - if (si->newspeed) { - si->speed = si->newspeed; - si->newspeed = 0; - } - - sa1100_irda_startup(si); - __sa1100_irda_set_power(si, si->power); - enable_irq(dev->irq); - - /* - * This automatically wakes up the queue - */ - netif_device_attach(dev); - } - - return 0; -} -#else -#define sa1100_irda_suspend NULL -#define sa1100_irda_resume NULL -#endif - /* * HP-SIR format interrupt service routines. */ @@ -774,6 +643,69 @@ sa1100_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) return ret; } +static int sa1100_irda_startup(struct sa1100_irda *si) +{ + int ret; + + /* + * Ensure that the ports for this device are setup correctly. + */ + if (si->pdata->startup) { + ret = si->pdata->startup(si->dev); + if (ret) + return ret; + } + + /* + * Configure PPC for IRDA - we want to drive TXD2 low. + * We also want to drive this pin low during sleep. + */ + PPSR &= ~PPC_TXD2; + PSDR &= ~PPC_TXD2; + PPDR |= PPC_TXD2; + + /* + * Enable HP-SIR modulation, and ensure that the port is disabled. + */ + Ser2UTCR3 = 0; + Ser2HSCR0 = HSCR0_UART; + Ser2UTCR4 = si->utcr4; + Ser2UTCR0 = UTCR0_8BitData; + Ser2HSCR2 = HSCR2_TrDataH | HSCR2_RcDataL; + + /* + * Clear status register + */ + Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID; + + ret = sa1100_irda_set_speed(si, si->speed = 9600); + if (ret) { + Ser2UTCR3 = 0; + Ser2HSCR0 = 0; + + if (si->pdata->shutdown) + si->pdata->shutdown(si->dev); + } + + return ret; +} + +static void sa1100_irda_shutdown(struct sa1100_irda *si) +{ + /* + * Stop all DMA activity. + */ + sa1100_stop_dma(si->dma_rx.regs); + sa1100_stop_dma(si->dma_tx.regs); + + /* Disable the port. */ + Ser2UTCR3 = 0; + Ser2HSCR0 = 0; + + if (si->pdata->shutdown) + si->pdata->shutdown(si->dev); +} + static int sa1100_irda_start(struct net_device *dev) { struct sa1100_irda *si = netdev_priv(dev); @@ -1024,6 +956,74 @@ static int sa1100_irda_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +/* + * Suspend the IrDA interface. + */ +static int sa1100_irda_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct sa1100_irda *si; + + if (!dev) + return 0; + + si = netdev_priv(dev); + if (si->open) { + /* + * Stop the transmit queue + */ + netif_device_detach(dev); + disable_irq(dev->irq); + sa1100_irda_shutdown(si); + __sa1100_irda_set_power(si, 0); + } + + return 0; +} + +/* + * Resume the IrDA interface. + */ +static int sa1100_irda_resume(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct sa1100_irda *si; + + if (!dev) + return 0; + + si = netdev_priv(dev); + if (si->open) { + /* + * If we missed a speed change, initialise at the new speed + * directly. It is debatable whether this is actually + * required, but in the interests of continuing from where + * we left off it is desirable. The converse argument is + * that we should re-negotiate at 9600 baud again. + */ + if (si->newspeed) { + si->speed = si->newspeed; + si->newspeed = 0; + } + + sa1100_irda_startup(si); + __sa1100_irda_set_power(si, si->power); + enable_irq(dev->irq); + + /* + * This automatically wakes up the queue + */ + netif_device_attach(dev); + } + + return 0; +} +#else +#define sa1100_irda_suspend NULL +#define sa1100_irda_resume NULL +#endif + static struct platform_driver sa1100ir_driver = { .probe = sa1100_irda_probe, .remove = sa1100_irda_remove, -- cgit v1.2.3-59-g8ed1b From 0e888ee31566c3f5071474ddd68457a7ad2ae5ac Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 8 Jan 2012 16:30:44 +0000 Subject: NET: sa11x0-ir: factor out speed checks Whenever we complete a transmit, we always check for a speed change. This check was open coded in several places. Provide a helper function to do this instead. Signed-off-by: Russell King --- drivers/net/irda/sa1100_ir.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 32ac4a44ce76..bfae34fa7a9e 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -70,6 +70,8 @@ struct sa1100_irda { iobuff_t rx_buff; }; +static int sa1100_irda_set_speed(struct sa1100_irda *, int); + #define IS_FIR(si) ((si)->speed >= 4000000) #define HPSIR_MAX_RXLEN 2047 @@ -129,6 +131,14 @@ static void sa1100_irda_rx_dma_start(struct sa1100_irda *si) Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_RXE; } +static void sa1100_irda_check_speed(struct sa1100_irda *si) +{ + if (si->newspeed) { + sa1100_irda_set_speed(si, si->newspeed); + si->newspeed = 0; + } +} + /* * Set the IrDA communications speed. */ @@ -318,10 +328,7 @@ static void sa1100_irda_hpsir_irq(struct net_device *dev) Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID; Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE; - if (si->newspeed) { - sa1100_irda_set_speed(si, si->newspeed); - si->newspeed = 0; - } + sa1100_irda_check_speed(si); /* I'm hungry! */ netif_wake_queue(dev); @@ -492,10 +499,7 @@ static void sa1100_irda_txdma_irq(void *id) * here - we don't free the old dma_rx.skb. We don't need * to allocate a buffer either. */ - if (si->newspeed) { - sa1100_irda_set_speed(si, si->newspeed); - si->newspeed = 0; - } + sa1100_irda_check_speed(si); /* * Start reception. This disables the transmitter for @@ -538,10 +542,7 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) * If this is an empty frame, we can bypass a lot. */ if (skb->len == 0) { - if (si->newspeed) { - si->newspeed = 0; - sa1100_irda_set_speed(si, speed); - } + sa1100_irda_check_speed(si); dev_kfree_skb(skb); return NETDEV_TX_OK; } -- cgit v1.2.3-59-g8ed1b From 3d26db137ac3169623a132ea310d26af6a48bf88 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 8 Jan 2012 16:16:39 +0000 Subject: NET: sa11x0-ir: split SIR and FIR tx functions Split the SIR and FIR transmit functions, as they behave differently. Signed-off-by: Russell King --- drivers/net/irda/sa1100_ir.c | 118 ++++++++++++++++++++++++------------------- 1 file changed, 66 insertions(+), 52 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index bfae34fa7a9e..8b8cf4152604 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -68,6 +68,8 @@ struct sa1100_irda { iobuff_t tx_buff; iobuff_t rx_buff; + + int (*tx_start)(struct sk_buff *, struct net_device *, struct sa1100_irda *); }; static int sa1100_irda_set_speed(struct sa1100_irda *, int); @@ -139,6 +141,63 @@ static void sa1100_irda_check_speed(struct sa1100_irda *si) } } +/* + * HP-SIR format support. + */ +static int sa1100_irda_sir_tx_start(struct sk_buff *skb, struct net_device *dev, + struct sa1100_irda *si) +{ + si->tx_buff.data = si->tx_buff.head; + si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data, + si->tx_buff.truesize); + + /* + * Set the transmit interrupt enable. This will fire off an + * interrupt immediately. Note that we disable the receiver + * so we won't get spurious characters received. + */ + Ser2UTCR3 = UTCR3_TIE | UTCR3_TXE; + + dev_kfree_skb(skb); + + return NETDEV_TX_OK; +} + +/* + * FIR format support. + */ +static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev, + struct sa1100_irda *si) +{ + int mtt = irda_get_mtt(skb); + + si->dma_tx.skb = skb; + si->dma_tx.dma = dma_map_single(si->dev, skb->data, skb->len, + DMA_TO_DEVICE); + if (dma_mapping_error(si->dev, si->dma_tx.dma)) { + si->dma_tx.skb = NULL; + netif_wake_queue(dev); + dev->stats.tx_dropped++; + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + + sa1100_start_dma(si->dma_tx.regs, si->dma_tx.dma, skb->len); + + /* + * If we have a mean turn-around time, impose the specified + * specified delay. We could shorten this by timing from + * the point we received the packet. + */ + if (mtt) + udelay(mtt); + + Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_TXE; + + return NETDEV_TX_OK; +} + + /* * Set the IrDA communications speed. */ @@ -176,6 +235,7 @@ static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed) si->pdata->set_speed(si->dev, speed); si->speed = speed; + si->tx_start = sa1100_irda_sir_tx_start; local_irq_restore(flags); ret = 0; @@ -191,6 +251,7 @@ static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed) Ser2UTCR3 = 0; si->speed = speed; + si->tx_start = sa1100_irda_fir_tx_start; if (si->pdata->set_speed) si->pdata->set_speed(si->dev, speed); @@ -538,66 +599,19 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) if (speed != si->speed && speed != -1) si->newspeed = speed; - /* - * If this is an empty frame, we can bypass a lot. - */ + /* If this is an empty frame, we can bypass a lot. */ if (skb->len == 0) { sa1100_irda_check_speed(si); dev_kfree_skb(skb); return NETDEV_TX_OK; } - if (!IS_FIR(si)) { - netif_stop_queue(dev); - - si->tx_buff.data = si->tx_buff.head; - si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data, - si->tx_buff.truesize); - - /* - * Set the transmit interrupt enable. This will fire - * off an interrupt immediately. Note that we disable - * the receiver so we won't get spurious characteres - * received. - */ - Ser2UTCR3 = UTCR3_TIE | UTCR3_TXE; - - dev_kfree_skb(skb); - } else { - int mtt = irda_get_mtt(skb); - - /* - * We must not be transmitting... - */ - BUG_ON(si->dma_tx.skb); - - netif_stop_queue(dev); - - si->dma_tx.skb = skb; - si->dma_tx.dma = dma_map_single(si->dev, skb->data, - skb->len, DMA_TO_DEVICE); - if (dma_mapping_error(si->dev, si->dma_tx.dma)) { - si->dma_tx.skb = NULL; - netif_wake_queue(dev); - dev->stats.tx_dropped++; - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - sa1100_start_dma(si->dma_tx.regs, si->dma_tx.dma, skb->len); - - /* - * If we have a mean turn-around time, impose the specified - * specified delay. We could shorten this by timing from - * the point we received the packet. - */ - if (mtt) - udelay(mtt); + netif_stop_queue(dev); - Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_TXE; - } + /* We must not already have a skb to transmit... */ + BUG_ON(si->dma_tx.skb); - return NETDEV_TX_OK; + return si->tx_start(skb, dev, si); } static int -- cgit v1.2.3-59-g8ed1b From 374f77390ca99b401ee121616524ed32c54d5ad6 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 8 Jan 2012 16:26:15 +0000 Subject: NET: sa11x0-ir: indirect handling of SIR and FIR interrupts Use the same method for doing this as we do for the tx_start functions. Signed-off-by: Russell King --- drivers/net/irda/sa1100_ir.c | 50 +++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 26 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 8b8cf4152604..32dee3322679 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -70,6 +70,7 @@ struct sa1100_irda { iobuff_t rx_buff; int (*tx_start)(struct sk_buff *, struct net_device *, struct sa1100_irda *); + irqreturn_t (*irq)(struct net_device *, struct sa1100_irda *); }; static int sa1100_irda_set_speed(struct sa1100_irda *, int); @@ -197,6 +198,8 @@ static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev, return NETDEV_TX_OK; } +static irqreturn_t sa1100_irda_sir_irq(struct net_device *, struct sa1100_irda *); +static irqreturn_t sa1100_irda_fir_irq(struct net_device *, struct sa1100_irda *); /* * Set the IrDA communications speed. @@ -236,6 +239,7 @@ static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed) si->speed = speed; si->tx_start = sa1100_irda_sir_tx_start; + si->irq = sa1100_irda_sir_irq; local_irq_restore(flags); ret = 0; @@ -252,6 +256,7 @@ static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed) si->speed = speed; si->tx_start = sa1100_irda_fir_tx_start; + si->irq = sa1100_irda_fir_irq; if (si->pdata->set_speed) si->pdata->set_speed(si->dev, speed); @@ -304,9 +309,8 @@ sa1100_set_power(struct sa1100_irda *si, unsigned int state) /* * HP-SIR format interrupt service routines. */ -static void sa1100_irda_hpsir_irq(struct net_device *dev) +static irqreturn_t sa1100_irda_sir_irq(struct net_device *dev, struct sa1100_irda *si) { - struct sa1100_irda *si = netdev_priv(dev); int status; status = Ser2UTSR0; @@ -395,6 +399,8 @@ static void sa1100_irda_hpsir_irq(struct net_device *dev) netif_wake_queue(dev); } } + + return IRQ_HANDLED; } static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev) @@ -475,10 +481,8 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev * * No matter what, we disable RX, process, and the restart RX. */ -static void sa1100_irda_fir_irq(struct net_device *dev) +static irqreturn_t sa1100_irda_fir_irq(struct net_device *dev, struct sa1100_irda *si) { - struct sa1100_irda *si = netdev_priv(dev); - /* * Stop RX DMA */ @@ -520,16 +524,16 @@ static void sa1100_irda_fir_irq(struct net_device *dev) * No matter what happens, we must restart reception. */ sa1100_irda_rx_dma_start(si); + + return IRQ_HANDLED; } static irqreturn_t sa1100_irda_irq(int irq, void *dev_id) { struct net_device *dev = dev_id; - if (IS_FIR(((struct sa1100_irda *)netdev_priv(dev)))) - sa1100_irda_fir_irq(dev); - else - sa1100_irda_hpsir_irq(dev); - return IRQ_HANDLED; + struct sa1100_irda *si = netdev_priv(dev); + + return si->irq(dev, si); } /* @@ -728,10 +732,6 @@ static int sa1100_irda_start(struct net_device *dev) si->speed = 9600; - err = request_irq(dev->irq, sa1100_irda_irq, 0, dev->name, dev); - if (err) - goto err_irq; - err = sa1100_request_dma(DMA_Ser2HSSPRd, "IrDA receive", NULL, NULL, &si->dma_rx.regs); if (err) @@ -742,11 +742,6 @@ static int sa1100_irda_start(struct net_device *dev) if (err) goto err_tx_dma; - /* - * The interrupt must remain disabled for now. - */ - disable_irq(dev->irq); - /* * Setup the serial port for the specified speed. */ @@ -762,15 +757,21 @@ static int sa1100_irda_start(struct net_device *dev) if (!si->irlap) goto err_irlap; + err = request_irq(dev->irq, sa1100_irda_irq, 0, dev->name, dev); + if (err) + goto err_irq; + /* * Now enable the interrupt and start the queue */ si->open = 1; sa1100_set_power(si, power_level); /* low power mode */ - enable_irq(dev->irq); + netif_start_queue(dev); return 0; +err_irq: + irlap_close(si->irlap); err_irlap: si->open = 0; sa1100_irda_shutdown(si); @@ -779,8 +780,6 @@ err_startup: err_tx_dma: sa1100_free_dma(si->dma_rx.regs); err_rx_dma: - free_irq(dev->irq, dev); -err_irq: return err; } @@ -789,7 +788,9 @@ static int sa1100_irda_stop(struct net_device *dev) struct sa1100_irda *si = netdev_priv(dev); struct sk_buff *skb; - disable_irq(dev->irq); + netif_stop_queue(dev); + + si->open = 0; sa1100_irda_shutdown(si); /* @@ -818,9 +819,6 @@ static int sa1100_irda_stop(struct net_device *dev) si->irlap = NULL; } - netif_stop_queue(dev); - si->open = 0; - /* * Free resources */ -- cgit v1.2.3-59-g8ed1b From a6b2ea66d630ad0687a1ac25d5a6afb282bd364a Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 8 Jan 2012 17:10:01 +0000 Subject: NET: sa11x0-ir: move SIR and FIR interrupt support Move the interrupt handlers to the SIR and FIR sections of the file. This improves the localization of the protocol handlers. Signed-off-by: Russell King --- drivers/net/irda/sa1100_ir.c | 290 +++++++++++++++++++++---------------------- 1 file changed, 141 insertions(+), 149 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 32dee3322679..61b42d1265b4 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -164,151 +164,6 @@ static int sa1100_irda_sir_tx_start(struct sk_buff *skb, struct net_device *dev, return NETDEV_TX_OK; } -/* - * FIR format support. - */ -static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev, - struct sa1100_irda *si) -{ - int mtt = irda_get_mtt(skb); - - si->dma_tx.skb = skb; - si->dma_tx.dma = dma_map_single(si->dev, skb->data, skb->len, - DMA_TO_DEVICE); - if (dma_mapping_error(si->dev, si->dma_tx.dma)) { - si->dma_tx.skb = NULL; - netif_wake_queue(dev); - dev->stats.tx_dropped++; - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - sa1100_start_dma(si->dma_tx.regs, si->dma_tx.dma, skb->len); - - /* - * If we have a mean turn-around time, impose the specified - * specified delay. We could shorten this by timing from - * the point we received the packet. - */ - if (mtt) - udelay(mtt); - - Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_TXE; - - return NETDEV_TX_OK; -} - -static irqreturn_t sa1100_irda_sir_irq(struct net_device *, struct sa1100_irda *); -static irqreturn_t sa1100_irda_fir_irq(struct net_device *, struct sa1100_irda *); - -/* - * Set the IrDA communications speed. - */ -static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed) -{ - unsigned long flags; - int brd, ret = -EINVAL; - - switch (speed) { - case 9600: case 19200: case 38400: - case 57600: case 115200: - brd = 3686400 / (16 * speed) - 1; - - /* - * Stop the receive DMA. - */ - if (IS_FIR(si)) - sa1100_stop_dma(si->dma_rx.regs); - - local_irq_save(flags); - - Ser2UTCR3 = 0; - Ser2HSCR0 = HSCR0_UART; - - Ser2UTCR1 = brd >> 8; - Ser2UTCR2 = brd; - - /* - * Clear status register - */ - Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID; - Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE; - - if (si->pdata->set_speed) - si->pdata->set_speed(si->dev, speed); - - si->speed = speed; - si->tx_start = sa1100_irda_sir_tx_start; - si->irq = sa1100_irda_sir_irq; - - local_irq_restore(flags); - ret = 0; - break; - - case 4000000: - local_irq_save(flags); - - si->hscr0 = 0; - - Ser2HSSR0 = 0xff; - Ser2HSCR0 = si->hscr0 | HSCR0_HSSP; - Ser2UTCR3 = 0; - - si->speed = speed; - si->tx_start = sa1100_irda_fir_tx_start; - si->irq = sa1100_irda_fir_irq; - - if (si->pdata->set_speed) - si->pdata->set_speed(si->dev, speed); - - sa1100_irda_rx_alloc(si); - sa1100_irda_rx_dma_start(si); - - local_irq_restore(flags); - - break; - - default: - break; - } - - return ret; -} - -/* - * Control the power state of the IrDA transmitter. - * State: - * 0 - off - * 1 - short range, lowest power - * 2 - medium range, medium power - * 3 - maximum range, high power - * - * Currently, only assabet is known to support this. - */ -static int -__sa1100_irda_set_power(struct sa1100_irda *si, unsigned int state) -{ - int ret = 0; - if (si->pdata->set_power) - ret = si->pdata->set_power(si->dev, state); - return ret; -} - -static inline int -sa1100_set_power(struct sa1100_irda *si, unsigned int state) -{ - int ret; - - ret = __sa1100_irda_set_power(si, state); - if (ret == 0) - si->power = state; - - return ret; -} - -/* - * HP-SIR format interrupt service routines. - */ static irqreturn_t sa1100_irda_sir_irq(struct net_device *dev, struct sa1100_irda *si) { int status; @@ -403,6 +258,40 @@ static irqreturn_t sa1100_irda_sir_irq(struct net_device *dev, struct sa1100_ird return IRQ_HANDLED; } +/* + * FIR format support. + */ +static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev, + struct sa1100_irda *si) +{ + int mtt = irda_get_mtt(skb); + + si->dma_tx.skb = skb; + si->dma_tx.dma = dma_map_single(si->dev, skb->data, skb->len, + DMA_TO_DEVICE); + if (dma_mapping_error(si->dev, si->dma_tx.dma)) { + si->dma_tx.skb = NULL; + netif_wake_queue(dev); + dev->stats.tx_dropped++; + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + + sa1100_start_dma(si->dma_tx.regs, si->dma_tx.dma, skb->len); + + /* + * If we have a mean turn-around time, impose the specified + * specified delay. We could shorten this by timing from + * the point we received the packet. + */ + if (mtt) + udelay(mtt); + + Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_TXE; + + return NETDEV_TX_OK; +} + static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev) { struct sk_buff *skb = si->dma_rx.skb; @@ -476,10 +365,8 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev } /* - * FIR format interrupt service routine. We only have to - * handle RX events; transmit events go via the TX DMA handler. - * - * No matter what, we disable RX, process, and the restart RX. + * We only have to handle RX events here; transmit events go via the TX + * DMA handler. We disable RX, process, and the restart RX. */ static irqreturn_t sa1100_irda_fir_irq(struct net_device *dev, struct sa1100_irda *si) { @@ -528,6 +415,111 @@ static irqreturn_t sa1100_irda_fir_irq(struct net_device *dev, struct sa1100_ird return IRQ_HANDLED; } +/* + * Set the IrDA communications speed. + */ +static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed) +{ + unsigned long flags; + int brd, ret = -EINVAL; + + switch (speed) { + case 9600: case 19200: case 38400: + case 57600: case 115200: + brd = 3686400 / (16 * speed) - 1; + + /* + * Stop the receive DMA. + */ + if (IS_FIR(si)) + sa1100_stop_dma(si->dma_rx.regs); + + local_irq_save(flags); + + Ser2UTCR3 = 0; + Ser2HSCR0 = HSCR0_UART; + + Ser2UTCR1 = brd >> 8; + Ser2UTCR2 = brd; + + /* + * Clear status register + */ + Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID; + Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE; + + if (si->pdata->set_speed) + si->pdata->set_speed(si->dev, speed); + + si->speed = speed; + si->tx_start = sa1100_irda_sir_tx_start; + si->irq = sa1100_irda_sir_irq; + + local_irq_restore(flags); + ret = 0; + break; + + case 4000000: + local_irq_save(flags); + + si->hscr0 = 0; + + Ser2HSSR0 = 0xff; + Ser2HSCR0 = si->hscr0 | HSCR0_HSSP; + Ser2UTCR3 = 0; + + si->speed = speed; + si->tx_start = sa1100_irda_fir_tx_start; + si->irq = sa1100_irda_fir_irq; + + if (si->pdata->set_speed) + si->pdata->set_speed(si->dev, speed); + + sa1100_irda_rx_alloc(si); + sa1100_irda_rx_dma_start(si); + + local_irq_restore(flags); + + break; + + default: + break; + } + + return ret; +} + +/* + * Control the power state of the IrDA transmitter. + * State: + * 0 - off + * 1 - short range, lowest power + * 2 - medium range, medium power + * 3 - maximum range, high power + * + * Currently, only assabet is known to support this. + */ +static int +__sa1100_irda_set_power(struct sa1100_irda *si, unsigned int state) +{ + int ret = 0; + if (si->pdata->set_power) + ret = si->pdata->set_power(si->dev, state); + return ret; +} + +static inline int +sa1100_set_power(struct sa1100_irda *si, unsigned int state) +{ + int ret; + + ret = __sa1100_irda_set_power(si, state); + if (ret == 0) + si->power = state; + + return ret; +} + static irqreturn_t sa1100_irda_irq(int irq, void *dev_id) { struct net_device *dev = dev_id; -- cgit v1.2.3-59-g8ed1b From 26f2bee1a3063ddd89f76a75b99adb32636f3513 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 8 Jan 2012 17:48:02 +0000 Subject: NET: sa11x0-ir: move sa1100_irda_txdma_irq Move the FIR DMA transmit completion function along-side the other FIR protocol functions. Signed-off-by: Russell King --- drivers/net/irda/sa1100_ir.c | 108 +++++++++++++++++++++---------------------- 1 file changed, 53 insertions(+), 55 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 61b42d1265b4..0b5a2e2a7be4 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -261,6 +261,57 @@ static irqreturn_t sa1100_irda_sir_irq(struct net_device *dev, struct sa1100_ird /* * FIR format support. */ +static void sa1100_irda_firtxdma_irq(void *id) +{ + struct net_device *dev = id; + struct sa1100_irda *si = netdev_priv(dev); + struct sk_buff *skb; + + /* + * Wait for the transmission to complete. Unfortunately, + * the hardware doesn't give us an interrupt to indicate + * "end of frame". + */ + do + rmb(); + while (!(Ser2HSSR0 & HSSR0_TUR) || Ser2HSSR1 & HSSR1_TBY); + + /* + * Clear the transmit underrun bit. + */ + Ser2HSSR0 = HSSR0_TUR; + + /* + * Do we need to change speed? Note that we're lazy + * here - we don't free the old dma_rx.skb. We don't need + * to allocate a buffer either. + */ + sa1100_irda_check_speed(si); + + /* + * Start reception. This disables the transmitter for + * us. This will be using the existing RX buffer. + */ + sa1100_irda_rx_dma_start(si); + + /* Account and free the packet. */ + skb = si->dma_tx.skb; + if (skb) { + dma_unmap_single(si->dev, si->dma_tx.dma, skb->len, + DMA_TO_DEVICE); + dev->stats.tx_packets ++; + dev->stats.tx_bytes += skb->len; + dev_kfree_skb_irq(skb); + si->dma_tx.skb = NULL; + } + + /* + * Make sure that the TX queue is available for sending + * (for retries). TX has priority over RX at all times. + */ + netif_wake_queue(dev); +} + static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev, struct sa1100_irda *si) { @@ -528,60 +579,6 @@ static irqreturn_t sa1100_irda_irq(int irq, void *dev_id) return si->irq(dev, si); } -/* - * TX DMA completion handler. - */ -static void sa1100_irda_txdma_irq(void *id) -{ - struct net_device *dev = id; - struct sa1100_irda *si = netdev_priv(dev); - struct sk_buff *skb; - - /* - * Wait for the transmission to complete. Unfortunately, - * the hardware doesn't give us an interrupt to indicate - * "end of frame". - */ - do - rmb(); - while (!(Ser2HSSR0 & HSSR0_TUR) || Ser2HSSR1 & HSSR1_TBY); - - /* - * Clear the transmit underrun bit. - */ - Ser2HSSR0 = HSSR0_TUR; - - /* - * Do we need to change speed? Note that we're lazy - * here - we don't free the old dma_rx.skb. We don't need - * to allocate a buffer either. - */ - sa1100_irda_check_speed(si); - - /* - * Start reception. This disables the transmitter for - * us. This will be using the existing RX buffer. - */ - sa1100_irda_rx_dma_start(si); - - /* Account and free the packet. */ - skb = si->dma_tx.skb; - if (skb) { - dma_unmap_single(si->dev, si->dma_tx.dma, skb->len, - DMA_TO_DEVICE); - dev->stats.tx_packets ++; - dev->stats.tx_bytes += skb->len; - dev_kfree_skb_irq(skb); - si->dma_tx.skb = NULL; - } - - /* - * Make sure that the TX queue is available for sending - * (for retries). TX has priority over RX at all times. - */ - netif_wake_queue(dev); -} - static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) { struct sa1100_irda *si = netdev_priv(dev); @@ -730,7 +727,8 @@ static int sa1100_irda_start(struct net_device *dev) goto err_rx_dma; err = sa1100_request_dma(DMA_Ser2HSSPWr, "IrDA transmit", - sa1100_irda_txdma_irq, dev, &si->dma_tx.regs); + sa1100_irda_firtxdma_irq, dev, + &si->dma_tx.regs); if (err) goto err_tx_dma; -- cgit v1.2.3-59-g8ed1b From 6a7f4911a470fede7d40746487fb1e4a95657efd Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 8 Jan 2012 20:49:28 +0000 Subject: NET: sa11x0-ir: get rid of si->hscr0 si->hscr0 is initialized to zero, and never changed. Get rid of this redundant variable. Signed-off-by: Russell King --- drivers/net/irda/sa1100_ir.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 0b5a2e2a7be4..d428dd0a8bce 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -50,7 +50,6 @@ struct sa1100_buf { }; struct sa1100_irda { - unsigned char hscr0; unsigned char utcr4; unsigned char power; unsigned char open; @@ -124,14 +123,14 @@ static void sa1100_irda_rx_dma_start(struct sa1100_irda *si) /* * First empty receive FIFO */ - Ser2HSCR0 = si->hscr0 | HSCR0_HSSP; + Ser2HSCR0 = HSCR0_HSSP; /* * Enable the DMA, receiver and receive interrupt. */ sa1100_clear_dma(si->dma_rx.regs); sa1100_start_dma(si->dma_rx.regs, si->dma_rx.dma, HPSIR_MAX_RXLEN); - Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_RXE; + Ser2HSCR0 = HSCR0_HSSP | HSCR0_RXE; } static void sa1100_irda_check_speed(struct sa1100_irda *si) @@ -338,7 +337,7 @@ static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev, if (mtt) udelay(mtt); - Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_TXE; + Ser2HSCR0 = HSCR0_HSSP | HSCR0_TXE; return NETDEV_TX_OK; } @@ -440,7 +439,7 @@ static irqreturn_t sa1100_irda_fir_irq(struct net_device *dev, struct sa1100_ird /* * Clear out the DMA... */ - Ser2HSCR0 = si->hscr0 | HSCR0_HSSP; + Ser2HSCR0 = HSCR0_HSSP; /* * Clear selected status bits now, so we @@ -513,10 +512,8 @@ static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed) case 4000000: local_irq_save(flags); - si->hscr0 = 0; - Ser2HSSR0 = 0xff; - Ser2HSCR0 = si->hscr0 | HSCR0_HSSP; + Ser2HSCR0 = HSCR0_HSSP; Ser2UTCR3 = 0; si->speed = speed; -- cgit v1.2.3-59-g8ed1b From 32273f50608e9b98116622e32187cbd139c09716 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 12 Jan 2012 12:45:00 +0000 Subject: NET: sa11x0-ir: convert to use scatterlist DMA API Convert the sa11x0 IrDA driver to use the scatterlist DMA API. This is a preparatory patch for converting the driver to use the DMA engine API, which requires a struct scatterlist for every transfer. Signed-off-by: Russell King --- drivers/net/irda/sa1100_ir.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index d428dd0a8bce..86d296ed69a7 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -45,7 +45,7 @@ static int max_rate = 4000000; struct sa1100_buf { struct sk_buff *skb; - dma_addr_t dma; + struct scatterlist sg; dma_regs_t *regs; }; @@ -98,10 +98,8 @@ static int sa1100_irda_rx_alloc(struct sa1100_irda *si) */ skb_reserve(si->dma_rx.skb, 1); - si->dma_rx.dma = dma_map_single(si->dev, si->dma_rx.skb->data, - HPSIR_MAX_RXLEN, - DMA_FROM_DEVICE); - if (dma_mapping_error(si->dev, si->dma_rx.dma)) { + sg_set_buf(&si->dma_rx.sg, si->dma_rx.skb->data, HPSIR_MAX_RXLEN); + if (dma_map_sg(si->dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE) == 0) { dev_kfree_skb_any(si->dma_rx.skb); return -ENOMEM; } @@ -129,7 +127,8 @@ static void sa1100_irda_rx_dma_start(struct sa1100_irda *si) * Enable the DMA, receiver and receive interrupt. */ sa1100_clear_dma(si->dma_rx.regs); - sa1100_start_dma(si->dma_rx.regs, si->dma_rx.dma, HPSIR_MAX_RXLEN); + sa1100_start_dma(si->dma_rx.regs, sg_dma_address(&si->dma_rx.sg), + sg_dma_len(&si->dma_rx.sg)); Ser2HSCR0 = HSCR0_HSSP | HSCR0_RXE; } @@ -296,8 +295,8 @@ static void sa1100_irda_firtxdma_irq(void *id) /* Account and free the packet. */ skb = si->dma_tx.skb; if (skb) { - dma_unmap_single(si->dev, si->dma_tx.dma, skb->len, - DMA_TO_DEVICE); + dma_unmap_sg(si->dev, &si->dma_tx.sg, 1, + DMA_TO_DEVICE); dev->stats.tx_packets ++; dev->stats.tx_bytes += skb->len; dev_kfree_skb_irq(skb); @@ -317,9 +316,8 @@ static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev, int mtt = irda_get_mtt(skb); si->dma_tx.skb = skb; - si->dma_tx.dma = dma_map_single(si->dev, skb->data, skb->len, - DMA_TO_DEVICE); - if (dma_mapping_error(si->dev, si->dma_tx.dma)) { + sg_set_buf(&si->dma_tx.sg, skb->data, skb->len); + if (dma_map_sg(si->dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE) == 0) { si->dma_tx.skb = NULL; netif_wake_queue(dev); dev->stats.tx_dropped++; @@ -327,7 +325,8 @@ static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev, return NETDEV_TX_OK; } - sa1100_start_dma(si->dma_tx.regs, si->dma_tx.dma, skb->len); + sa1100_start_dma(si->dma_tx.regs, sg_dma_address(&si->dma_tx.sg), + sg_dma_len(&si->dma_tx.sg)); /* * If we have a mean turn-around time, impose the specified @@ -357,10 +356,10 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev * Get the current data position. */ dma_addr = sa1100_get_dma_pos(si->dma_rx.regs); - len = dma_addr - si->dma_rx.dma; + len = dma_addr - sg_dma_address(&si->dma_rx.sg); if (len > HPSIR_MAX_RXLEN) len = HPSIR_MAX_RXLEN; - dma_unmap_single(si->dev, si->dma_rx.dma, len, DMA_FROM_DEVICE); + dma_unmap_sg(si->dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE); do { /* @@ -408,9 +407,7 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev * Remap the buffer - it was previously mapped, and we * hope that this succeeds. */ - si->dma_rx.dma = dma_map_single(si->dev, si->dma_rx.skb->data, - HPSIR_MAX_RXLEN, - DMA_FROM_DEVICE); + dma_map_sg(si->dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE); } } @@ -786,16 +783,16 @@ static int sa1100_irda_stop(struct net_device *dev) */ skb = si->dma_rx.skb; if (skb) { - dma_unmap_single(si->dev, si->dma_rx.dma, HPSIR_MAX_RXLEN, - DMA_FROM_DEVICE); + dma_unmap_sg(si->dev, &si->dma_rx.sg, 1, + DMA_FROM_DEVICE); dev_kfree_skb(skb); si->dma_rx.skb = NULL; } skb = si->dma_tx.skb; if (skb) { - dma_unmap_single(si->dev, si->dma_tx.dma, skb->len, - DMA_TO_DEVICE); + dma_unmap_sg(si->dev, &si->dma_tx.sg, 1, + DMA_TO_DEVICE); dev_kfree_skb(skb); si->dma_tx.skb = NULL; } @@ -871,6 +868,9 @@ static int sa1100_irda_probe(struct platform_device *pdev) si->dev = &pdev->dev; si->pdata = pdev->dev.platform_data; + sg_init_table(&si->dma_rx.sg, 1); + sg_init_table(&si->dma_tx.sg, 1); + /* * Initialise the HP-SIR buffers */ -- cgit v1.2.3-59-g8ed1b From 04b7fc4dec4fcb61dbe022bbaffda8ea37c39430 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 12 Jan 2012 13:51:10 +0000 Subject: NET: sa11x0-ir: fix size of SIR transmit buffer The SIR transmit buffer was being allocated as 4000 bytes. IrDA now has constants for the buffer sizes, and defines the maximum wrapped SIR packet to be 4269 bytes as indicated by IRDA_SIR_MAX_FRAME. Use this definition to allocate the transmit buffer instead. Signed-off-by: Russell King --- drivers/net/irda/sa1100_ir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 86d296ed69a7..be67bdc0ca02 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -877,7 +877,7 @@ static int sa1100_irda_probe(struct platform_device *pdev) err = sa1100_irda_init_iobuf(&si->rx_buff, 14384); if (err) goto err_mem_5; - err = sa1100_irda_init_iobuf(&si->tx_buff, 4000); + err = sa1100_irda_init_iobuf(&si->tx_buff, IRDA_SIR_MAX_FRAME); if (err) goto err_mem_5; -- cgit v1.2.3-59-g8ed1b From 3c500a35544d6270b127bce7d4c5a15ef454b9e2 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 12 Jan 2012 13:56:28 +0000 Subject: NET: sa11x0-ir: split si->dev for IrDA transmit and receive buffers The sa11x0-ir device is not the device which is doing the DMA, the DMA is being performed by a separate DMA engine. Split the struct device associated with each DMA channel from the main struct device, but for the time being initialize it from the main struct device. This is another preparatory step to converting this driver to use the DMA engine API. Signed-off-by: Russell King --- drivers/net/irda/sa1100_ir.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index be67bdc0ca02..9c748f38b9d5 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -44,6 +44,7 @@ static int tx_lpm; static int max_rate = 4000000; struct sa1100_buf { + struct device *dev; struct sk_buff *skb; struct scatterlist sg; dma_regs_t *regs; @@ -99,7 +100,7 @@ static int sa1100_irda_rx_alloc(struct sa1100_irda *si) skb_reserve(si->dma_rx.skb, 1); sg_set_buf(&si->dma_rx.sg, si->dma_rx.skb->data, HPSIR_MAX_RXLEN); - if (dma_map_sg(si->dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE) == 0) { + if (dma_map_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE) == 0) { dev_kfree_skb_any(si->dma_rx.skb); return -ENOMEM; } @@ -295,7 +296,7 @@ static void sa1100_irda_firtxdma_irq(void *id) /* Account and free the packet. */ skb = si->dma_tx.skb; if (skb) { - dma_unmap_sg(si->dev, &si->dma_tx.sg, 1, + dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE); dev->stats.tx_packets ++; dev->stats.tx_bytes += skb->len; @@ -317,7 +318,7 @@ static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev, si->dma_tx.skb = skb; sg_set_buf(&si->dma_tx.sg, skb->data, skb->len); - if (dma_map_sg(si->dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE) == 0) { + if (dma_map_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE) == 0) { si->dma_tx.skb = NULL; netif_wake_queue(dev); dev->stats.tx_dropped++; @@ -359,7 +360,7 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev len = dma_addr - sg_dma_address(&si->dma_rx.sg); if (len > HPSIR_MAX_RXLEN) len = HPSIR_MAX_RXLEN; - dma_unmap_sg(si->dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE); + dma_unmap_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE); do { /* @@ -407,7 +408,7 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev * Remap the buffer - it was previously mapped, and we * hope that this succeeds. */ - dma_map_sg(si->dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE); + dma_map_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE); } } @@ -726,6 +727,9 @@ static int sa1100_irda_start(struct net_device *dev) if (err) goto err_tx_dma; + si->dma_rx.dev = si->dev; + si->dma_tx.dev = si->dev; + /* * Setup the serial port for the specified speed. */ @@ -783,7 +787,7 @@ static int sa1100_irda_stop(struct net_device *dev) */ skb = si->dma_rx.skb; if (skb) { - dma_unmap_sg(si->dev, &si->dma_rx.sg, 1, + dma_unmap_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE); dev_kfree_skb(skb); si->dma_rx.skb = NULL; @@ -791,7 +795,7 @@ static int sa1100_irda_stop(struct net_device *dev) skb = si->dma_tx.skb; if (skb) { - dma_unmap_sg(si->dev, &si->dma_tx.sg, 1, + dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE); dev_kfree_skb(skb); si->dma_tx.skb = NULL; -- cgit v1.2.3-59-g8ed1b From bf95154ff6c84e04afd9ba7f2b54a4628beefdb9 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 13 Jan 2012 11:48:13 +0000 Subject: NET: sa11x0-ir: convert sa11x0-ir driver to use DMA engine API Convert the sa11x0 IrDA driver to use the sa11x0 DMA engine driver rather than our own platform specific DMA API. Signed-off-by: Russell King --- drivers/net/irda/Kconfig | 2 +- drivers/net/irda/sa1100_ir.c | 120 ++++++++++++++++++++++++++++++++----------- 2 files changed, 92 insertions(+), 30 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index e535137eb2d0..468047866c8c 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig @@ -356,7 +356,7 @@ config VLSI_FIR config SA1100_FIR tristate "SA1100 Internal IR" - depends on ARCH_SA1100 && IRDA + depends on ARCH_SA1100 && IRDA && DMA_SA11X0 config VIA_FIR tristate "VIA VT8231/VT1211 SIR/MIR/FIR" diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 9c748f38b9d5..620a48d00e2b 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -30,12 +30,13 @@ #include #include #include +#include +#include #include #include #include -#include #include #include @@ -47,7 +48,8 @@ struct sa1100_buf { struct device *dev; struct sk_buff *skb; struct scatterlist sg; - dma_regs_t *regs; + struct dma_chan *chan; + dma_cookie_t cookie; }; struct sa1100_irda { @@ -79,6 +81,75 @@ static int sa1100_irda_set_speed(struct sa1100_irda *, int); #define HPSIR_MAX_RXLEN 2047 +static struct dma_slave_config sa1100_irda_fir_rx = { + .direction = DMA_FROM_DEVICE, + .src_addr = __PREG(Ser2HSDR), + .src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, + .src_maxburst = 8, +}; + +static struct dma_slave_config sa1100_irda_fir_tx = { + .direction = DMA_TO_DEVICE, + .dst_addr = __PREG(Ser2HSDR), + .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, + .dst_maxburst = 8, +}; + +static unsigned sa1100_irda_dma_xferred(struct sa1100_buf *buf) +{ + struct dma_chan *chan = buf->chan; + struct dma_tx_state state; + enum dma_status status; + + status = chan->device->device_tx_status(chan, buf->cookie, &state); + if (status != DMA_PAUSED) + return 0; + + return sg_dma_len(&buf->sg) - state.residue; +} + +static int sa1100_irda_dma_request(struct device *dev, struct sa1100_buf *buf, + const char *name, struct dma_slave_config *cfg) +{ + dma_cap_mask_t m; + int ret; + + dma_cap_zero(m); + dma_cap_set(DMA_SLAVE, m); + + buf->chan = dma_request_channel(m, sa11x0_dma_filter_fn, (void *)name); + if (!buf->chan) { + dev_err(dev, "unable to request DMA channel for %s\n", + name); + return -ENOENT; + } + + ret = dmaengine_slave_config(buf->chan, cfg); + if (ret) + dev_warn(dev, "DMA slave_config for %s returned %d\n", + name, ret); + + buf->dev = buf->chan->device->dev; + + return 0; +} + +static void sa1100_irda_dma_start(struct sa1100_buf *buf, + enum dma_transfer_direction dir, dma_async_tx_callback cb, void *cb_p) +{ + struct dma_async_tx_descriptor *desc; + struct dma_chan *chan = buf->chan; + + desc = chan->device->device_prep_slave_sg(chan, &buf->sg, 1, dir, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (desc) { + desc->callback = cb; + desc->callback_param = cb_p; + buf->cookie = dmaengine_submit(desc); + dma_async_issue_pending(chan); + } +} + /* * Allocate and map the receive buffer, unless it is already allocated. */ @@ -127,9 +198,9 @@ static void sa1100_irda_rx_dma_start(struct sa1100_irda *si) /* * Enable the DMA, receiver and receive interrupt. */ - sa1100_clear_dma(si->dma_rx.regs); - sa1100_start_dma(si->dma_rx.regs, sg_dma_address(&si->dma_rx.sg), - sg_dma_len(&si->dma_rx.sg)); + dmaengine_terminate_all(si->dma_rx.chan); + sa1100_irda_dma_start(&si->dma_rx, DMA_DEV_TO_MEM, NULL, NULL); + Ser2HSCR0 = HSCR0_HSSP | HSCR0_RXE; } @@ -326,8 +397,7 @@ static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev, return NETDEV_TX_OK; } - sa1100_start_dma(si->dma_tx.regs, sg_dma_address(&si->dma_tx.sg), - sg_dma_len(&si->dma_tx.sg)); + sa1100_irda_dma_start(&si->dma_tx, DMA_MEM_TO_DEV, sa1100_irda_firtxdma_irq, dev); /* * If we have a mean turn-around time, impose the specified @@ -345,7 +415,6 @@ static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev, static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev) { struct sk_buff *skb = si->dma_rx.skb; - dma_addr_t dma_addr; unsigned int len, stat, data; if (!skb) { @@ -356,8 +425,7 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev /* * Get the current data position. */ - dma_addr = sa1100_get_dma_pos(si->dma_rx.regs); - len = dma_addr - sg_dma_address(&si->dma_rx.sg); + len = sa1100_irda_dma_xferred(&si->dma_rx); if (len > HPSIR_MAX_RXLEN) len = HPSIR_MAX_RXLEN; dma_unmap_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE); @@ -421,7 +489,7 @@ static irqreturn_t sa1100_irda_fir_irq(struct net_device *dev, struct sa1100_ird /* * Stop RX DMA */ - sa1100_stop_dma(si->dma_rx.regs); + dmaengine_pause(si->dma_rx.chan); /* * Framing error - we throw away the packet completely. @@ -476,11 +544,9 @@ static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed) case 57600: case 115200: brd = 3686400 / (16 * speed) - 1; - /* - * Stop the receive DMA. - */ + /* Stop the receive DMA, and configure transmit. */ if (IS_FIR(si)) - sa1100_stop_dma(si->dma_rx.regs); + dmaengine_terminate_all(si->dma_rx.chan); local_irq_save(flags); @@ -698,8 +764,8 @@ static void sa1100_irda_shutdown(struct sa1100_irda *si) /* * Stop all DMA activity. */ - sa1100_stop_dma(si->dma_rx.regs); - sa1100_stop_dma(si->dma_tx.regs); + dmaengine_terminate_all(si->dma_rx.chan); + dmaengine_terminate_all(si->dma_tx.chan); /* Disable the port. */ Ser2UTCR3 = 0; @@ -716,20 +782,16 @@ static int sa1100_irda_start(struct net_device *dev) si->speed = 9600; - err = sa1100_request_dma(DMA_Ser2HSSPRd, "IrDA receive", - NULL, NULL, &si->dma_rx.regs); + err = sa1100_irda_dma_request(si->dev, &si->dma_rx, "Ser2ICPRc", + &sa1100_irda_fir_rx); if (err) goto err_rx_dma; - err = sa1100_request_dma(DMA_Ser2HSSPWr, "IrDA transmit", - sa1100_irda_firtxdma_irq, dev, - &si->dma_tx.regs); + err = sa1100_irda_dma_request(si->dev, &si->dma_tx, "Ser2ICPTr", + &sa1100_irda_sir_tx); if (err) goto err_tx_dma; - si->dma_rx.dev = si->dev; - si->dma_tx.dev = si->dev; - /* * Setup the serial port for the specified speed. */ @@ -764,9 +826,9 @@ err_irlap: si->open = 0; sa1100_irda_shutdown(si); err_startup: - sa1100_free_dma(si->dma_tx.regs); + dma_release_channel(si->dma_tx.chan); err_tx_dma: - sa1100_free_dma(si->dma_rx.regs); + dma_release_channel(si->dma_rx.chan); err_rx_dma: return err; } @@ -810,8 +872,8 @@ static int sa1100_irda_stop(struct net_device *dev) /* * Free resources */ - sa1100_free_dma(si->dma_tx.regs); - sa1100_free_dma(si->dma_rx.regs); + dma_release_channel(si->dma_tx.chan); + dma_release_channel(si->dma_rx.chan); free_irq(dev->irq, dev); sa1100_set_power(si, 0); -- cgit v1.2.3-59-g8ed1b From d138dacb4b8255c02e4380ce2aadab758a99d2c1 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 13 Jan 2012 11:50:03 +0000 Subject: NET: sa11x0-ir: add DMA support for SIR transmit mode As the DMA engine API allows DMA channels to be reconfigured on the fly, we can now support switching the DMA channel configuration to support SIR transmit DMA without needing to claim an additional physical DMA channel - thereby using up half the DMA channels just for one driver. Signed-off-by: Russell King --- drivers/net/irda/sa1100_ir.c | 103 +++++++++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 44 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 620a48d00e2b..a0d1913a58d3 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -81,6 +81,13 @@ static int sa1100_irda_set_speed(struct sa1100_irda *, int); #define HPSIR_MAX_RXLEN 2047 +static struct dma_slave_config sa1100_irda_sir_tx = { + .direction = DMA_TO_DEVICE, + .dst_addr = __PREG(Ser2UTDR), + .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, + .dst_maxburst = 4, +}; + static struct dma_slave_config sa1100_irda_fir_rx = { .direction = DMA_FROM_DEVICE, .src_addr = __PREG(Ser2HSDR), @@ -215,6 +222,36 @@ static void sa1100_irda_check_speed(struct sa1100_irda *si) /* * HP-SIR format support. */ +static void sa1100_irda_sirtxdma_irq(void *id) +{ + struct net_device *dev = id; + struct sa1100_irda *si = netdev_priv(dev); + + dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE); + dev_kfree_skb(si->dma_tx.skb); + si->dma_tx.skb = NULL; + + dev->stats.tx_packets++; + dev->stats.tx_bytes += sg_dma_len(&si->dma_tx.sg); + + /* We need to ensure that the transmitter has finished. */ + do + rmb(); + while (Ser2UTSR1 & UTSR1_TBY); + + /* + * Ok, we've finished transmitting. Now enable the receiver. + * Sometimes we get a receive IRQ immediately after a transmit... + */ + Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID; + Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE; + + sa1100_irda_check_speed(si); + + /* I'm hungry! */ + netif_wake_queue(dev); +} + static int sa1100_irda_sir_tx_start(struct sk_buff *skb, struct net_device *dev, struct sa1100_irda *si) { @@ -222,14 +259,22 @@ static int sa1100_irda_sir_tx_start(struct sk_buff *skb, struct net_device *dev, si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data, si->tx_buff.truesize); + si->dma_tx.skb = skb; + sg_set_buf(&si->dma_tx.sg, si->tx_buff.data, si->tx_buff.len); + if (dma_map_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE) == 0) { + si->dma_tx.skb = NULL; + netif_wake_queue(dev); + dev->stats.tx_dropped++; + return NETDEV_TX_OK; + } + + sa1100_irda_dma_start(&si->dma_tx, DMA_MEM_TO_DEV, sa1100_irda_sirtxdma_irq, dev); + /* - * Set the transmit interrupt enable. This will fire off an - * interrupt immediately. Note that we disable the receiver - * so we won't get spurious characters received. + * The mean turn-around time is enforced by XBOF padding, + * so we don't have to do anything special here. */ - Ser2UTCR3 = UTCR3_TIE | UTCR3_TXE; - - dev_kfree_skb(skb); + Ser2UTCR3 = UTCR3_TXE; return NETDEV_TX_OK; } @@ -288,43 +333,6 @@ static irqreturn_t sa1100_irda_sir_irq(struct net_device *dev, struct sa1100_ird } - if (status & UTSR0_TFS && si->tx_buff.len) { - /* - * Transmitter FIFO is not full - */ - do { - Ser2UTDR = *si->tx_buff.data++; - si->tx_buff.len -= 1; - } while (Ser2UTSR1 & UTSR1_TNF && si->tx_buff.len); - - if (si->tx_buff.len == 0) { - dev->stats.tx_packets++; - dev->stats.tx_bytes += si->tx_buff.data - - si->tx_buff.head; - - /* - * We need to ensure that the transmitter has - * finished. - */ - do - rmb(); - while (Ser2UTSR1 & UTSR1_TBY); - - /* - * Ok, we've finished transmitting. Now enable - * the receiver. Sometimes we get a receive IRQ - * immediately after a transmit... - */ - Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID; - Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE; - - sa1100_irda_check_speed(si); - - /* I'm hungry! */ - netif_wake_queue(dev); - } - } - return IRQ_HANDLED; } @@ -545,8 +553,11 @@ static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed) brd = 3686400 / (16 * speed) - 1; /* Stop the receive DMA, and configure transmit. */ - if (IS_FIR(si)) + if (IS_FIR(si)) { dmaengine_terminate_all(si->dma_rx.chan); + dmaengine_slave_config(si->dma_tx.chan, + &sa1100_irda_sir_tx); + } local_irq_save(flags); @@ -574,6 +585,10 @@ static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed) break; case 4000000: + if (!IS_FIR(si)) + dmaengine_slave_config(si->dma_tx.chan, + &sa1100_irda_fir_tx); + local_irq_save(flags); Ser2HSSR0 = 0xff; -- cgit v1.2.3-59-g8ed1b