diff options
author | Anton Vorontsov <avorontsov@ru.mvista.com> | 2009-04-02 04:26:07 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-04-02 04:26:07 -0400 |
commit | da1aa63ec3b4e9b4c5680f06288f57f44caa61b8 (patch) | |
tree | 972f649dc0c35b5347c28bfba06463a3e3fb4d0f /drivers | |
parent | 050cc1f568e896a615110109999ed60ef75edf93 (diff) |
ucc_geth: Pass proper device to DMA routines, otherwise oops happens
The driver should pass a device that actually specifies internal DMA
ops, but currently it passes netdev's device, which is wrong and that
causes following oops:
Kernel BUG at c01c4df8 [verbose debug info unavailable]
Oops: Exception in kernel mode, sig: 5 [#1]
[...]
NIP [c01c4df8] get_new_skb+0x7c/0xf8
LR [c01c4da4] get_new_skb+0x28/0xf8
Call Trace:
[ef82be00] [c01c4da4] get_new_skb+0x28/0xf8 (unreliable)
[ef82be20] [c01c4eb8] rx_bd_buffer_set+0x44/0x98
[ef82be40] [c01c62bc] ucc_geth_startup+0x11b0/0x147c
[ef82be80] [c01c6674] ucc_geth_open+0xec/0x2a4
[ef82bea0] [c02288a4] dev_open+0xc0/0x11c
[...]
Fix this by passing of_device's device that specifies DMA ops in its
archdata.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/ucc_geth.c | 21 | ||||
-rw-r--r-- | drivers/net/ucc_geth.h | 3 |
2 files changed, 13 insertions, 11 deletions
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index a124615421bf..d3f39e86eb95 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c | |||
@@ -222,10 +222,10 @@ static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth, | |||
222 | (((unsigned)skb->data) & (UCC_GETH_RX_DATA_BUF_ALIGNMENT - | 222 | (((unsigned)skb->data) & (UCC_GETH_RX_DATA_BUF_ALIGNMENT - |
223 | 1))); | 223 | 1))); |
224 | 224 | ||
225 | skb->dev = ugeth->dev; | 225 | skb->dev = ugeth->ndev; |
226 | 226 | ||
227 | out_be32(&((struct qe_bd __iomem *)bd)->buf, | 227 | out_be32(&((struct qe_bd __iomem *)bd)->buf, |
228 | dma_map_single(&ugeth->dev->dev, | 228 | dma_map_single(ugeth->dev, |
229 | skb->data, | 229 | skb->data, |
230 | ugeth->ug_info->uf_info.max_rx_buf_length + | 230 | ugeth->ug_info->uf_info.max_rx_buf_length + |
231 | UCC_GETH_RX_DATA_BUF_ALIGNMENT, | 231 | UCC_GETH_RX_DATA_BUF_ALIGNMENT, |
@@ -1871,7 +1871,7 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth) | |||
1871 | continue; | 1871 | continue; |
1872 | for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) { | 1872 | for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) { |
1873 | if (ugeth->tx_skbuff[i][j]) { | 1873 | if (ugeth->tx_skbuff[i][j]) { |
1874 | dma_unmap_single(&ugeth->dev->dev, | 1874 | dma_unmap_single(ugeth->dev, |
1875 | in_be32(&((struct qe_bd __iomem *)bd)->buf), | 1875 | in_be32(&((struct qe_bd __iomem *)bd)->buf), |
1876 | (in_be32((u32 __iomem *)bd) & | 1876 | (in_be32((u32 __iomem *)bd) & |
1877 | BD_LENGTH_MASK), | 1877 | BD_LENGTH_MASK), |
@@ -1899,7 +1899,7 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth) | |||
1899 | bd = ugeth->p_rx_bd_ring[i]; | 1899 | bd = ugeth->p_rx_bd_ring[i]; |
1900 | for (j = 0; j < ugeth->ug_info->bdRingLenRx[i]; j++) { | 1900 | for (j = 0; j < ugeth->ug_info->bdRingLenRx[i]; j++) { |
1901 | if (ugeth->rx_skbuff[i][j]) { | 1901 | if (ugeth->rx_skbuff[i][j]) { |
1902 | dma_unmap_single(&ugeth->dev->dev, | 1902 | dma_unmap_single(ugeth->dev, |
1903 | in_be32(&((struct qe_bd __iomem *)bd)->buf), | 1903 | in_be32(&((struct qe_bd __iomem *)bd)->buf), |
1904 | ugeth->ug_info-> | 1904 | ugeth->ug_info-> |
1905 | uf_info.max_rx_buf_length + | 1905 | uf_info.max_rx_buf_length + |
@@ -3070,7 +3070,7 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
3070 | 3070 | ||
3071 | /* set up the buffer descriptor */ | 3071 | /* set up the buffer descriptor */ |
3072 | out_be32(&((struct qe_bd __iomem *)bd)->buf, | 3072 | out_be32(&((struct qe_bd __iomem *)bd)->buf, |
3073 | dma_map_single(&ugeth->dev->dev, skb->data, | 3073 | dma_map_single(ugeth->dev, skb->data, |
3074 | skb->len, DMA_TO_DEVICE)); | 3074 | skb->len, DMA_TO_DEVICE)); |
3075 | 3075 | ||
3076 | /* printk(KERN_DEBUG"skb->data is 0x%x\n",skb->data); */ | 3076 | /* printk(KERN_DEBUG"skb->data is 0x%x\n",skb->data); */ |
@@ -3126,7 +3126,7 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit | |||
3126 | 3126 | ||
3127 | ugeth_vdbg("%s: IN", __func__); | 3127 | ugeth_vdbg("%s: IN", __func__); |
3128 | 3128 | ||
3129 | dev = ugeth->dev; | 3129 | dev = ugeth->ndev; |
3130 | 3130 | ||
3131 | /* collect received buffers */ | 3131 | /* collect received buffers */ |
3132 | bd = ugeth->rxBd[rxQ]; | 3132 | bd = ugeth->rxBd[rxQ]; |
@@ -3160,7 +3160,7 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit | |||
3160 | skb_put(skb, length); | 3160 | skb_put(skb, length); |
3161 | 3161 | ||
3162 | /* Tell the skb what kind of packet this is */ | 3162 | /* Tell the skb what kind of packet this is */ |
3163 | skb->protocol = eth_type_trans(skb, ugeth->dev); | 3163 | skb->protocol = eth_type_trans(skb, ugeth->ndev); |
3164 | 3164 | ||
3165 | dev->stats.rx_bytes += length; | 3165 | dev->stats.rx_bytes += length; |
3166 | /* Send the packet up the stack */ | 3166 | /* Send the packet up the stack */ |
@@ -3431,7 +3431,7 @@ static int ucc_geth_close(struct net_device *dev) | |||
3431 | 3431 | ||
3432 | ucc_geth_stop(ugeth); | 3432 | ucc_geth_stop(ugeth); |
3433 | 3433 | ||
3434 | free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev); | 3434 | free_irq(ugeth->ug_info->uf_info.irq, ugeth->ndev); |
3435 | 3435 | ||
3436 | netif_stop_queue(dev); | 3436 | netif_stop_queue(dev); |
3437 | 3437 | ||
@@ -3445,7 +3445,7 @@ static void ucc_geth_timeout_work(struct work_struct *work) | |||
3445 | struct net_device *dev; | 3445 | struct net_device *dev; |
3446 | 3446 | ||
3447 | ugeth = container_of(work, struct ucc_geth_private, timeout_work); | 3447 | ugeth = container_of(work, struct ucc_geth_private, timeout_work); |
3448 | dev = ugeth->dev; | 3448 | dev = ugeth->ndev; |
3449 | 3449 | ||
3450 | ugeth_vdbg("%s: IN", __func__); | 3450 | ugeth_vdbg("%s: IN", __func__); |
3451 | 3451 | ||
@@ -3755,7 +3755,8 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
3755 | memcpy(dev->dev_addr, mac_addr, 6); | 3755 | memcpy(dev->dev_addr, mac_addr, 6); |
3756 | 3756 | ||
3757 | ugeth->ug_info = ug_info; | 3757 | ugeth->ug_info = ug_info; |
3758 | ugeth->dev = dev; | 3758 | ugeth->dev = device; |
3759 | ugeth->ndev = dev; | ||
3759 | ugeth->node = np; | 3760 | ugeth->node = np; |
3760 | 3761 | ||
3761 | return 0; | 3762 | return 0; |
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index 48fde5ad6a34..2f8ee7c87efe 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h | |||
@@ -1128,7 +1128,8 @@ struct ucc_geth_info { | |||
1128 | struct ucc_geth_private { | 1128 | struct ucc_geth_private { |
1129 | struct ucc_geth_info *ug_info; | 1129 | struct ucc_geth_info *ug_info; |
1130 | struct ucc_fast_private *uccf; | 1130 | struct ucc_fast_private *uccf; |
1131 | struct net_device *dev; | 1131 | struct device *dev; |
1132 | struct net_device *ndev; | ||
1132 | struct napi_struct napi; | 1133 | struct napi_struct napi; |
1133 | struct work_struct timeout_work; | 1134 | struct work_struct timeout_work; |
1134 | struct ucc_geth __iomem *ug_regs; | 1135 | struct ucc_geth __iomem *ug_regs; |