Blame view

drivers/net/arcnet/arcnet.c 32.2 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
  /*
   * Linux ARCnet driver - device-independent routines
cb334648a   Joe Perches   arcnet: Use norma...
3
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
   * Written 1997 by David Woodhouse.
   * Written 1994-1999 by Avery Pennarun.
   * Written 1999-2000 by Martin Mares <mj@ucw.cz>.
   * Derived from skeleton.c by Donald Becker.
   *
   * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
   *  for sponsoring the further development of this driver.
   *
   * **********************
   *
   * The original copyright was as follows:
   *
   * skeleton.c Written 1993 by Donald Becker.
   * Copyright 1993 United States Government as represented by the
   * Director, National Security Agency.  This software may only be used
   * and distributed according to the terms of the GNU General Public License as
   * modified by SRC, incorporated herein by reference.
   *
   * **********************
cb334648a   Joe Perches   arcnet: Use norma...
23
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
   * The change log is now in a file called ChangeLog in this directory.
   *
   * Sources:
   *  - Crynwr arcnet.com/arcether.com packet drivers.
cb334648a   Joe Perches   arcnet: Use norma...
28
   *  - arcnet.c v0.00 dated 1/1/94 and apparently by
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
31
32
33
34
35
36
37
38
39
40
41
42
   *     Donald Becker - it didn't work :)
   *  - skeleton.c v0.05 dated 11/16/93 by Donald Becker
   *     (from Linux Kernel 1.1.45)
   *  - RFC's 1201 and 1051 - re: TCP/IP over ARCnet
   *  - The official ARCnet COM9026 data sheets (!) thanks to
   *     Ken Cornetet <kcornete@nyx10.cs.du.edu>
   *  - The official ARCnet COM20020 data sheets.
   *  - Information on some more obscure ARCnet controller chips, thanks
   *     to the nice people at SMSC.
   *  - net/inet/eth.c (from kernel 1.1.50) for header-building info.
   *  - Alternate Linux ARCnet source by V.Shergin <vsher@sao.stavropol.su>
   *  - Textual information and more alternate source from Joachim Koenig
   *     <jojo@repas.de>
   */
05a24b234   Joe Perches   arcnet: Convert p...
43
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
  
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
49
50
51
  #include <linux/types.h>
  #include <linux/delay.h>
  #include <linux/netdevice.h>
  #include <linux/if_arp.h>
  #include <net/arp.h>
  #include <linux/init.h>
ff5688ae1   Marcelo Feitoza Parisi   [PATCH] drivers/n...
52
  #include <linux/jiffies.h>
05fcd31cc   Michael Grzeschik   arcnet: add err_s...
53
  #include <linux/errqueue.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54

8890624a4   Michael Grzeschik   arcnet: com20020-...
55
  #include <linux/leds.h>
26c6d2816   Joe Perches   arcnet: Move file...
56
  #include "arcdevice.h"
8e0f295ea   Joe Perches   arcnet: Add com90...
57
  #include "com9026.h"
26c6d2816   Joe Perches   arcnet: Move file...
58

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
60
61
62
63
64
65
  /* "do nothing" functions for protocol drivers */
  static void null_rx(struct net_device *dev, int bufnum,
  		    struct archdr *pkthdr, int length);
  static int null_build_header(struct sk_buff *skb, struct net_device *dev,
  			     unsigned short type, uint8_t daddr);
  static int null_prepare_tx(struct net_device *dev, struct archdr *pkt,
  			   int length, int bufnum);
f03aa2d89   Adrian Bunk   [PATCH] drivers/n...
66
  static void arcnet_rx(struct net_device *dev, int bufnum);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67

f2f0a16bf   Joe Perches   arcnet: Use netwo...
68
  /* one ArcProto per possible proto ID.  None of the elements of
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
71
72
   * arc_proto_map are allowed to be NULL; they will get set to
   * arc_proto_default instead.  It also must not be NULL; if you would like
   * to set it to NULL, set it to &arc_proto_null instead.
   */
811eafc02   Joe Perches   arcnet: Move EXPO...
73
74
75
76
77
78
79
80
81
82
83
  struct ArcProto *arc_proto_map[256];
  EXPORT_SYMBOL(arc_proto_map);
  
  struct ArcProto *arc_proto_default;
  EXPORT_SYMBOL(arc_proto_default);
  
  struct ArcProto *arc_bcast_proto;
  EXPORT_SYMBOL(arc_bcast_proto);
  
  struct ArcProto *arc_raw_proto;
  EXPORT_SYMBOL(arc_raw_proto);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84

7f5e760c1   Joe Perches   arcnet: Use norma...
85
  static struct ArcProto arc_proto_null = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
89
90
91
92
93
94
95
96
97
  	.suffix		= '?',
  	.mtu		= XMTU,
  	.is_ip          = 0,
  	.rx		= null_rx,
  	.build_header	= null_build_header,
  	.prepare_tx	= null_prepare_tx,
  	.continue_tx    = NULL,
  	.ack_tx         = NULL
  };
  
  /* Exported function prototypes */
  int arcnet_debug = ARCNET_DEBUG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
  EXPORT_SYMBOL(arcnet_debug);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
100
  
  /* Internal function prototypes */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
  static int arcnet_header(struct sk_buff *skb, struct net_device *dev,
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
102
103
  			 unsigned short type, const void *daddr,
  			 const void *saddr, unsigned len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
105
106
107
108
109
110
111
112
113
114
  static int go_tx(struct net_device *dev);
  
  static int debug = ARCNET_DEBUG;
  module_param(debug, int, 0);
  MODULE_LICENSE("GPL");
  
  static int __init arcnet_init(void)
  {
  	int count;
  
  	arcnet_debug = debug;
05a24b234   Joe Perches   arcnet: Convert p...
115
116
  	pr_info("arcnet loaded
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
118
119
120
121
  
  	/* initialize the protocol map */
  	arc_raw_proto = arc_proto_default = arc_bcast_proto = &arc_proto_null;
  	for (count = 0; count < 256; count++)
  		arc_proto_map[count] = arc_proto_default;
72aeea484   Joe Perches   arcnet: Expand od...
122
  	if (BUGLVL(D_DURING))
5b5e0928f   Alexey Dobriyan   lib/vsprintf.c: r...
123
124
  		pr_info("struct sizes: %zd %zd %zd %zd %zd
  ",
05a24b234   Joe Perches   arcnet: Convert p...
125
126
127
128
129
  			sizeof(struct arc_hardware),
  			sizeof(struct arc_rfc1201),
  			sizeof(struct arc_rfc1051),
  			sizeof(struct arc_eth_encap),
  			sizeof(struct archdr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
131
132
133
134
135
136
137
138
139
  
  	return 0;
  }
  
  static void __exit arcnet_exit(void)
  {
  }
  
  module_init(arcnet_init);
  module_exit(arcnet_exit);
f2f0a16bf   Joe Perches   arcnet: Use netwo...
140
  /* Dump the contents of an sk_buff */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
143
144
  #if ARCNET_DEBUG_MAX & D_SKB
  void arcnet_dump_skb(struct net_device *dev,
  		     struct sk_buff *skb, char *desc)
  {
ad361c988   Joe Perches   Remove multiple K...
145
  	char hdr[32];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146

ad361c988   Joe Perches   Remove multiple K...
147
148
149
150
  	/* dump the packet */
  	snprintf(hdr, sizeof(hdr), "%6s:%s skb->data:", dev->name, desc);
  	print_hex_dump(KERN_DEBUG, hdr, DUMP_PREFIX_OFFSET,
  		       16, 1, skb->data, skb->len, true);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
153
  EXPORT_SYMBOL(arcnet_dump_skb);
  #endif
f2f0a16bf   Joe Perches   arcnet: Use netwo...
154
  /* Dump the contents of an ARCnet buffer */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
  #if (ARCNET_DEBUG_MAX & (D_RX | D_TX))
f03aa2d89   Adrian Bunk   [PATCH] drivers/n...
156
157
  static void arcnet_dump_packet(struct net_device *dev, int bufnum,
  			       char *desc, int take_arcnet_lock)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
  {
454d7c9b1   Wang Chen   netdevice: safe c...
159
  	struct arcnet_local *lp = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
161
162
  	int i, length;
  	unsigned long flags = 0;
  	static uint8_t buf[512];
ad361c988   Joe Perches   Remove multiple K...
163
  	char hdr[32];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
165
  
  	/* hw.copy_from_card expects IRQ context so take the IRQ lock
f2f0a16bf   Joe Perches   arcnet: Use netwo...
166
167
  	 * to keep it single threaded
  	 */
cb334648a   Joe Perches   arcnet: Use norma...
168
  	if (take_arcnet_lock)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
171
  		spin_lock_irqsave(&lp->lock, flags);
  
  	lp->hw.copy_from_card(dev, bufnum, 0, buf, 512);
cb334648a   Joe Perches   arcnet: Use norma...
172
  	if (take_arcnet_lock)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
174
175
176
  		spin_unlock_irqrestore(&lp->lock, flags);
  
  	/* if the offset[0] byte is nonzero, this is a 256-byte packet */
  	length = (buf[2] ? 256 : 512);
ad361c988   Joe Perches   Remove multiple K...
177
178
179
180
  	/* dump the packet */
  	snprintf(hdr, sizeof(hdr), "%6s:%s packet dump:", dev->name, desc);
  	print_hex_dump(KERN_DEBUG, hdr, DUMP_PREFIX_OFFSET,
  		       16, 1, buf, length, true);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
  }
f03aa2d89   Adrian Bunk   [PATCH] drivers/n...
182
  #else
cb334648a   Joe Perches   arcnet: Use norma...
183
  #define arcnet_dump_packet(dev, bufnum, desc, take_arcnet_lock) do { } while (0)
f03aa2d89   Adrian Bunk   [PATCH] drivers/n...
184

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
  #endif
8890624a4   Michael Grzeschik   arcnet: com20020-...
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
  /* Trigger a LED event in response to a ARCNET device event */
  void arcnet_led_event(struct net_device *dev, enum arcnet_led_event event)
  {
  	struct arcnet_local *lp = netdev_priv(dev);
  	unsigned long led_delay = 350;
  	unsigned long tx_delay = 50;
  
  	switch (event) {
  	case ARCNET_LED_EVENT_RECON:
  		led_trigger_blink_oneshot(lp->recon_led_trig,
  					  &led_delay, &led_delay, 0);
  		break;
  	case ARCNET_LED_EVENT_OPEN:
  		led_trigger_event(lp->tx_led_trig, LED_OFF);
  		led_trigger_event(lp->recon_led_trig, LED_OFF);
  		break;
  	case ARCNET_LED_EVENT_STOP:
  		led_trigger_event(lp->tx_led_trig, LED_OFF);
  		led_trigger_event(lp->recon_led_trig, LED_OFF);
  		break;
  	case ARCNET_LED_EVENT_TX:
  		led_trigger_blink_oneshot(lp->tx_led_trig,
  					  &tx_delay, &tx_delay, 0);
  		break;
  	}
  }
  EXPORT_SYMBOL_GPL(arcnet_led_event);
  
  static void arcnet_led_release(struct device *gendev, void *res)
  {
  	struct arcnet_local *lp = netdev_priv(to_net_dev(gendev));
  
  	led_trigger_unregister_simple(lp->tx_led_trig);
  	led_trigger_unregister_simple(lp->recon_led_trig);
  }
  
  /* Register ARCNET LED triggers for a arcnet device
   *
   * This is normally called from a driver's probe function
   */
  void devm_arcnet_led_init(struct net_device *netdev, int index, int subid)
  {
  	struct arcnet_local *lp = netdev_priv(netdev);
  	void *res;
  
  	res = devres_alloc(arcnet_led_release, 0, GFP_KERNEL);
  	if (!res) {
  		netdev_err(netdev, "cannot register LED triggers
  ");
  		return;
  	}
  
  	snprintf(lp->tx_led_trig_name, sizeof(lp->tx_led_trig_name),
  		 "arc%d-%d-tx", index, subid);
  	snprintf(lp->recon_led_trig_name, sizeof(lp->recon_led_trig_name),
  		 "arc%d-%d-recon", index, subid);
  
  	led_trigger_register_simple(lp->tx_led_trig_name,
  				    &lp->tx_led_trig);
  	led_trigger_register_simple(lp->recon_led_trig_name,
  				    &lp->recon_led_trig);
  
  	devres_add(&netdev->dev, res);
  }
  EXPORT_SYMBOL_GPL(devm_arcnet_led_init);
f2f0a16bf   Joe Perches   arcnet: Use netwo...
251
  /* Unregister a protocol driver from the arc_proto_map.  Protocol drivers
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
   * are responsible for registering themselves, but the unregister routine
   * is pretty generic so we'll do it here.
   */
  void arcnet_unregister_proto(struct ArcProto *proto)
  {
  	int count;
  
  	if (arc_proto_default == proto)
  		arc_proto_default = &arc_proto_null;
  	if (arc_bcast_proto == proto)
  		arc_bcast_proto = arc_proto_default;
  	if (arc_raw_proto == proto)
  		arc_raw_proto = arc_proto_default;
  
  	for (count = 0; count < 256; count++) {
  		if (arc_proto_map[count] == proto)
  			arc_proto_map[count] = arc_proto_default;
  	}
  }
811eafc02   Joe Perches   arcnet: Move EXPO...
271
  EXPORT_SYMBOL(arcnet_unregister_proto);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272

f2f0a16bf   Joe Perches   arcnet: Use netwo...
273
  /* Add a buffer to the queue.  Only the interrupt handler is allowed to do
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
   * this, unless interrupts are disabled.
cb334648a   Joe Perches   arcnet: Use norma...
275
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
277
278
279
280
   * Note: we don't check for a full queue, since there aren't enough buffers
   * to more than fill it.
   */
  static void release_arcbuf(struct net_device *dev, int bufnum)
  {
454d7c9b1   Wang Chen   netdevice: safe c...
281
  	struct arcnet_local *lp = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
283
284
285
  	int i;
  
  	lp->buf_queue[lp->first_free_buf++] = bufnum;
  	lp->first_free_buf %= 5;
72aeea484   Joe Perches   arcnet: Expand od...
286
  	if (BUGLVL(D_DURING)) {
a34c0932c   Joe Perches   arcnet: Convert B...
287
288
  		arc_printk(D_DURING, dev, "release_arcbuf: freed #%d; buffer queue is now: ",
  			   bufnum);
cb334648a   Joe Perches   arcnet: Use norma...
289
  		for (i = lp->next_buf; i != lp->first_free_buf; i = (i + 1) % 5)
a34c0932c   Joe Perches   arcnet: Convert B...
290
291
292
  			arc_cont(D_DURING, "#%d ", lp->buf_queue[i]);
  		arc_cont(D_DURING, "
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
294
  	}
  }
f2f0a16bf   Joe Perches   arcnet: Use netwo...
295
296
  /* Get a buffer from the queue.
   * If this returns -1, there are no buffers available.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
299
   */
  static int get_arcbuf(struct net_device *dev)
  {
454d7c9b1   Wang Chen   netdevice: safe c...
300
  	struct arcnet_local *lp = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
302
303
304
  	int buf = -1, i;
  
  	if (!atomic_dec_and_test(&lp->buf_lock)) {
  		/* already in this function */
a34c0932c   Joe Perches   arcnet: Convert B...
305
306
307
  		arc_printk(D_NORMAL, dev, "get_arcbuf: overlap (%d)!
  ",
  			   lp->buf_lock.counter);
7f5e760c1   Joe Perches   arcnet: Use norma...
308
  	} else {			/* we can continue */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
310
  		if (lp->next_buf >= 5)
  			lp->next_buf -= 5;
7f5e760c1   Joe Perches   arcnet: Use norma...
311
  		if (lp->next_buf == lp->first_free_buf) {
a34c0932c   Joe Perches   arcnet: Convert B...
312
313
  			arc_printk(D_NORMAL, dev, "get_arcbuf: BUG: no buffers are available??
  ");
7f5e760c1   Joe Perches   arcnet: Use norma...
314
  		} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
316
317
318
  			buf = lp->buf_queue[lp->next_buf++];
  			lp->next_buf %= 5;
  		}
  	}
72aeea484   Joe Perches   arcnet: Expand od...
319
  	if (BUGLVL(D_DURING)) {
a34c0932c   Joe Perches   arcnet: Convert B...
320
321
  		arc_printk(D_DURING, dev, "get_arcbuf: got #%d; buffer queue is now: ",
  			   buf);
cb334648a   Joe Perches   arcnet: Use norma...
322
  		for (i = lp->next_buf; i != lp->first_free_buf; i = (i + 1) % 5)
a34c0932c   Joe Perches   arcnet: Convert B...
323
324
325
  			arc_cont(D_DURING, "#%d ", lp->buf_queue[i]);
  		arc_cont(D_DURING, "
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
327
328
329
330
  	}
  
  	atomic_inc(&lp->buf_lock);
  	return buf;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
332
333
334
335
336
  static int choose_mtu(void)
  {
  	int count, mtu = 65535;
  
  	/* choose the smallest MTU of all available encaps */
  	for (count = 0; count < 256; count++) {
8e95a2026   Joe Perches   drivers/net: Move...
337
338
  		if (arc_proto_map[count] != &arc_proto_null &&
  		    arc_proto_map[count]->mtu < mtu) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
340
341
342
343
344
  			mtu = arc_proto_map[count]->mtu;
  		}
  	}
  
  	return mtu == 65535 ? XMTU : mtu;
  }
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
345
346
  static const struct header_ops arcnet_header_ops = {
  	.create = arcnet_header,
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
347
  };
bca5b8939   Stephen Hemminger   arcnet: convert t...
348
349
350
351
352
353
  static const struct net_device_ops arcnet_netdev_ops = {
  	.ndo_open	= arcnet_open,
  	.ndo_stop	= arcnet_close,
  	.ndo_start_xmit = arcnet_send_packet,
  	.ndo_tx_timeout = arcnet_timeout,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
355
356
357
358
  
  /* Setup a struct device for ARCnet. */
  static void arcdev_setup(struct net_device *dev)
  {
  	dev->type = ARPHRD_ARCNET;
bca5b8939   Stephen Hemminger   arcnet: convert t...
359
  	dev->netdev_ops = &arcnet_netdev_ops;
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
360
  	dev->header_ops = &arcnet_header_ops;
980137a20   Michael Grzeschik   ARCNET: fix hard_...
361
  	dev->hard_header_len = sizeof(struct arc_hardware);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
363
364
365
366
367
368
369
370
  	dev->mtu = choose_mtu();
  
  	dev->addr_len = ARCNET_ALEN;
  	dev->tx_queue_len = 100;
  	dev->broadcast[0] = 0x00;	/* for us, broadcasts are address 0 */
  	dev->watchdog_timeo = TX_TIMEOUT;
  
  	/* New-style flags. */
  	dev->flags = IFF_BROADCAST;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
  }
c58320de5   Kees Cook   drivers/net: arcn...
372
  static void arcnet_timer(struct timer_list *t)
59fbcbc61   Michael Grzeschik   arcnet: add netif...
373
  {
c58320de5   Kees Cook   drivers/net: arcn...
374
375
  	struct arcnet_local *lp = from_timer(lp, t, timer);
  	struct net_device *dev = lp->dev;
59fbcbc61   Michael Grzeschik   arcnet: add netif...
376
377
378
379
380
381
382
  
  	if (!netif_carrier_ok(dev)) {
  		netif_carrier_on(dev);
  		netdev_info(dev, "link up
  ");
  	}
  }
05fcd31cc   Michael Grzeschik   arcnet: add err_s...
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
  static void arcnet_reply_tasklet(unsigned long data)
  {
  	struct arcnet_local *lp = (struct arcnet_local *)data;
  
  	struct sk_buff *ackskb, *skb;
  	struct sock_exterr_skb *serr;
  	struct sock *sk;
  	int ret;
  
  	local_irq_disable();
  	skb = lp->outgoing.skb;
  	if (!skb || !skb->sk) {
  		local_irq_enable();
  		return;
  	}
  
  	sock_hold(skb->sk);
  	sk = skb->sk;
  	ackskb = skb_clone_sk(skb);
  	sock_put(skb->sk);
  
  	if (!ackskb) {
  		local_irq_enable();
  		return;
  	}
  
  	serr = SKB_EXT_ERR(ackskb);
  	memset(serr, 0, sizeof(*serr));
  	serr->ee.ee_errno = ENOMSG;
  	serr->ee.ee_origin = SO_EE_ORIGIN_TXSTATUS;
  	serr->ee.ee_data = skb_shinfo(skb)->tskey;
  	serr->ee.ee_info = lp->reply_status;
  
  	/* finally erasing outgoing skb */
  	dev_kfree_skb(lp->outgoing.skb);
  	lp->outgoing.skb = NULL;
  
  	ackskb->dev = lp->dev;
  
  	ret = sock_queue_err_skb(sk, ackskb);
  	if (ret)
  		kfree_skb(ackskb);
  
  	local_irq_enable();
  };
bca5b8939   Stephen Hemminger   arcnet: convert t...
428
  struct net_device *alloc_arcdev(const char *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
430
431
432
  {
  	struct net_device *dev;
  
  	dev = alloc_netdev(sizeof(struct arcnet_local),
c835a6773   Tom Gundersen   net: set name_ass...
433
434
  			   name && *name ? name : "arc%d", NET_NAME_UNKNOWN,
  			   arcdev_setup);
cb334648a   Joe Perches   arcnet: Use norma...
435
  	if (dev) {
454d7c9b1   Wang Chen   netdevice: safe c...
436
  		struct arcnet_local *lp = netdev_priv(dev);
01a1d5ac4   Joe Perches   arcnet: Add and r...
437

05fcd31cc   Michael Grzeschik   arcnet: add err_s...
438
  		lp->dev = dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
  		spin_lock_init(&lp->lock);
c58320de5   Kees Cook   drivers/net: arcn...
440
  		timer_setup(&lp->timer, arcnet_timer, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
442
443
444
  	}
  
  	return dev;
  }
811eafc02   Joe Perches   arcnet: Move EXPO...
445
  EXPORT_SYMBOL(alloc_arcdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446

f2f0a16bf   Joe Perches   arcnet: Use netwo...
447
  /* Open/initialize the board.  This is called sometime after booting when
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
449
450
451
452
453
   * the 'ifconfig' program is run.
   *
   * This routine should set everything up anew at each open, even registers
   * that "should" only need to be set once at boot, so that there is
   * non-reboot way to recover if something goes wrong.
   */
bca5b8939   Stephen Hemminger   arcnet: convert t...
454
  int arcnet_open(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
  {
454d7c9b1   Wang Chen   netdevice: safe c...
456
  	struct arcnet_local *lp = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
  	int count, newmtu, error;
a34c0932c   Joe Perches   arcnet: Convert B...
458
  	arc_printk(D_INIT, dev, "opened.");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
460
461
  
  	if (!try_module_get(lp->hw.owner))
  		return -ENODEV;
72aeea484   Joe Perches   arcnet: Expand od...
462
  	if (BUGLVL(D_PROTO)) {
a34c0932c   Joe Perches   arcnet: Convert B...
463
464
  		arc_printk(D_PROTO, dev, "protocol map (default is '%c'): ",
  			   arc_proto_default->suffix);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
  		for (count = 0; count < 256; count++)
a34c0932c   Joe Perches   arcnet: Convert B...
466
467
468
  			arc_cont(D_PROTO, "%c", arc_proto_map[count]->suffix);
  		arc_cont(D_PROTO, "
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
  	}
05fcd31cc   Michael Grzeschik   arcnet: add err_s...
470
471
  	tasklet_init(&lp->reply_tasklet, arcnet_reply_tasklet,
  		     (unsigned long)lp);
a34c0932c   Joe Perches   arcnet: Convert B...
472
473
  	arc_printk(D_INIT, dev, "arcnet_open: resetting card.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
475
476
477
478
  
  	/* try to put the card in a defined state - if it fails the first
  	 * time, actually reset it.
  	 */
  	error = -ENODEV;
e15b03625   Joe Perches   arcnet: Remove fu...
479
  	if (lp->hw.reset(dev, 0) && lp->hw.reset(dev, 1))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
481
482
483
484
  		goto out_module_put;
  
  	newmtu = choose_mtu();
  	if (newmtu < dev->mtu)
  		dev->mtu = newmtu;
a34c0932c   Joe Perches   arcnet: Convert B...
485
486
  	arc_printk(D_INIT, dev, "arcnet_open: mtu: %d.
  ", dev->mtu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
  
  	/* autodetect the encapsulation for each host. */
  	memset(lp->default_proto, 0, sizeof(lp->default_proto));
  
  	/* the broadcast address is special - use the 'bcast' protocol */
  	for (count = 0; count < 256; count++) {
  		if (arc_proto_map[count] == arc_bcast_proto) {
  			lp->default_proto[0] = count;
  			break;
  		}
  	}
  
  	/* initialize buffers */
  	atomic_set(&lp->buf_lock, 1);
  
  	lp->next_buf = lp->first_free_buf = 0;
  	release_arcbuf(dev, 0);
  	release_arcbuf(dev, 1);
  	release_arcbuf(dev, 2);
  	release_arcbuf(dev, 3);
  	lp->cur_tx = lp->next_tx = -1;
  	lp->cur_rx = -1;
  
  	lp->rfc1201.sequence = 1;
  
  	/* bring up the hardware driver */
  	if (lp->hw.open)
  		lp->hw.open(dev);
  
  	if (dev->dev_addr[0] == 0)
a34c0932c   Joe Perches   arcnet: Convert B...
517
518
  		arc_printk(D_NORMAL, dev, "WARNING!  Station address 00 is reserved for broadcasts!
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
  	else if (dev->dev_addr[0] == 255)
a34c0932c   Joe Perches   arcnet: Convert B...
520
521
  		arc_printk(D_NORMAL, dev, "WARNING!  Station address FF may confuse DOS networking programs!
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522

a34c0932c   Joe Perches   arcnet: Convert B...
523
524
  	arc_printk(D_DEBUG, dev, "%s: %d: %s
  ", __FILE__, __LINE__, __func__);
e15b03625   Joe Perches   arcnet: Remove fu...
525
  	if (lp->hw.status(dev) & RESETflag) {
a34c0932c   Joe Perches   arcnet: Convert B...
526
527
528
  		arc_printk(D_DEBUG, dev, "%s: %d: %s
  ",
  			   __FILE__, __LINE__, __func__);
e15b03625   Joe Perches   arcnet: Remove fu...
529
  		lp->hw.command(dev, CFLAGScmd | RESETclear);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
  	}
a34c0932c   Joe Perches   arcnet: Convert B...
531
532
  	arc_printk(D_DEBUG, dev, "%s: %d: %s
  ", __FILE__, __LINE__, __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
  	/* make sure we're ready to receive IRQ's. */
e15b03625   Joe Perches   arcnet: Remove fu...
534
  	lp->hw.intmask(dev, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
536
537
538
  	udelay(1);		/* give it time to set the mask before
  				 * we reset it again. (may not even be
  				 * necessary)
  				 */
a34c0932c   Joe Perches   arcnet: Convert B...
539
540
  	arc_printk(D_DEBUG, dev, "%s: %d: %s
  ", __FILE__, __LINE__, __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
  	lp->intmask = NORXflag | RECONflag;
e15b03625   Joe Perches   arcnet: Remove fu...
542
  	lp->hw.intmask(dev, lp->intmask);
a34c0932c   Joe Perches   arcnet: Convert B...
543
544
  	arc_printk(D_DEBUG, dev, "%s: %d: %s
  ", __FILE__, __LINE__, __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545

59fbcbc61   Michael Grzeschik   arcnet: add netif...
546
  	netif_carrier_off(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547
  	netif_start_queue(dev);
59fbcbc61   Michael Grzeschik   arcnet: add netif...
548
  	mod_timer(&lp->timer, jiffies + msecs_to_jiffies(1000));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549

8890624a4   Michael Grzeschik   arcnet: com20020-...
550
  	arcnet_led_event(dev, ARCNET_LED_EVENT_OPEN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
552
553
554
555
556
  	return 0;
  
   out_module_put:
  	module_put(lp->hw.owner);
  	return error;
  }
811eafc02   Joe Perches   arcnet: Move EXPO...
557
  EXPORT_SYMBOL(arcnet_open);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
  /* The inverse routine to arcnet_open - shuts down the card. */
bca5b8939   Stephen Hemminger   arcnet: convert t...
560
  int arcnet_close(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
  {
454d7c9b1   Wang Chen   netdevice: safe c...
562
  	struct arcnet_local *lp = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563

8890624a4   Michael Grzeschik   arcnet: com20020-...
564
  	arcnet_led_event(dev, ARCNET_LED_EVENT_STOP);
59fbcbc61   Michael Grzeschik   arcnet: add netif...
565
  	del_timer_sync(&lp->timer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
  	netif_stop_queue(dev);
59fbcbc61   Michael Grzeschik   arcnet: add netif...
567
  	netif_carrier_off(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568

05fcd31cc   Michael Grzeschik   arcnet: add err_s...
569
  	tasklet_kill(&lp->reply_tasklet);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
  	/* flush TX and disable RX */
e15b03625   Joe Perches   arcnet: Remove fu...
571
572
573
  	lp->hw.intmask(dev, 0);
  	lp->hw.command(dev, NOTXcmd);	/* stop transmit */
  	lp->hw.command(dev, NORXcmd);	/* disable receive */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
575
576
577
578
579
580
  	mdelay(1);
  
  	/* shut down the card */
  	lp->hw.close(dev);
  	module_put(lp->hw.owner);
  	return 0;
  }
811eafc02   Joe Perches   arcnet: Move EXPO...
581
  EXPORT_SYMBOL(arcnet_close);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583
  static int arcnet_header(struct sk_buff *skb, struct net_device *dev,
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
584
585
  			 unsigned short type, const void *daddr,
  			 const void *saddr, unsigned len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586
  {
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
587
  	const struct arcnet_local *lp = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
589
  	uint8_t _daddr, proto_num;
  	struct ArcProto *proto;
a34c0932c   Joe Perches   arcnet: Convert B...
590
591
592
593
594
595
  	arc_printk(D_DURING, dev,
  		   "create header from %d to %d; protocol %d (%Xh); size %u.
  ",
  		   saddr ? *(uint8_t *)saddr : -1,
  		   daddr ? *(uint8_t *)daddr : -1,
  		   type, type, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
596

cb334648a   Joe Perches   arcnet: Use norma...
597
  	if (skb->len != 0 && len != skb->len)
a34c0932c   Joe Perches   arcnet: Convert B...
598
599
600
  		arc_printk(D_NORMAL, dev, "arcnet_header: Yikes!  skb->len(%d) != len(%d)!
  ",
  			   skb->len, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601

cb334648a   Joe Perches   arcnet: Use norma...
602
603
604
  	/* Type is host order - ? */
  	if (type == ETH_P_ARCNET) {
  		proto = arc_raw_proto;
a34c0932c   Joe Perches   arcnet: Convert B...
605
606
607
  		arc_printk(D_DEBUG, dev, "arc_raw_proto used. proto='%c'
  ",
  			   proto->suffix);
cb334648a   Joe Perches   arcnet: Use norma...
608
  		_daddr = daddr ? *(uint8_t *)daddr : 0;
7f5e760c1   Joe Perches   arcnet: Use norma...
609
  	} else if (!daddr) {
f2f0a16bf   Joe Perches   arcnet: Use netwo...
610
611
612
613
  		/* if the dest addr isn't provided, we can't choose an
  		 * encapsulation!  Store the packet type (eg. ETH_P_IP)
  		 * for now, and we'll push on a real header when we do
  		 * rebuild_header.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
614
  		 */
cb334648a   Joe Perches   arcnet: Use norma...
615
  		*(uint16_t *)skb_push(skb, 2) = type;
f2f0a16bf   Joe Perches   arcnet: Use netwo...
616
  		/* XXX: Why not use skb->mac_len? */
b0e380b1d   Arnaldo Carvalho de Melo   [SK_BUFF]: unions...
617
  		if (skb->network_header - skb->mac_header != 2)
a34c0932c   Joe Perches   arcnet: Convert B...
618
619
620
  			arc_printk(D_NORMAL, dev, "arcnet_header: Yikes!  diff (%u) is not 2!
  ",
  				   skb->network_header - skb->mac_header);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
  		return -2;	/* return error -- can't transmit yet! */
7f5e760c1   Joe Perches   arcnet: Use norma...
622
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623
  		/* otherwise, we can just add the header as usual. */
cb334648a   Joe Perches   arcnet: Use norma...
624
  		_daddr = *(uint8_t *)daddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
626
  		proto_num = lp->default_proto[_daddr];
  		proto = arc_proto_map[proto_num];
a34c0932c   Joe Perches   arcnet: Convert B...
627
628
629
  		arc_printk(D_DURING, dev, "building header for %02Xh using protocol '%c'
  ",
  			   proto_num, proto->suffix);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
  		if (proto == &arc_proto_null && arc_bcast_proto != proto) {
a34c0932c   Joe Perches   arcnet: Convert B...
631
632
633
  			arc_printk(D_DURING, dev, "actually, let's use '%c' instead.
  ",
  				   arc_bcast_proto->suffix);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
634
635
636
637
638
  			proto = arc_bcast_proto;
  		}
  	}
  	return proto->build_header(skb, dev, type, _daddr);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
639
  /* Called by the kernel in order to transmit a packet. */
61357325f   Stephen Hemminger   netdev: convert b...
640
  netdev_tx_t arcnet_send_packet(struct sk_buff *skb,
cb334648a   Joe Perches   arcnet: Use norma...
641
  			       struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
642
  {
454d7c9b1   Wang Chen   netdevice: safe c...
643
  	struct arcnet_local *lp = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
645
646
647
648
  	struct archdr *pkt;
  	struct arc_rfc1201 *soft;
  	struct ArcProto *proto;
  	int txbuf;
  	unsigned long flags;
b82de0e28   Michael Grzeschik   arcnet: move dev_...
649
  	int retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650

a34c0932c   Joe Perches   arcnet: Convert B...
651
652
653
  	arc_printk(D_DURING, dev,
  		   "transmit requested (status=%Xh, txbufs=%d/%d, len=%d, protocol %x)
  ",
e15b03625   Joe Perches   arcnet: Remove fu...
654
  		   lp->hw.status(dev), lp->cur_tx, lp->next_tx, skb->len, skb->protocol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655

cb334648a   Joe Perches   arcnet: Use norma...
656
  	pkt = (struct archdr *)skb->data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
657
658
  	soft = &pkt->soft.rfc1201;
  	proto = arc_proto_map[soft->proto];
a34c0932c   Joe Perches   arcnet: Convert B...
659
660
661
  	arc_printk(D_SKB_SIZE, dev, "skb: transmitting %d bytes to %02X
  ",
  		   skb->len, pkt->hard.dest);
72aeea484   Joe Perches   arcnet: Expand od...
662
663
  	if (BUGLVL(D_SKB))
  		arcnet_dump_skb(dev, skb, "tx");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
665
666
  
  	/* fits in one packet? */
  	if (skb->len - ARC_HDR_SIZE > XMTU && !proto->continue_tx) {
a34c0932c   Joe Perches   arcnet: Convert B...
667
668
  		arc_printk(D_NORMAL, dev, "fixme: packet too large: compensating badly!
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
  		dev_kfree_skb(skb);
c6bb15a0c   Pieter Dejaeghere   [ARCNET]: Fix ret...
670
  		return NETDEV_TX_OK;	/* don't try again */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
672
673
674
675
676
  	}
  
  	/* We're busy transmitting a packet... */
  	netif_stop_queue(dev);
  
  	spin_lock_irqsave(&lp->lock, flags);
e15b03625   Joe Perches   arcnet: Remove fu...
677
  	lp->hw.intmask(dev, 0);
cb334648a   Joe Perches   arcnet: Use norma...
678
  	if (lp->next_tx == -1)
c6bb15a0c   Pieter Dejaeghere   [ARCNET]: Fix ret...
679
  		txbuf = get_arcbuf(dev);
7f5e760c1   Joe Perches   arcnet: Use norma...
680
  	else
c6bb15a0c   Pieter Dejaeghere   [ARCNET]: Fix ret...
681
  		txbuf = -1;
7f5e760c1   Joe Perches   arcnet: Use norma...
682

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683
  	if (txbuf != -1) {
05fcd31cc   Michael Grzeschik   arcnet: add err_s...
684
  		lp->outgoing.skb = skb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
686
687
  		if (proto->prepare_tx(dev, pkt, skb->len, txbuf) &&
  		    !proto->ack_tx) {
  			/* done right away and we don't want to acknowledge
f2f0a16bf   Joe Perches   arcnet: Use netwo...
688
689
  			 *  the package later - forget about it now
  			 */
5803c5122   Stephen Hemminger   arcnet: convert t...
690
  			dev->stats.tx_bytes += skb->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
691
692
693
694
695
696
697
698
  		} else {
  			/* do it the 'split' way */
  			lp->outgoing.proto = proto;
  			lp->outgoing.skb = skb;
  			lp->outgoing.pkt = pkt;
  
  			if (proto->continue_tx &&
  			    proto->continue_tx(dev, txbuf)) {
a34c0932c   Joe Perches   arcnet: Convert B...
699
700
701
702
  				arc_printk(D_NORMAL, dev,
  					   "bug! continue_tx finished the first time! (proto='%c')
  ",
  					   proto->suffix);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
703
704
  			}
  		}
c6bb15a0c   Pieter Dejaeghere   [ARCNET]: Fix ret...
705
  		retval = NETDEV_TX_OK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706
707
  		lp->next_tx = txbuf;
  	} else {
c6bb15a0c   Pieter Dejaeghere   [ARCNET]: Fix ret...
708
  		retval = NETDEV_TX_BUSY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
709
  	}
a34c0932c   Joe Perches   arcnet: Convert B...
710
711
  	arc_printk(D_DEBUG, dev, "%s: %d: %s, status: %x
  ",
e15b03625   Joe Perches   arcnet: Remove fu...
712
  		   __FILE__, __LINE__, __func__, lp->hw.status(dev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713
  	/* make sure we didn't ignore a TX IRQ while we were in here */
e15b03625   Joe Perches   arcnet: Remove fu...
714
  	lp->hw.intmask(dev, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
715

a34c0932c   Joe Perches   arcnet: Convert B...
716
717
  	arc_printk(D_DEBUG, dev, "%s: %d: %s
  ", __FILE__, __LINE__, __func__);
cb334648a   Joe Perches   arcnet: Use norma...
718
  	lp->intmask |= TXFREEflag | EXCNAKflag;
e15b03625   Joe Perches   arcnet: Remove fu...
719
  	lp->hw.intmask(dev, lp->intmask);
a34c0932c   Joe Perches   arcnet: Convert B...
720
721
  	arc_printk(D_DEBUG, dev, "%s: %d: %s, status: %x
  ",
e15b03625   Joe Perches   arcnet: Remove fu...
722
  		   __FILE__, __LINE__, __func__, lp->hw.status(dev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
723

8890624a4   Michael Grzeschik   arcnet: com20020-...
724
  	arcnet_led_event(dev, ARCNET_LED_EVENT_TX);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725
  	spin_unlock_irqrestore(&lp->lock, flags);
c6bb15a0c   Pieter Dejaeghere   [ARCNET]: Fix ret...
726
  	return retval;		/* no need to try again */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
  }
811eafc02   Joe Perches   arcnet: Move EXPO...
728
  EXPORT_SYMBOL(arcnet_send_packet);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
729

f2f0a16bf   Joe Perches   arcnet: Use netwo...
730
  /* Actually start transmitting a packet that was loaded into a buffer
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731
732
733
734
   * by prepare_tx.  This should _only_ be called by the interrupt handler.
   */
  static int go_tx(struct net_device *dev)
  {
454d7c9b1   Wang Chen   netdevice: safe c...
735
  	struct arcnet_local *lp = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736

a34c0932c   Joe Perches   arcnet: Convert B...
737
738
  	arc_printk(D_DURING, dev, "go_tx: status=%Xh, intmask=%Xh, next_tx=%d, cur_tx=%d
  ",
e15b03625   Joe Perches   arcnet: Remove fu...
739
  		   lp->hw.status(dev), lp->intmask, lp->next_tx, lp->cur_tx);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
741
742
  
  	if (lp->cur_tx != -1 || lp->next_tx == -1)
  		return 0;
72aeea484   Joe Perches   arcnet: Expand od...
743
744
  	if (BUGLVL(D_TX))
  		arcnet_dump_packet(dev, lp->next_tx, "go_tx", 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
745
746
747
748
749
  
  	lp->cur_tx = lp->next_tx;
  	lp->next_tx = -1;
  
  	/* start sending */
e15b03625   Joe Perches   arcnet: Remove fu...
750
  	lp->hw.command(dev, TXcmd | (lp->cur_tx << 3));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751

5803c5122   Stephen Hemminger   arcnet: convert t...
752
  	dev->stats.tx_packets++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
754
755
  	lp->lasttrans_dest = lp->lastload_dest;
  	lp->lastload_dest = 0;
  	lp->excnak_pending = 0;
cb334648a   Joe Perches   arcnet: Use norma...
756
  	lp->intmask |= TXFREEflag | EXCNAKflag;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
758
759
  
  	return 1;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760
  /* Called by the kernel when transmit times out */
0290bd291   Michael S. Tsirkin   netdev: pass the ...
761
  void arcnet_timeout(struct net_device *dev, unsigned int txqueue)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762
763
  {
  	unsigned long flags;
454d7c9b1   Wang Chen   netdevice: safe c...
764
  	struct arcnet_local *lp = netdev_priv(dev);
e15b03625   Joe Perches   arcnet: Remove fu...
765
  	int status = lp->hw.status(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
766
767
768
769
770
771
772
  	char *msg;
  
  	spin_lock_irqsave(&lp->lock, flags);
  	if (status & TXFREEflag) {	/* transmit _DID_ finish */
  		msg = " - missed IRQ?";
  	} else {
  		msg = "";
5803c5122   Stephen Hemminger   arcnet: convert t...
773
  		dev->stats.tx_aborted_errors++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
774
  		lp->timed_out = 1;
e15b03625   Joe Perches   arcnet: Remove fu...
775
  		lp->hw.command(dev, NOTXcmd | (lp->cur_tx << 3));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776
  	}
5803c5122   Stephen Hemminger   arcnet: convert t...
777
  	dev->stats.tx_errors++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
778
779
  
  	/* make sure we didn't miss a TX or a EXC NAK IRQ */
e15b03625   Joe Perches   arcnet: Remove fu...
780
  	lp->hw.intmask(dev, 0);
cb334648a   Joe Perches   arcnet: Use norma...
781
  	lp->intmask |= TXFREEflag | EXCNAKflag;
e15b03625   Joe Perches   arcnet: Remove fu...
782
  	lp->hw.intmask(dev, lp->intmask);
cb334648a   Joe Perches   arcnet: Use norma...
783

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784
  	spin_unlock_irqrestore(&lp->lock, flags);
cb334648a   Joe Perches   arcnet: Use norma...
785
  	if (time_after(jiffies, lp->last_timeout + 10 * HZ)) {
a34c0932c   Joe Perches   arcnet: Convert B...
786
787
788
  		arc_printk(D_EXTRA, dev, "tx timed out%s (status=%Xh, intmask=%Xh, dest=%02Xh)
  ",
  			   msg, status, lp->intmask, lp->lasttrans_dest);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789
790
791
792
793
794
  		lp->last_timeout = jiffies;
  	}
  
  	if (lp->cur_tx == -1)
  		netif_wake_queue(dev);
  }
811eafc02   Joe Perches   arcnet: Move EXPO...
795
  EXPORT_SYMBOL(arcnet_timeout);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
796

f2f0a16bf   Joe Perches   arcnet: Use netwo...
797
  /* The typical workload of the driver: Handle the network interface
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
799
800
   * interrupts. Establish which device needs attention, and call the correct
   * chipset interrupt handler.
   */
7d12e780e   David Howells   IRQ: Maintain reg...
801
  irqreturn_t arcnet_interrupt(int irq, void *dev_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
803
804
805
  {
  	struct net_device *dev = dev_id;
  	struct arcnet_local *lp;
  	int recbuf, status, diagstatus, didsomething, boguscount;
5b8584032   Michael Grzeschik   arcnet: change ir...
806
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
  	int retval = IRQ_NONE;
a34c0932c   Joe Perches   arcnet: Convert B...
808
809
  	arc_printk(D_DURING, dev, "
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810

a34c0932c   Joe Perches   arcnet: Convert B...
811
812
  	arc_printk(D_DURING, dev, "in arcnet_interrupt
  ");
454d7c9b1   Wang Chen   netdevice: safe c...
813
814
  
  	lp = netdev_priv(dev);
5d9428de1   Eric Sesterhenn   BUG_ON() Conversi...
815
  	BUG_ON(!lp);
cb334648a   Joe Perches   arcnet: Use norma...
816

5b8584032   Michael Grzeschik   arcnet: change ir...
817
  	spin_lock_irqsave(&lp->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
818

f2f0a16bf   Joe Perches   arcnet: Use netwo...
819
820
  	/* RESET flag was enabled - if device is not running, we must
  	 * clear it right away (but nothing else).
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
821
822
  	 */
  	if (!netif_running(dev)) {
e15b03625   Joe Perches   arcnet: Remove fu...
823
824
825
  		if (lp->hw.status(dev) & RESETflag)
  			lp->hw.command(dev, CFLAGScmd | RESETclear);
  		lp->hw.intmask(dev, 0);
5b8584032   Michael Grzeschik   arcnet: change ir...
826
  		spin_unlock_irqrestore(&lp->lock, flags);
226ee6751   Michael Grzeschik   ARCNET: return IR...
827
  		return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
828
  	}
a34c0932c   Joe Perches   arcnet: Convert B...
829
830
  	arc_printk(D_DURING, dev, "in arcnet_inthandler (status=%Xh, intmask=%Xh)
  ",
e15b03625   Joe Perches   arcnet: Remove fu...
831
  		   lp->hw.status(dev), lp->intmask);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
832
833
834
  
  	boguscount = 5;
  	do {
e15b03625   Joe Perches   arcnet: Remove fu...
835
  		status = lp->hw.status(dev);
cb334648a   Joe Perches   arcnet: Use norma...
836
  		diagstatus = (status >> 8) & 0xFF;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
837

a34c0932c   Joe Perches   arcnet: Convert B...
838
839
840
  		arc_printk(D_DEBUG, dev, "%s: %d: %s: status=%x
  ",
  			   __FILE__, __LINE__, __func__, status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
  		didsomething = 0;
f2f0a16bf   Joe Perches   arcnet: Use netwo...
842
  		/* RESET flag was enabled - card is resetting and if RX is
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
843
  		 * disabled, it's NOT because we just got a packet.
cb334648a   Joe Perches   arcnet: Use norma...
844
  		 *
f2f0a16bf   Joe Perches   arcnet: Use netwo...
845
846
  		 * The card is in an undefined state.
  		 * Clear it out and start over.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
847
848
  		 */
  		if (status & RESETflag) {
a34c0932c   Joe Perches   arcnet: Convert B...
849
850
851
  			arc_printk(D_NORMAL, dev, "spurious reset (status=%Xh)
  ",
  				   status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852
853
854
855
856
857
  			arcnet_close(dev);
  			arcnet_open(dev);
  
  			/* get out of the interrupt handler! */
  			break;
  		}
f2f0a16bf   Joe Perches   arcnet: Use netwo...
858
859
  		/* RX is inhibited - we must have received something.
  		 * Prepare to receive into the next buffer.
cb334648a   Joe Perches   arcnet: Use norma...
860
  		 *
f2f0a16bf   Joe Perches   arcnet: Use netwo...
861
862
863
864
  		 * We don't actually copy the received packet from the card
  		 * until after the transmit handler runs (and possibly
  		 * launches the next tx); this should improve latency slightly
  		 * if we get both types of interrupts at once.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
865
866
867
868
  		 */
  		recbuf = -1;
  		if (status & lp->intmask & NORXflag) {
  			recbuf = lp->cur_rx;
a34c0932c   Joe Perches   arcnet: Convert B...
869
870
871
  			arc_printk(D_DURING, dev, "Buffer #%d: receive irq (status=%Xh)
  ",
  				   recbuf, status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
872
873
874
  
  			lp->cur_rx = get_arcbuf(dev);
  			if (lp->cur_rx != -1) {
a34c0932c   Joe Perches   arcnet: Convert B...
875
876
877
  				arc_printk(D_DURING, dev, "enabling receive to buffer #%d
  ",
  					   lp->cur_rx);
e15b03625   Joe Perches   arcnet: Remove fu...
878
  				lp->hw.command(dev, RXcmd | (lp->cur_rx << 3) | RXbcasts);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
879
880
881
  			}
  			didsomething++;
  		}
cb334648a   Joe Perches   arcnet: Use norma...
882
  		if ((diagstatus & EXCNAKflag)) {
a34c0932c   Joe Perches   arcnet: Convert B...
883
884
885
  			arc_printk(D_DURING, dev, "EXCNAK IRQ (diagstat=%Xh)
  ",
  				   diagstatus);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
886

e15b03625   Joe Perches   arcnet: Remove fu...
887
  			lp->hw.command(dev, NOTXcmd);      /* disable transmit */
cb334648a   Joe Perches   arcnet: Use norma...
888
  			lp->excnak_pending = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
889

e15b03625   Joe Perches   arcnet: Remove fu...
890
  			lp->hw.command(dev, EXCNAKclear);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
891
  			lp->intmask &= ~(EXCNAKflag);
cb334648a   Joe Perches   arcnet: Use norma...
892
893
  			didsomething++;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
895
896
  		/* a transmit finished, and we're interested in it. */
  		if ((status & lp->intmask & TXFREEflag) || lp->timed_out) {
05fcd31cc   Michael Grzeschik   arcnet: add err_s...
897
  			int ackstatus;
cb334648a   Joe Perches   arcnet: Use norma...
898
  			lp->intmask &= ~(TXFREEflag | EXCNAKflag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
899

05fcd31cc   Michael Grzeschik   arcnet: add err_s...
900
901
902
903
904
905
  			if (status & TXACKflag)
  				ackstatus = 2;
  			else if (lp->excnak_pending)
  				ackstatus = 1;
  			else
  				ackstatus = 0;
d6d7d3ed5   Joe Perches   arcnet: Wrap some...
906
907
908
  			arc_printk(D_DURING, dev, "TX IRQ (stat=%Xh)
  ",
  				   status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
909
910
  
  			if (lp->cur_tx != -1 && !lp->timed_out) {
cb334648a   Joe Perches   arcnet: Use norma...
911
  				if (!(status & TXACKflag)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
  					if (lp->lasttrans_dest != 0) {
a34c0932c   Joe Perches   arcnet: Convert B...
913
914
915
916
917
  						arc_printk(D_EXTRA, dev,
  							   "transmit was not acknowledged! (status=%Xh, dest=%02Xh)
  ",
  							   status,
  							   lp->lasttrans_dest);
5803c5122   Stephen Hemminger   arcnet: convert t...
918
919
  						dev->stats.tx_errors++;
  						dev->stats.tx_carrier_errors++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
920
  					} else {
a34c0932c   Joe Perches   arcnet: Convert B...
921
922
923
924
925
  						arc_printk(D_DURING, dev,
  							   "broadcast was not acknowledged; that's normal (status=%Xh, dest=%02Xh)
  ",
  							   status,
  							   lp->lasttrans_dest);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
926
927
928
929
930
  					}
  				}
  
  				if (lp->outgoing.proto &&
  				    lp->outgoing.proto->ack_tx) {
cb334648a   Joe Perches   arcnet: Use norma...
931
932
  					lp->outgoing.proto
  						->ack_tx(dev, ackstatus);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
933
  				}
05fcd31cc   Michael Grzeschik   arcnet: add err_s...
934
935
  				lp->reply_status = ackstatus;
  				tasklet_hi_schedule(&lp->reply_tasklet);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936
937
938
939
940
941
942
943
944
945
946
947
  			}
  			if (lp->cur_tx != -1)
  				release_arcbuf(dev, lp->cur_tx);
  
  			lp->cur_tx = -1;
  			lp->timed_out = 0;
  			didsomething++;
  
  			/* send another packet if there is one */
  			go_tx(dev);
  
  			/* continue a split packet, if any */
d6d7d3ed5   Joe Perches   arcnet: Wrap some...
948
949
  			if (lp->outgoing.proto &&
  			    lp->outgoing.proto->continue_tx) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
950
  				int txbuf = get_arcbuf(dev);
01a1d5ac4   Joe Perches   arcnet: Add and r...
951

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952
953
954
  				if (txbuf != -1) {
  					if (lp->outgoing.proto->continue_tx(dev, txbuf)) {
  						/* that was the last segment */
5803c5122   Stephen Hemminger   arcnet: convert t...
955
  						dev->stats.tx_bytes += lp->outgoing.skb->len;
7f5e760c1   Joe Perches   arcnet: Use norma...
956
  						if (!lp->outgoing.proto->ack_tx) {
cb334648a   Joe Perches   arcnet: Use norma...
957
958
959
  							dev_kfree_skb_irq(lp->outgoing.skb);
  							lp->outgoing.proto = NULL;
  						}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960
961
962
963
964
965
966
967
968
969
  					}
  					lp->next_tx = txbuf;
  				}
  			}
  			/* inform upper layers of idleness, if necessary */
  			if (lp->cur_tx == -1)
  				netif_wake_queue(dev);
  		}
  		/* now process the received packet, if any */
  		if (recbuf != -1) {
72aeea484   Joe Perches   arcnet: Expand od...
970
971
  			if (BUGLVL(D_RX))
  				arcnet_dump_packet(dev, recbuf, "rx irq", 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
972
973
974
975
976
977
978
  
  			arcnet_rx(dev, recbuf);
  			release_arcbuf(dev, recbuf);
  
  			didsomething++;
  		}
  		if (status & lp->intmask & RECONflag) {
e15b03625   Joe Perches   arcnet: Remove fu...
979
  			lp->hw.command(dev, CFLAGScmd | CONFIGclear);
5803c5122   Stephen Hemminger   arcnet: convert t...
980
  			dev->stats.tx_carrier_errors++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
981

a34c0932c   Joe Perches   arcnet: Convert B...
982
983
984
  			arc_printk(D_RECON, dev, "Network reconfiguration detected (status=%Xh)
  ",
  				   status);
59fbcbc61   Michael Grzeschik   arcnet: add netif...
985
986
987
988
989
990
  			if (netif_carrier_ok(dev)) {
  				netif_carrier_off(dev);
  				netdev_info(dev, "link down
  ");
  			}
  			mod_timer(&lp->timer, jiffies + msecs_to_jiffies(1000));
8890624a4   Michael Grzeschik   arcnet: com20020-...
991
  			arcnet_led_event(dev, ARCNET_LED_EVENT_RECON);
c6bb15a0c   Pieter Dejaeghere   [ARCNET]: Fix ret...
992
  			/* MYRECON bit is at bit 7 of diagstatus */
cb334648a   Joe Perches   arcnet: Use norma...
993
  			if (diagstatus & 0x80)
a34c0932c   Joe Perches   arcnet: Convert B...
994
995
  				arc_printk(D_RECON, dev, "Put out that recon myself
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
996
997
998
  
  			/* is the RECON info empty or old? */
  			if (!lp->first_recon || !lp->last_recon ||
9307b570a   S.Çağlar Onur   drivers/net/arcne...
999
  			    time_after(jiffies, lp->last_recon + HZ * 10)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1000
  				if (lp->network_down)
a34c0932c   Joe Perches   arcnet: Convert B...
1001
1002
  					arc_printk(D_NORMAL, dev, "reconfiguration detected: cabling restored?
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1003
1004
  				lp->first_recon = lp->last_recon = jiffies;
  				lp->num_recons = lp->network_down = 0;
a34c0932c   Joe Perches   arcnet: Convert B...
1005
1006
  				arc_printk(D_DURING, dev, "recon: clearing counters.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007
1008
1009
  			} else {	/* add to current RECON counter */
  				lp->last_recon = jiffies;
  				lp->num_recons++;
a34c0932c   Joe Perches   arcnet: Convert B...
1010
1011
1012
1013
1014
  				arc_printk(D_DURING, dev, "recon: counter=%d, time=%lds, net=%d
  ",
  					   lp->num_recons,
  					   (lp->last_recon - lp->first_recon) / HZ,
  					   lp->network_down);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1015
1016
1017
1018
1019
1020
1021
  
  				/* if network is marked up;
  				 * and first_recon and last_recon are 60+ apart;
  				 * and the average no. of recons counted is
  				 *    > RECON_THRESHOLD/min;
  				 * then print a warning message.
  				 */
8e95a2026   Joe Perches   drivers/net: Move...
1022
1023
1024
  				if (!lp->network_down &&
  				    (lp->last_recon - lp->first_recon) <= HZ * 60 &&
  				    lp->num_recons >= RECON_THRESHOLD) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1025
  					lp->network_down = 1;
a34c0932c   Joe Perches   arcnet: Convert B...
1026
1027
  					arc_printk(D_NORMAL, dev, "many reconfigurations detected: cabling problem?
  ");
8e95a2026   Joe Perches   drivers/net: Move...
1028
1029
  				} else if (!lp->network_down &&
  					   lp->last_recon - lp->first_recon > HZ * 60) {
d6d7d3ed5   Joe Perches   arcnet: Wrap some...
1030
1031
1032
  					/* reset counters if we've gone for
  					 *  over a minute.
  					 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1033
1034
1035
1036
  					lp->first_recon = lp->last_recon;
  					lp->num_recons = 1;
  				}
  			}
9307b570a   S.Çağlar Onur   drivers/net/arcne...
1037
  		} else if (lp->network_down &&
cb334648a   Joe Perches   arcnet: Use norma...
1038
  			   time_after(jiffies, lp->last_recon + HZ * 10)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1039
  			if (lp->network_down)
a34c0932c   Joe Perches   arcnet: Convert B...
1040
1041
  				arc_printk(D_NORMAL, dev, "cabling restored?
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1042
1043
  			lp->first_recon = lp->last_recon = 0;
  			lp->num_recons = lp->network_down = 0;
a34c0932c   Joe Perches   arcnet: Convert B...
1044
1045
  			arc_printk(D_DURING, dev, "not recon: clearing counters anyway.
  ");
59fbcbc61   Michael Grzeschik   arcnet: add netif...
1046
  			netif_carrier_on(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1047
  		}
7f5e760c1   Joe Perches   arcnet: Use norma...
1048
  		if (didsomething)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1049
  			retval |= IRQ_HANDLED;
7f5e760c1   Joe Perches   arcnet: Use norma...
1050
  	} while (--boguscount && didsomething);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1051

a34c0932c   Joe Perches   arcnet: Convert B...
1052
1053
  	arc_printk(D_DURING, dev, "arcnet_interrupt complete (status=%Xh, count=%d)
  ",
e15b03625   Joe Perches   arcnet: Remove fu...
1054
  		   lp->hw.status(dev), boguscount);
a34c0932c   Joe Perches   arcnet: Convert B...
1055
1056
  	arc_printk(D_DURING, dev, "
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1057

e15b03625   Joe Perches   arcnet: Remove fu...
1058
  	lp->hw.intmask(dev, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1059
  	udelay(1);
e15b03625   Joe Perches   arcnet: Remove fu...
1060
  	lp->hw.intmask(dev, lp->intmask);
cb334648a   Joe Perches   arcnet: Use norma...
1061

5b8584032   Michael Grzeschik   arcnet: change ir...
1062
  	spin_unlock_irqrestore(&lp->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1063
1064
  	return retval;
  }
811eafc02   Joe Perches   arcnet: Move EXPO...
1065
  EXPORT_SYMBOL(arcnet_interrupt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1066

f2f0a16bf   Joe Perches   arcnet: Use netwo...
1067
  /* This is a generic packet receiver that calls arcnet??_rx depending on the
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1068
1069
   * protocol ID found.
   */
f03aa2d89   Adrian Bunk   [PATCH] drivers/n...
1070
  static void arcnet_rx(struct net_device *dev, int bufnum)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1071
  {
454d7c9b1   Wang Chen   netdevice: safe c...
1072
  	struct arcnet_local *lp = netdev_priv(dev);
02a070468   Uwe Kleine-König   arcnet: provide a...
1073
1074
1075
1076
  	union {
  		struct archdr pkt;
  		char buf[512];
  	} rxdata;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1077
1078
  	struct arc_rfc1201 *soft;
  	int length, ofs;
02a070468   Uwe Kleine-König   arcnet: provide a...
1079
  	soft = &rxdata.pkt.soft.rfc1201;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1080

02a070468   Uwe Kleine-König   arcnet: provide a...
1081
1082
1083
  	lp->hw.copy_from_card(dev, bufnum, 0, &rxdata.pkt, ARC_HDR_SIZE);
  	if (rxdata.pkt.hard.offset[0]) {
  		ofs = rxdata.pkt.hard.offset[0];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1084
1085
  		length = 256 - ofs;
  	} else {
02a070468   Uwe Kleine-König   arcnet: provide a...
1086
  		ofs = rxdata.pkt.hard.offset[1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1087
1088
1089
1090
  		length = 512 - ofs;
  	}
  
  	/* get the full header, if possible */
02a070468   Uwe Kleine-König   arcnet: provide a...
1091
1092
  	if (sizeof(rxdata.pkt.soft) <= length) {
  		lp->hw.copy_from_card(dev, bufnum, ofs, soft, sizeof(rxdata.pkt.soft));
7f5e760c1   Joe Perches   arcnet: Use norma...
1093
  	} else {
02a070468   Uwe Kleine-König   arcnet: provide a...
1094
  		memset(&rxdata.pkt.soft, 0, sizeof(rxdata.pkt.soft));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1095
1096
  		lp->hw.copy_from_card(dev, bufnum, ofs, soft, length);
  	}
a34c0932c   Joe Perches   arcnet: Convert B...
1097
1098
  	arc_printk(D_DURING, dev, "Buffer #%d: received packet from %02Xh to %02Xh (%d+4 bytes)
  ",
02a070468   Uwe Kleine-König   arcnet: provide a...
1099
  		   bufnum, rxdata.pkt.hard.source, rxdata.pkt.hard.dest, length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1100

5803c5122   Stephen Hemminger   arcnet: convert t...
1101
1102
  	dev->stats.rx_packets++;
  	dev->stats.rx_bytes += length + ARC_HDR_SIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1103
1104
1105
  
  	/* call the right receiver for the protocol */
  	if (arc_proto_map[soft->proto]->is_ip) {
72aeea484   Joe Perches   arcnet: Expand od...
1106
  		if (BUGLVL(D_PROTO)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1107
  			struct ArcProto
02a070468   Uwe Kleine-König   arcnet: provide a...
1108
  			*oldp = arc_proto_map[lp->default_proto[rxdata.pkt.hard.source]],
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1109
1110
1111
  			*newp = arc_proto_map[soft->proto];
  
  			if (oldp != newp) {
a34c0932c   Joe Perches   arcnet: Convert B...
1112
1113
1114
  				arc_printk(D_PROTO, dev,
  					   "got protocol %02Xh; encap for host %02Xh is now '%c' (was '%c')
  ",
02a070468   Uwe Kleine-König   arcnet: provide a...
1115
  					   soft->proto, rxdata.pkt.hard.source,
a34c0932c   Joe Perches   arcnet: Convert B...
1116
  					   newp->suffix, oldp->suffix);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1117
1118
1119
1120
1121
1122
1123
  			}
  		}
  
  		/* broadcasts will always be done with the last-used encap. */
  		lp->default_proto[0] = soft->proto;
  
  		/* in striking contrast, the following isn't a hack. */
02a070468   Uwe Kleine-König   arcnet: provide a...
1124
  		lp->default_proto[rxdata.pkt.hard.source] = soft->proto;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1125
1126
  	}
  	/* call the protocol-specific receiver. */
02a070468   Uwe Kleine-König   arcnet: provide a...
1127
  	arc_proto_map[soft->proto]->rx(dev, bufnum, &rxdata.pkt, length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1128
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1129
1130
1131
  static void null_rx(struct net_device *dev, int bufnum,
  		    struct archdr *pkthdr, int length)
  {
a34c0932c   Joe Perches   arcnet: Convert B...
1132
1133
1134
1135
  	arc_printk(D_PROTO, dev,
  		   "rx: don't know how to deal with proto %02Xh from host %02Xh.
  ",
  		   pkthdr->soft.rfc1201.proto, pkthdr->hard.source);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1136
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1137
1138
1139
  static int null_build_header(struct sk_buff *skb, struct net_device *dev,
  			     unsigned short type, uint8_t daddr)
  {
454d7c9b1   Wang Chen   netdevice: safe c...
1140
  	struct arcnet_local *lp = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1141

a34c0932c   Joe Perches   arcnet: Convert B...
1142
1143
1144
1145
  	arc_printk(D_PROTO, dev,
  		   "tx: can't build header for encap %02Xh; load a protocol driver.
  ",
  		   lp->default_proto[daddr]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1146
1147
1148
1149
  
  	/* always fails */
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1150
1151
1152
1153
  /* the "do nothing" prepare_tx function warns that there's nothing to do. */
  static int null_prepare_tx(struct net_device *dev, struct archdr *pkt,
  			   int length, int bufnum)
  {
454d7c9b1   Wang Chen   netdevice: safe c...
1154
  	struct arcnet_local *lp = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1155
  	struct arc_hardware newpkt;
a34c0932c   Joe Perches   arcnet: Convert B...
1156
1157
  	arc_printk(D_PROTO, dev, "tx: no encap for this host; load a protocol driver.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
  
  	/* send a packet to myself -- will never get received, of course */
  	newpkt.source = newpkt.dest = dev->dev_addr[0];
  
  	/* only one byte of actual data (and it's random) */
  	newpkt.offset[0] = 0xFF;
  
  	lp->hw.copy_to_card(dev, bufnum, 0, &newpkt, ARC_HDR_SIZE);
  
  	return 1;		/* done */
  }