aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2008-01-11 12:28:00 -0500
committerDavid S. Miller <davem@davemloft.net>2008-02-03 07:28:10 -0500
commitc800c5c9db9c621b2c1d70c3ae6532fafe2db69d (patch)
tree429dadd456a693c42193c089b6d42d1dbdf1725a
parentba64f58ea47de34d864a438d49deccbbaea3f935 (diff)
Fix/Rewrite of the mipsnet driver]
This is Thiemo's patch. ----- Forwarded message from Thiemo Seufer <ths@networkno.de> ----- From: Thiemo Seufer <ths@networkno.de> Date: Sat, 17 Nov 2007 22:29:13 +0000 To: netdev@vger.kernel.org Cc: linux-mips@linux-mips.org, ralf@linux-mips.org Subject: [PATCH, REPOST] Fix/Rewrite of the mipsnet driver Content-Type: text/plain; charset=us-ascii Hello All, currently the mipsnet driver fails after transmitting a number of packages because SKBs are allocated but never freed. I fixed that and coudn't refrain from removing the most egregious warts. - mipsnet.h folded into mipsnet.c, as it doesn't provide any useful external interface. - Free SKB after transmission. - Call free_irq in mipsnet_close, to balance the request_irq in mipsnet_open. - Removed duplicate read of rxDataCount. - Some identifiers are now less verbose. - Removed dead and/or unnecessarily complex code. - Code formatting fixes. Tested on Qemu's mipssim emulation, with this patch it can boot a Debian NFSroot. Thiemo Signed-off-by: Thiemo Seufer <ths@networkno.de> Signed-off-by: Jeff Garzik <jeff@garzik.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/mipsnet.c203
-rw-r--r--drivers/net/mipsnet.h112
2 files changed, 135 insertions, 180 deletions
diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c
index aafc3ce59cbb..6d343efb2717 100644
--- a/drivers/net/mipsnet.c
+++ b/drivers/net/mipsnet.c
@@ -4,8 +4,6 @@
4 * for more details. 4 * for more details.
5 */ 5 */
6 6
7#define DEBUG
8
9#include <linux/init.h> 7#include <linux/init.h>
10#include <linux/io.h> 8#include <linux/io.h>
11#include <linux/kernel.h> 9#include <linux/kernel.h>
@@ -15,11 +13,93 @@
15#include <linux/platform_device.h> 13#include <linux/platform_device.h>
16#include <asm/mips-boards/simint.h> 14#include <asm/mips-boards/simint.h>
17 15
18#include "mipsnet.h" /* actual device IO mapping */ 16#define MIPSNET_VERSION "2007-11-17"
17
18/*
19 * Net status/control block as seen by sw in the core.
20 */
21struct mipsnet_regs {
22 /*
23 * Device info for probing, reads as MIPSNET%d where %d is some
24 * form of version.
25 */
26 u64 devId; /*0x00 */
19 27
20#define MIPSNET_VERSION "2005-06-20" 28 /*
29 * read only busy flag.
30 * Set and cleared by the Net Device to indicate that an rx or a tx
31 * is in progress.
32 */
33 u32 busy; /*0x08 */
21 34
22#define mipsnet_reg_address(dev, field) (dev->base_addr + field_offset(field)) 35 /*
36 * Set by the Net Device.
37 * The device will set it once data has been received.
38 * The value is the number of bytes that should be read from
39 * rxDataBuffer. The value will decrease till 0 until all the data
40 * from rxDataBuffer has been read.
41 */
42 u32 rxDataCount; /*0x0c */
43#define MIPSNET_MAX_RXTX_DATACOUNT (1 << 16)
44
45 /*
46 * Settable from the MIPS core, cleared by the Net Device.
47 * The core should set the number of bytes it wants to send,
48 * then it should write those bytes of data to txDataBuffer.
49 * The device will clear txDataCount has been processed (not
50 * necessarily sent).
51 */
52 u32 txDataCount; /*0x10 */
53
54 /*
55 * Interrupt control
56 *
57 * Used to clear the interrupted generated by this dev.
58 * Write a 1 to clear the interrupt. (except bit31).
59 *
60 * Bit0 is set if it was a tx-done interrupt.
61 * Bit1 is set when new rx-data is available.
62 * Until this bit is cleared there will be no other RXs.
63 *
64 * Bit31 is used for testing, it clears after a read.
65 * Writing 1 to this bit will cause an interrupt to be generated.
66 * To clear the test interrupt, write 0 to this register.
67 */
68 u32 interruptControl; /*0x14 */
69#define MIPSNET_INTCTL_TXDONE (1u << 0)
70#define MIPSNET_INTCTL_RXDONE (1u << 1)
71#define MIPSNET_INTCTL_TESTBIT (1u << 31)
72
73 /*
74 * Readonly core-specific interrupt info for the device to signal
75 * the core. The meaning of the contents of this field might change.
76 */
77 /* XXX: the whole memIntf interrupt scheme is messy: the device
78 * should have no control what so ever of what VPE/register set is
79 * being used.
80 * The MemIntf should only expose interrupt lines, and something in
81 * the config should be responsible for the line<->core/vpe bindings.
82 */
83 u32 interruptInfo; /*0x18 */
84
85 /*
86 * This is where the received data is read out.
87 * There is more data to read until rxDataReady is 0.
88 * Only 1 byte at this regs offset is used.
89 */
90 u32 rxDataBuffer; /*0x1c */
91
92 /*
93 * This is where the data to transmit is written.
94 * Data should be written for the amount specified in the
95 * txDataCount register.
96 * Only 1 byte at this regs offset is used.
97 */
98 u32 txDataBuffer; /*0x20 */
99};
100
101#define regaddr(dev, field) \
102 (dev->base_addr + offsetof(struct mipsnet_regs, field))
23 103
24static char mipsnet_string[] = "mipsnet"; 104static char mipsnet_string[] = "mipsnet";
25 105
@@ -29,32 +109,27 @@ static char mipsnet_string[] = "mipsnet";
29static int ioiocpy_frommipsnet(struct net_device *dev, unsigned char *kdata, 109static int ioiocpy_frommipsnet(struct net_device *dev, unsigned char *kdata,
30 int len) 110 int len)
31{ 111{
32 uint32_t available_len = inl(mipsnet_reg_address(dev, rxDataCount));
33
34 if (available_len < len)
35 return -EFAULT;
36
37 for (; len > 0; len--, kdata++) 112 for (; len > 0; len--, kdata++)
38 *kdata = inb(mipsnet_reg_address(dev, rxDataBuffer)); 113 *kdata = inb(regaddr(dev, rxDataBuffer));
39 114
40 return inl(mipsnet_reg_address(dev, rxDataCount)); 115 return inl(regaddr(dev, rxDataCount));
41} 116}
42 117
43static inline ssize_t mipsnet_put_todevice(struct net_device *dev, 118static inline void mipsnet_put_todevice(struct net_device *dev,
44 struct sk_buff *skb) 119 struct sk_buff *skb)
45{ 120{
46 int count_to_go = skb->len; 121 int count_to_go = skb->len;
47 char *buf_ptr = skb->data; 122 char *buf_ptr = skb->data;
48 123
49 outl(skb->len, mipsnet_reg_address(dev, txDataCount)); 124 outl(skb->len, regaddr(dev, txDataCount));
50 125
51 for (; count_to_go; buf_ptr++, count_to_go--) 126 for (; count_to_go; buf_ptr++, count_to_go--)
52 outb(*buf_ptr, mipsnet_reg_address(dev, txDataBuffer)); 127 outb(*buf_ptr, regaddr(dev, txDataBuffer));
53 128
54 dev->stats.tx_packets++; 129 dev->stats.tx_packets++;
55 dev->stats.tx_bytes += skb->len; 130 dev->stats.tx_bytes += skb->len;
56 131
57 return skb->len; 132 dev_kfree_skb(skb);
58} 133}
59 134
60static int mipsnet_xmit(struct sk_buff *skb, struct net_device *dev) 135static int mipsnet_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -69,18 +144,20 @@ static int mipsnet_xmit(struct sk_buff *skb, struct net_device *dev)
69 return 0; 144 return 0;
70} 145}
71 146
72static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count) 147static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t len)
73{ 148{
74 struct sk_buff *skb; 149 struct sk_buff *skb;
75 size_t len = count;
76 150
77 skb = alloc_skb(len + 2, GFP_KERNEL); 151 if (!len)
152 return len;
153
154 skb = dev_alloc_skb(len + NET_IP_ALIGN);
78 if (!skb) { 155 if (!skb) {
79 dev->stats.rx_dropped++; 156 dev->stats.rx_dropped++;
80 return -ENOMEM; 157 return -ENOMEM;
81 } 158 }
82 159
83 skb_reserve(skb, 2); 160 skb_reserve(skb, NET_IP_ALIGN);
84 if (ioiocpy_frommipsnet(dev, skb_put(skb, len), len)) 161 if (ioiocpy_frommipsnet(dev, skb_put(skb, len), len))
85 return -EFAULT; 162 return -EFAULT;
86 163
@@ -92,50 +169,42 @@ static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count)
92 dev->stats.rx_packets++; 169 dev->stats.rx_packets++;
93 dev->stats.rx_bytes += len; 170 dev->stats.rx_bytes += len;
94 171
95 return count; 172 return len;
96} 173}
97 174
98static irqreturn_t mipsnet_interrupt(int irq, void *dev_id) 175static irqreturn_t mipsnet_interrupt(int irq, void *dev_id)
99{ 176{
100 struct net_device *dev = dev_id; 177 struct net_device *dev = dev_id;
101 178 u32 int_flags;
102 irqreturn_t retval = IRQ_NONE; 179 irqreturn_t ret = IRQ_NONE;
103 uint64_t interruptFlags; 180
104 181 if (irq != dev->irq)
105 if (irq == dev->irq) { 182 goto out_badirq;
106 retval = IRQ_HANDLED; 183
107 184 /* TESTBIT is cleared on read. */
108 interruptFlags = 185 int_flags = inl(regaddr(dev, interruptControl));
109 inl(mipsnet_reg_address(dev, interruptControl)); 186 if (int_flags & MIPSNET_INTCTL_TESTBIT) {
110 187 /* TESTBIT takes effect after a write with 0. */
111 if (interruptFlags & MIPSNET_INTCTL_TXDONE) { 188 outl(0, regaddr(dev, interruptControl));
112 outl(MIPSNET_INTCTL_TXDONE, 189 ret = IRQ_HANDLED;
113 mipsnet_reg_address(dev, interruptControl)); 190 } else if (int_flags & MIPSNET_INTCTL_TXDONE) {
114 /* only one packet at a time, we are done. */ 191 /* Only one packet at a time, we are done. */
115 netif_wake_queue(dev); 192 dev->stats.tx_packets++;
116 } else if (interruptFlags & MIPSNET_INTCTL_RXDONE) { 193 netif_wake_queue(dev);
117 mipsnet_get_fromdev(dev, 194 outl(MIPSNET_INTCTL_TXDONE,
118 inl(mipsnet_reg_address(dev, rxDataCount))); 195 regaddr(dev, interruptControl));
119 outl(MIPSNET_INTCTL_RXDONE, 196 ret = IRQ_HANDLED;
120 mipsnet_reg_address(dev, interruptControl)); 197 } else if (int_flags & MIPSNET_INTCTL_RXDONE) {
121 198 mipsnet_get_fromdev(dev, inl(regaddr(dev, rxDataCount)));
122 } else if (interruptFlags & MIPSNET_INTCTL_TESTBIT) { 199 outl(MIPSNET_INTCTL_RXDONE, regaddr(dev, interruptControl));
123 /* 200 ret = IRQ_HANDLED;
124 * TESTBIT is cleared on read.
125 * And takes effect after a write with 0
126 */
127 outl(0, mipsnet_reg_address(dev, interruptControl));
128 } else {
129 /* Maybe shared IRQ, just ignore, no clearing. */
130 retval = IRQ_NONE;
131 }
132
133 } else {
134 printk(KERN_INFO "%s: %s(): irq %d for unknown device\n",
135 dev->name, __FUNCTION__, irq);
136 retval = IRQ_NONE;
137 } 201 }
138 return retval; 202 return ret;
203
204out_badirq:
205 printk(KERN_INFO "%s: %s(): irq %d for unknown device\n",
206 dev->name, __FUNCTION__, irq);
207 return ret;
139} 208}
140 209
141static int mipsnet_open(struct net_device *dev) 210static int mipsnet_open(struct net_device *dev)
@@ -144,18 +213,15 @@ static int mipsnet_open(struct net_device *dev)
144 213
145 err = request_irq(dev->irq, &mipsnet_interrupt, 214 err = request_irq(dev->irq, &mipsnet_interrupt,
146 IRQF_SHARED, dev->name, (void *) dev); 215 IRQF_SHARED, dev->name, (void *) dev);
147
148 if (err) { 216 if (err) {
149 release_region(dev->base_addr, MIPSNET_IO_EXTENT); 217 release_region(dev->base_addr, sizeof(struct mipsnet_regs));
150 return err; 218 return err;
151 } 219 }
152 220
153 netif_start_queue(dev); 221 netif_start_queue(dev);
154 222
155 /* test interrupt handler */ 223 /* test interrupt handler */
156 outl(MIPSNET_INTCTL_TESTBIT, 224 outl(MIPSNET_INTCTL_TESTBIT, regaddr(dev, interruptControl));
157 mipsnet_reg_address(dev, interruptControl));
158
159 225
160 return 0; 226 return 0;
161} 227}
@@ -163,7 +229,7 @@ static int mipsnet_open(struct net_device *dev)
163static int mipsnet_close(struct net_device *dev) 229static int mipsnet_close(struct net_device *dev)
164{ 230{
165 netif_stop_queue(dev); 231 netif_stop_queue(dev);
166 232 free_irq(dev->irq, dev);
167 return 0; 233 return 0;
168} 234}
169 235
@@ -194,10 +260,11 @@ static int __init mipsnet_probe(struct device *dev)
194 */ 260 */
195 netdev->base_addr = 0x4200; 261 netdev->base_addr = 0x4200;
196 netdev->irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_MB0 + 262 netdev->irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_MB0 +
197 inl(mipsnet_reg_address(netdev, interruptInfo)); 263 inl(regaddr(netdev, interruptInfo));
198 264
199 /* Get the io region now, get irq on open() */ 265 /* Get the io region now, get irq on open() */
200 if (!request_region(netdev->base_addr, MIPSNET_IO_EXTENT, "mipsnet")) { 266 if (!request_region(netdev->base_addr, sizeof(struct mipsnet_regs),
267 "mipsnet")) {
201 err = -EBUSY; 268 err = -EBUSY;
202 goto out_free_netdev; 269 goto out_free_netdev;
203 } 270 }
@@ -217,7 +284,7 @@ static int __init mipsnet_probe(struct device *dev)
217 return 0; 284 return 0;
218 285
219out_free_region: 286out_free_region:
220 release_region(netdev->base_addr, MIPSNET_IO_EXTENT); 287 release_region(netdev->base_addr, sizeof(struct mipsnet_regs));
221 288
222out_free_netdev: 289out_free_netdev:
223 free_netdev(netdev); 290 free_netdev(netdev);
@@ -231,7 +298,7 @@ static int __devexit mipsnet_device_remove(struct device *device)
231 struct net_device *dev = dev_get_drvdata(device); 298 struct net_device *dev = dev_get_drvdata(device);
232 299
233 unregister_netdev(dev); 300 unregister_netdev(dev);
234 release_region(dev->base_addr, MIPSNET_IO_EXTENT); 301 release_region(dev->base_addr, sizeof(struct mipsnet_regs));
235 free_netdev(dev); 302 free_netdev(dev);
236 dev_set_drvdata(device, NULL); 303 dev_set_drvdata(device, NULL);
237 304
diff --git a/drivers/net/mipsnet.h b/drivers/net/mipsnet.h
deleted file mode 100644
index 0132c6714a40..000000000000
--- a/drivers/net/mipsnet.h
+++ /dev/null
@@ -1,112 +0,0 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 */
6#ifndef __MIPSNET_H
7#define __MIPSNET_H
8
9/*
10 * Id of this Net device, as seen by the core.
11 */
12#define MIPS_NET_DEV_ID ((uint64_t) \
13 ((uint64_t) 'M' << 0)| \
14 ((uint64_t) 'I' << 8)| \
15 ((uint64_t) 'P' << 16)| \
16 ((uint64_t) 'S' << 24)| \
17 ((uint64_t) 'N' << 32)| \
18 ((uint64_t) 'E' << 40)| \
19 ((uint64_t) 'T' << 48)| \
20 ((uint64_t) '0' << 56))
21
22/*
23 * Net status/control block as seen by sw in the core.
24 * (Why not use bit fields? can't be bothered with cross-platform struct
25 * packing.)
26 */
27struct net_control_block {
28 /*
29 * dev info for probing
30 * reads as MIPSNET%d where %d is some form of version
31 */
32 uint64_t devId; /* 0x00 */
33
34 /*
35 * read only busy flag.
36 * Set and cleared by the Net Device to indicate that an rx or a tx
37 * is in progress.
38 */
39 uint32_t busy; /* 0x08 */
40
41 /*
42 * Set by the Net Device.
43 * The device will set it once data has been received.
44 * The value is the number of bytes that should be read from
45 * rxDataBuffer. The value will decrease till 0 until all the data
46 * from rxDataBuffer has been read.
47 */
48 uint32_t rxDataCount; /* 0x0c */
49#define MIPSNET_MAX_RXTX_DATACOUNT (1<<16)
50
51 /*
52 * Settable from the MIPS core, cleared by the Net Device. The core
53 * should set the number of bytes it wants to send, then it should
54 * write those bytes of data to txDataBuffer. The device will clear
55 * txDataCount has been processed (not necessarily sent).
56 */
57 uint32_t txDataCount; /* 0x10 */
58
59 /*
60 * Interrupt control
61 *
62 * Used to clear the interrupted generated by this dev.
63 * Write a 1 to clear the interrupt. (except bit31).
64 *
65 * Bit0 is set if it was a tx-done interrupt.
66 * Bit1 is set when new rx-data is available.
67 * Until this bit is cleared there will be no other RXs.
68 *
69 * Bit31 is used for testing, it clears after a read.
70 * Writing 1 to this bit will cause an interrupt to be generated.
71 * To clear the test interrupt, write 0 to this register.
72 */
73 uint32_t interruptControl; /*0x14 */
74#define MIPSNET_INTCTL_TXDONE ((uint32_t)(1 << 0))
75#define MIPSNET_INTCTL_RXDONE ((uint32_t)(1 << 1))
76#define MIPSNET_INTCTL_TESTBIT ((uint32_t)(1 << 31))
77#define MIPSNET_INTCTL_ALLSOURCES (MIPSNET_INTCTL_TXDONE | \
78 MIPSNET_INTCTL_RXDONE | \
79 MIPSNET_INTCTL_TESTBIT)
80
81 /*
82 * Readonly core-specific interrupt info for the device to signal the
83 * core. The meaning of the contents of this field might change.
84 *
85 * TODO: the whole memIntf interrupt scheme is messy: the device should
86 * have no control what so ever of what VPE/register set is being
87 * used. The MemIntf should only expose interrupt lines, and
88 * something in the config should be responsible for the
89 * line<->core/vpe bindings.
90 */
91 uint32_t interruptInfo; /* 0x18 */
92
93 /*
94 * This is where the received data is read out.
95 * There is more data to read until rxDataReady is 0.
96 * Only 1 byte at this regs offset is used.
97 */
98 uint32_t rxDataBuffer; /* 0x1c */
99
100 /*
101 * This is where the data to transmit is written. Data should be
102 * written for the amount specified in the txDataCount register. Only
103 * 1 byte at this regs offset is used.
104 */
105 uint32_t txDataBuffer; /* 0x20 */
106};
107
108#define MIPSNET_IO_EXTENT 0x40 /* being generous */
109
110#define field_offset(field) (offsetof(struct net_control_block, field))
111
112#endif /* __MIPSNET_H */