Blame view

drivers/net/ethernet/mipsnet.c 8.23 KB
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
1
2
3
4
5
  /*
   * This file is subject to the terms and conditions of the GNU General Public
   * License.  See the file "COPYING" in the main directory of this archive
   * for more details.
   */
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
6
  #include <linux/init.h>
539d3ee63   Alexey Dobriyan   net: fix MIPS fal...
7
  #include <linux/interrupt.h>
c2af68e5f   Ralf Baechle   MIPSsim: General ...
8
  #include <linux/io.h>
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
9
10
11
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/netdevice.h>
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
12
  #include <linux/etherdevice.h>
d052d1bef   Russell King   Create platform_d...
13
  #include <linux/platform_device.h>
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
14
  #include <asm/mips-boards/simint.h>
c800c5c9d   Ralf Baechle   Fix/Rewrite of th...
15
16
17
18
19
20
21
22
23
24
25
  #define MIPSNET_VERSION "2007-11-17"
  
  /*
   * Net status/control block as seen by sw in the core.
   */
  struct mipsnet_regs {
  	/*
  	 * Device info for probing, reads as MIPSNET%d where %d is some
  	 * form of version.
  	 */
  	u64 devId;		/*0x00 */
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
26

c800c5c9d   Ralf Baechle   Fix/Rewrite of th...
27
28
29
30
31
32
  	/*
  	 * read only busy flag.
  	 * Set and cleared by the Net Device to indicate that an rx or a tx
  	 * is in progress.
  	 */
  	u32 busy;		/*0x08 */
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
33

c800c5c9d   Ralf Baechle   Fix/Rewrite of th...
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
  	/*
  	 * Set by the Net Device.
  	 * The device will set it once data has been received.
  	 * The value is the number of bytes that should be read from
  	 * rxDataBuffer.  The value will decrease till 0 until all the data
  	 * from rxDataBuffer has been read.
  	 */
  	u32 rxDataCount;	/*0x0c */
  #define MIPSNET_MAX_RXTX_DATACOUNT (1 << 16)
  
  	/*
  	 * Settable from the MIPS core, cleared by the Net Device.
  	 * The core should set the number of bytes it wants to send,
  	 * then it should write those bytes of data to txDataBuffer.
  	 * The device will clear txDataCount has been processed (not
  	 * necessarily sent).
  	 */
  	u32 txDataCount;	/*0x10 */
  
  	/*
  	 * Interrupt control
  	 *
  	 * Used to clear the interrupted generated by this dev.
  	 * Write a 1 to clear the interrupt. (except bit31).
  	 *
  	 * Bit0 is set if it was a tx-done interrupt.
  	 * Bit1 is set when new rx-data is available.
  	 *    Until this bit is cleared there will be no other RXs.
  	 *
  	 * Bit31 is used for testing, it clears after a read.
  	 *    Writing 1 to this bit will cause an interrupt to be generated.
  	 *    To clear the test interrupt, write 0 to this register.
  	 */
  	u32 interruptControl;	/*0x14 */
  #define MIPSNET_INTCTL_TXDONE     (1u << 0)
  #define MIPSNET_INTCTL_RXDONE     (1u << 1)
  #define MIPSNET_INTCTL_TESTBIT    (1u << 31)
  
  	/*
  	 * Readonly core-specific interrupt info for the device to signal
  	 * the core. The meaning of the contents of this field might change.
  	 */
  	/* XXX: the whole memIntf interrupt scheme is messy: the device
  	 * should have no control what so ever of what VPE/register set is
  	 * being used.
  	 * The MemIntf should only expose interrupt lines, and something in
  	 * the config should be responsible for the line<->core/vpe bindings.
  	 */
  	u32 interruptInfo;	/*0x18 */
  
  	/*
  	 * This is where the received data is read out.
  	 * There is more data to read until rxDataReady is 0.
  	 * Only 1 byte at this regs offset is used.
  	 */
  	u32 rxDataBuffer;	/*0x1c */
  
  	/*
  	 * This is where the data to transmit is written.
  	 * Data should be written for the amount specified in the
  	 * txDataCount register.
  	 * Only 1 byte at this regs offset is used.
  	 */
  	u32 txDataBuffer;	/*0x20 */
  };
  
  #define regaddr(dev, field) \
    (dev->base_addr + offsetof(struct mipsnet_regs, field))
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
102

dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
103
104
105
106
107
108
109
110
  static char mipsnet_string[] = "mipsnet";
  
  /*
   * Copy data from the MIPSNET rx data port
   */
  static int ioiocpy_frommipsnet(struct net_device *dev, unsigned char *kdata,
  			int len)
  {
c2af68e5f   Ralf Baechle   MIPSsim: General ...
111
  	for (; len > 0; len--, kdata++)
c800c5c9d   Ralf Baechle   Fix/Rewrite of th...
112
  		*kdata = inb(regaddr(dev, rxDataBuffer));
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
113

c800c5c9d   Ralf Baechle   Fix/Rewrite of th...
114
  	return inl(regaddr(dev, rxDataCount));
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
115
  }
c800c5c9d   Ralf Baechle   Fix/Rewrite of th...
116
  static inline void mipsnet_put_todevice(struct net_device *dev,
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
117
118
119
120
  	struct sk_buff *skb)
  {
  	int count_to_go = skb->len;
  	char *buf_ptr = skb->data;
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
121

c800c5c9d   Ralf Baechle   Fix/Rewrite of th...
122
  	outl(skb->len, regaddr(dev, txDataCount));
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
123

c2af68e5f   Ralf Baechle   MIPSsim: General ...
124
  	for (; count_to_go; buf_ptr++, count_to_go--)
c800c5c9d   Ralf Baechle   Fix/Rewrite of th...
125
  		outb(*buf_ptr, regaddr(dev, txDataBuffer));
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
126

09f75cd7b   Jeff Garzik   [NET] drivers/net...
127
128
  	dev->stats.tx_packets++;
  	dev->stats.tx_bytes += skb->len;
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
129

c800c5c9d   Ralf Baechle   Fix/Rewrite of th...
130
  	dev_kfree_skb(skb);
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
131
132
133
134
  }
  
  static int mipsnet_xmit(struct sk_buff *skb, struct net_device *dev)
  {
f5e42fbab   Ralf Baechle   MIPSnet: Delete a...
135
136
  	/*
  	 * Only one packet at a time. Once TXDONE interrupt is serviced, the
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
137
138
139
140
  	 * queue will be restarted.
  	 */
  	netif_stop_queue(dev);
  	mipsnet_put_todevice(dev, skb);
6ed106549   Patrick McHardy   net: use NETDEV_T...
141
  	return NETDEV_TX_OK;
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
142
  }
c800c5c9d   Ralf Baechle   Fix/Rewrite of th...
143
  static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t len)
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
144
145
  {
  	struct sk_buff *skb;
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
146

c800c5c9d   Ralf Baechle   Fix/Rewrite of th...
147
148
149
150
  	if (!len)
  		return len;
  
  	skb = dev_alloc_skb(len + NET_IP_ALIGN);
c2af68e5f   Ralf Baechle   MIPSsim: General ...
151
  	if (!skb) {
09f75cd7b   Jeff Garzik   [NET] drivers/net...
152
  		dev->stats.rx_dropped++;
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
153
154
  		return -ENOMEM;
  	}
c800c5c9d   Ralf Baechle   Fix/Rewrite of th...
155
  	skb_reserve(skb, NET_IP_ALIGN);
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
156
157
  	if (ioiocpy_frommipsnet(dev, skb_put(skb, len), len))
  		return -EFAULT;
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
158
159
  	skb->protocol = eth_type_trans(skb, dev);
  	skb->ip_summed = CHECKSUM_UNNECESSARY;
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
160
  	netif_rx(skb);
09f75cd7b   Jeff Garzik   [NET] drivers/net...
161
162
  	dev->stats.rx_packets++;
  	dev->stats.rx_bytes += len;
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
163

c800c5c9d   Ralf Baechle   Fix/Rewrite of th...
164
  	return len;
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
165
  }
7d12e780e   David Howells   IRQ: Maintain reg...
166
  static irqreturn_t mipsnet_interrupt(int irq, void *dev_id)
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
167
168
  {
  	struct net_device *dev = dev_id;
c800c5c9d   Ralf Baechle   Fix/Rewrite of th...
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
  	u32 int_flags;
  	irqreturn_t ret = IRQ_NONE;
  
  	if (irq != dev->irq)
  		goto out_badirq;
  
  	/* TESTBIT is cleared on read. */
  	int_flags = inl(regaddr(dev, interruptControl));
  	if (int_flags & MIPSNET_INTCTL_TESTBIT) {
  		/* TESTBIT takes effect after a write with 0. */
  		outl(0, regaddr(dev, interruptControl));
  		ret = IRQ_HANDLED;
  	} else if (int_flags & MIPSNET_INTCTL_TXDONE) {
  		/* Only one packet at a time, we are done. */
  		dev->stats.tx_packets++;
  		netif_wake_queue(dev);
  		outl(MIPSNET_INTCTL_TXDONE,
  		     regaddr(dev, interruptControl));
  		ret = IRQ_HANDLED;
  	} else if (int_flags & MIPSNET_INTCTL_RXDONE) {
  		mipsnet_get_fromdev(dev, inl(regaddr(dev, rxDataCount)));
  		outl(MIPSNET_INTCTL_RXDONE, regaddr(dev, interruptControl));
  		ret = IRQ_HANDLED;
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
192
  	}
c800c5c9d   Ralf Baechle   Fix/Rewrite of th...
193
194
195
196
197
  	return ret;
  
  out_badirq:
  	printk(KERN_INFO "%s: %s(): irq %d for unknown device
  ",
b39d66a81   Harvey Harrison   drivers/net: repl...
198
  	       dev->name, __func__, irq);
c800c5c9d   Ralf Baechle   Fix/Rewrite of th...
199
  	return ret;
c2af68e5f   Ralf Baechle   MIPSsim: General ...
200
  }
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
201
202
203
204
  
  static int mipsnet_open(struct net_device *dev)
  {
  	int err;
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
205

a0607fd3a   Joe Perches   drivers/net: requ...
206
  	err = request_irq(dev->irq, mipsnet_interrupt,
1fb9df5d3   Thomas Gleixner   [PATCH] irq-flags...
207
  			  IRQF_SHARED, dev->name, (void *) dev);
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
208
  	if (err) {
c800c5c9d   Ralf Baechle   Fix/Rewrite of th...
209
  		release_region(dev->base_addr, sizeof(struct mipsnet_regs));
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
210
211
  		return err;
  	}
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
212
  	netif_start_queue(dev);
c2af68e5f   Ralf Baechle   MIPSsim: General ...
213
  	/* test interrupt handler */
c800c5c9d   Ralf Baechle   Fix/Rewrite of th...
214
  	outl(MIPSNET_INTCTL_TESTBIT, regaddr(dev, interruptControl));
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
215
216
217
218
219
220
  
  	return 0;
  }
  
  static int mipsnet_close(struct net_device *dev)
  {
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
221
  	netif_stop_queue(dev);
c800c5c9d   Ralf Baechle   Fix/Rewrite of th...
222
  	free_irq(dev->irq, dev);
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
223
224
  	return 0;
  }
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
225
226
  static void mipsnet_set_mclist(struct net_device *dev)
  {
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
227
  }
d6771e0b8   Alexander Beregalov   mipsnet: convert ...
228
229
230
231
  static const struct net_device_ops mipsnet_netdev_ops = {
  	.ndo_open		= mipsnet_open,
  	.ndo_stop		= mipsnet_close,
  	.ndo_start_xmit		= mipsnet_xmit,
afc4b13df   Jiri Pirko   net: remove use o...
232
  	.ndo_set_rx_mode	= mipsnet_set_mclist,
d6771e0b8   Alexander Beregalov   mipsnet: convert ...
233
234
235
236
  	.ndo_change_mtu		= eth_change_mtu,
  	.ndo_validate_addr	= eth_validate_addr,
  	.ndo_set_mac_address	= eth_mac_addr,
  };
ade2d3db2   Ralf Baechle   NET: MIPSsim: Fix...
237
  static int __devinit mipsnet_probe(struct platform_device *dev)
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
238
239
240
  {
  	struct net_device *netdev;
  	int err;
09f75cd7b   Jeff Garzik   [NET] drivers/net...
241
  	netdev = alloc_etherdev(0);
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
242
243
244
245
  	if (!netdev) {
  		err = -ENOMEM;
  		goto out;
  	}
7a192ec33   Ming Lei   platform driver: ...
246
  	platform_set_drvdata(dev, netdev);
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
247

d6771e0b8   Alexander Beregalov   mipsnet: convert ...
248
  	netdev->netdev_ops = &mipsnet_netdev_ops;
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
249
250
251
252
253
  
  	/*
  	 * TODO: probe for these or load them from PARAM
  	 */
  	netdev->base_addr = 0x4200;
3b1d4ed53   Ralf Baechle   [MIPS] Don't drag...
254
  	netdev->irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_MB0 +
c800c5c9d   Ralf Baechle   Fix/Rewrite of th...
255
  		      inl(regaddr(netdev, interruptInfo));
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
256

c2af68e5f   Ralf Baechle   MIPSsim: General ...
257
  	/* Get the io region now, get irq on open() */
c800c5c9d   Ralf Baechle   Fix/Rewrite of th...
258
259
  	if (!request_region(netdev->base_addr, sizeof(struct mipsnet_regs),
  			    "mipsnet")) {
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
  		err = -EBUSY;
  		goto out_free_netdev;
  	}
  
  	/*
  	 * Lacking any better mechanism to allocate a MAC address we use a
  	 * random one ...
  	 */
  	random_ether_addr(netdev->dev_addr);
  
  	err = register_netdev(netdev);
  	if (err) {
  		printk(KERN_ERR "MIPSNet: failed to register netdev.
  ");
  		goto out_free_region;
  	}
  
  	return 0;
  
  out_free_region:
c800c5c9d   Ralf Baechle   Fix/Rewrite of th...
280
  	release_region(netdev->base_addr, sizeof(struct mipsnet_regs));
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
281
282
283
284
285
286
287
  
  out_free_netdev:
  	free_netdev(netdev);
  
  out:
  	return err;
  }
7a192ec33   Ming Lei   platform driver: ...
288
  static int __devexit mipsnet_device_remove(struct platform_device *device)
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
289
  {
7a192ec33   Ming Lei   platform driver: ...
290
  	struct net_device *dev = platform_get_drvdata(device);
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
291
292
  
  	unregister_netdev(dev);
c800c5c9d   Ralf Baechle   Fix/Rewrite of th...
293
  	release_region(dev->base_addr, sizeof(struct mipsnet_regs));
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
294
  	free_netdev(dev);
7a192ec33   Ming Lei   platform driver: ...
295
  	platform_set_drvdata(device, NULL);
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
296
297
298
  
  	return 0;
  }
7a192ec33   Ming Lei   platform driver: ...
299
300
301
302
303
304
305
  static struct platform_driver mipsnet_driver = {
  	.driver = {
  		.name		= mipsnet_string,
  		.owner		= THIS_MODULE,
  	},
  	.probe		= mipsnet_probe,
  	.remove		= __devexit_p(mipsnet_device_remove),
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
306
  };
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
307
308
  static int __init mipsnet_init_module(void)
  {
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
309
310
311
312
313
  	int err;
  
  	printk(KERN_INFO "MIPSNet Ethernet driver. Version: %s. "
  	       "(c)2005 MIPS Technologies, Inc.
  ", MIPSNET_VERSION);
7a192ec33   Ming Lei   platform driver: ...
314
  	err = platform_driver_register(&mipsnet_driver);
1e2b980fd   Ralf Baechle   MIPSnet: Moderniz...
315
  	if (err)
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
316
317
  		printk(KERN_ERR "Driver registration failed
  ");
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
318

dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
319
320
321
322
323
  	return err;
  }
  
  static void __exit mipsnet_exit_module(void)
  {
7a192ec33   Ming Lei   platform driver: ...
324
  	platform_driver_unregister(&mipsnet_driver);
dcbf84775   Ralf Baechle   [PATCH] mipsnet: ...
325
326
327
328
  }
  
  module_init(mipsnet_init_module);
  module_exit(mipsnet_exit_module);