]>
Commit | Line | Data |
---|---|---|
cfb739b4 GKH |
1 | /* |
2 | * Agere Systems Inc. | |
3 | * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs | |
4 | * | |
64f93036 | 5 | * Copyright © 2005 Agere Systems Inc. |
cfb739b4 GKH |
6 | * All rights reserved. |
7 | * http://www.agere.com | |
8 | * | |
9 | *------------------------------------------------------------------------------ | |
10 | * | |
11 | * et131x_netdev.c - Routines and data required by all Linux network devices. | |
12 | * | |
13 | *------------------------------------------------------------------------------ | |
14 | * | |
15 | * SOFTWARE LICENSE | |
16 | * | |
17 | * This software is provided subject to the following terms and conditions, | |
18 | * which you should read carefully before using the software. Using this | |
19 | * software indicates your acceptance of these terms and conditions. If you do | |
20 | * not agree with these terms and conditions, do not use the software. | |
21 | * | |
64f93036 | 22 | * Copyright © 2005 Agere Systems Inc. |
cfb739b4 GKH |
23 | * All rights reserved. |
24 | * | |
25 | * Redistribution and use in source or binary forms, with or without | |
26 | * modifications, are permitted provided that the following conditions are met: | |
27 | * | |
28 | * . Redistributions of source code must retain the above copyright notice, this | |
29 | * list of conditions and the following Disclaimer as comments in the code as | |
30 | * well as in the documentation and/or other materials provided with the | |
31 | * distribution. | |
32 | * | |
33 | * . Redistributions in binary form must reproduce the above copyright notice, | |
34 | * this list of conditions and the following Disclaimer in the documentation | |
35 | * and/or other materials provided with the distribution. | |
36 | * | |
37 | * . Neither the name of Agere Systems Inc. nor the names of the contributors | |
38 | * may be used to endorse or promote products derived from this software | |
39 | * without specific prior written permission. | |
40 | * | |
41 | * Disclaimer | |
42 | * | |
64f93036 | 43 | * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
cfb739b4 GKH |
44 | * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF |
45 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY | |
46 | * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN | |
47 | * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY | |
48 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
49 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
50 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
51 | * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT | |
52 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
53 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | |
54 | * DAMAGE. | |
55 | * | |
56 | */ | |
57 | ||
58 | #include "et131x_version.h" | |
cfb739b4 GKH |
59 | #include "et131x_defs.h" |
60 | ||
61 | #include <linux/init.h> | |
62 | #include <linux/module.h> | |
63 | #include <linux/types.h> | |
64 | #include <linux/kernel.h> | |
65 | ||
66 | #include <linux/sched.h> | |
67 | #include <linux/ptrace.h> | |
68 | #include <linux/slab.h> | |
69 | #include <linux/ctype.h> | |
70 | #include <linux/string.h> | |
71 | #include <linux/timer.h> | |
72 | #include <linux/interrupt.h> | |
73 | #include <linux/in.h> | |
74 | #include <linux/delay.h> | |
64f93036 AC |
75 | #include <linux/io.h> |
76 | #include <linux/bitops.h> | |
15700039 | 77 | #include <linux/pci.h> |
cfb739b4 | 78 | #include <asm/system.h> |
cfb739b4 GKH |
79 | |
80 | #include <linux/mii.h> | |
81 | #include <linux/netdevice.h> | |
82 | #include <linux/etherdevice.h> | |
83 | #include <linux/skbuff.h> | |
84 | #include <linux/if_arp.h> | |
85 | #include <linux/ioport.h> | |
86 | ||
87 | #include "et1310_phy.h" | |
cfb739b4 | 88 | #include "et1310_tx.h" |
cfb739b4 | 89 | #include "et131x_adapter.h" |
69ea5fcb | 90 | #include "et131x.h" |
cfb739b4 | 91 | |
cfb739b4 GKH |
92 | struct net_device_stats *et131x_stats(struct net_device *netdev); |
93 | int et131x_open(struct net_device *netdev); | |
94 | int et131x_close(struct net_device *netdev); | |
95 | int et131x_ioctl(struct net_device *netdev, struct ifreq *reqbuf, int cmd); | |
96 | void et131x_multicast(struct net_device *netdev); | |
97 | int et131x_tx(struct sk_buff *skb, struct net_device *netdev); | |
98 | void et131x_tx_timeout(struct net_device *netdev); | |
99 | int et131x_change_mtu(struct net_device *netdev, int new_mtu); | |
100 | int et131x_set_mac_addr(struct net_device *netdev, void *new_mac); | |
101 | void et131x_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp); | |
102 | void et131x_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid); | |
103 | void et131x_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid); | |
104 | ||
fa5a602a AB |
105 | static const struct net_device_ops et131x_netdev_ops = { |
106 | .ndo_open = et131x_open, | |
107 | .ndo_stop = et131x_close, | |
108 | .ndo_start_xmit = et131x_tx, | |
109 | .ndo_set_multicast_list = et131x_multicast, | |
110 | .ndo_tx_timeout = et131x_tx_timeout, | |
111 | .ndo_change_mtu = et131x_change_mtu, | |
112 | .ndo_set_mac_address = et131x_set_mac_addr, | |
113 | .ndo_validate_addr = eth_validate_addr, | |
114 | .ndo_get_stats = et131x_stats, | |
115 | .ndo_do_ioctl = et131x_ioctl, | |
116 | }; | |
117 | ||
cfb739b4 GKH |
118 | /** |
119 | * et131x_device_alloc | |
120 | * | |
121 | * Returns pointer to the allocated and initialized net_device struct for | |
122 | * this device. | |
123 | * | |
124 | * Create instances of net_device and wl_private for the new adapter and | |
125 | * register the device's entry points in the net_device structure. | |
126 | */ | |
127 | struct net_device *et131x_device_alloc(void) | |
128 | { | |
129 | struct net_device *netdev; | |
130 | ||
cfb739b4 GKH |
131 | /* Alloc net_device and adapter structs */ |
132 | netdev = alloc_etherdev(sizeof(struct et131x_adapter)); | |
133 | ||
134 | if (netdev == NULL) { | |
15700039 | 135 | printk(KERN_ERR "et131x: Alloc of net_device struct failed\n"); |
cfb739b4 GKH |
136 | return NULL; |
137 | } | |
138 | ||
139 | /* Setup the function registration table (and other data) for a | |
140 | * net_device | |
141 | */ | |
64f93036 AC |
142 | /* netdev->init = &et131x_init; */ |
143 | /* netdev->set_config = &et131x_config; */ | |
cfb739b4 | 144 | netdev->watchdog_timeo = ET131X_TX_TIMEOUT; |
fa5a602a | 145 | netdev->netdev_ops = &et131x_netdev_ops; |
cfb739b4 | 146 | |
64f93036 | 147 | /* netdev->ethtool_ops = &et131x_ethtool_ops; */ |
cfb739b4 | 148 | |
64f93036 AC |
149 | /* Poll? */ |
150 | /* netdev->poll = &et131x_poll; */ | |
151 | /* netdev->poll_controller = &et131x_poll_controller; */ | |
cfb739b4 GKH |
152 | return netdev; |
153 | } | |
154 | ||
155 | /** | |
156 | * et131x_stats - Return the current device statistics. | |
157 | * @netdev: device whose stats are being queried | |
158 | * | |
159 | * Returns 0 on success, errno on failure (as defined in errno.h) | |
160 | */ | |
161 | struct net_device_stats *et131x_stats(struct net_device *netdev) | |
162 | { | |
163 | struct et131x_adapter *adapter = netdev_priv(netdev); | |
164 | struct net_device_stats *stats = &adapter->net_stats; | |
165 | CE_STATS_t *devstat = &adapter->Stats; | |
166 | ||
cfb739b4 GKH |
167 | stats->rx_packets = devstat->ipackets; |
168 | stats->tx_packets = devstat->opackets; | |
169 | stats->rx_errors = devstat->length_err + devstat->alignment_err + | |
170 | devstat->crc_err + devstat->code_violations + devstat->other_errors; | |
171 | stats->tx_errors = devstat->max_pkt_error; | |
172 | stats->multicast = devstat->multircv; | |
173 | stats->collisions = devstat->collisions; | |
174 | ||
175 | stats->rx_length_errors = devstat->length_err; | |
176 | stats->rx_over_errors = devstat->rx_ov_flow; | |
177 | stats->rx_crc_errors = devstat->crc_err; | |
178 | ||
64f93036 AC |
179 | /* NOTE: These stats don't have corresponding values in CE_STATS, |
180 | * so we're going to have to update these directly from within the | |
181 | * TX/RX code | |
182 | */ | |
183 | /* stats->rx_bytes = 20; devstat->; */ | |
184 | /* stats->tx_bytes = 20; devstat->; */ | |
185 | /* stats->rx_dropped = devstat->; */ | |
186 | /* stats->tx_dropped = devstat->; */ | |
187 | ||
188 | /* NOTE: Not used, can't find analogous statistics */ | |
189 | /* stats->rx_frame_errors = devstat->; */ | |
190 | /* stats->rx_fifo_errors = devstat->; */ | |
191 | /* stats->rx_missed_errors = devstat->; */ | |
192 | ||
193 | /* stats->tx_aborted_errors = devstat->; */ | |
194 | /* stats->tx_carrier_errors = devstat->; */ | |
195 | /* stats->tx_fifo_errors = devstat->; */ | |
196 | /* stats->tx_heartbeat_errors = devstat->; */ | |
197 | /* stats->tx_window_errors = devstat->; */ | |
cfb739b4 GKH |
198 | return stats; |
199 | } | |
200 | ||
201 | /** | |
202 | * et131x_open - Open the device for use. | |
203 | * @netdev: device to be opened | |
204 | * | |
205 | * Returns 0 on success, errno on failure (as defined in errno.h) | |
206 | */ | |
207 | int et131x_open(struct net_device *netdev) | |
208 | { | |
209 | int result = 0; | |
210 | struct et131x_adapter *adapter = netdev_priv(netdev); | |
211 | ||
cfb739b4 GKH |
212 | /* Start the timer to track NIC errors */ |
213 | add_timer(&adapter->ErrorTimer); | |
214 | ||
15700039 AC |
215 | /* Register our IRQ */ |
216 | result = request_irq(netdev->irq, et131x_isr, IRQF_SHARED, | |
217 | netdev->name, netdev); | |
cfb739b4 | 218 | if (result) { |
15700039 AC |
219 | dev_err(&adapter->pdev->dev, "c ould not register IRQ %d\n", |
220 | netdev->irq); | |
cfb739b4 GKH |
221 | return result; |
222 | } | |
223 | ||
224 | /* Enable the Tx and Rx DMA engines (if not already enabled) */ | |
225 | et131x_rx_dma_enable(adapter); | |
226 | et131x_tx_dma_enable(adapter); | |
227 | ||
228 | /* Enable device interrupts */ | |
229 | et131x_enable_interrupts(adapter); | |
230 | ||
f6b35d66 | 231 | adapter->Flags |= fMP_ADAPTER_INTERRUPT_IN_USE; |
cfb739b4 GKH |
232 | |
233 | /* We're ready to move some data, so start the queue */ | |
234 | netif_start_queue(netdev); | |
cfb739b4 GKH |
235 | return result; |
236 | } | |
237 | ||
238 | /** | |
239 | * et131x_close - Close the device | |
240 | * @netdev: device to be closed | |
241 | * | |
242 | * Returns 0 on success, errno on failure (as defined in errno.h) | |
243 | */ | |
244 | int et131x_close(struct net_device *netdev) | |
245 | { | |
246 | struct et131x_adapter *adapter = netdev_priv(netdev); | |
247 | ||
cfb739b4 GKH |
248 | /* First thing is to stop the queue */ |
249 | netif_stop_queue(netdev); | |
250 | ||
251 | /* Stop the Tx and Rx DMA engines */ | |
252 | et131x_rx_dma_disable(adapter); | |
253 | et131x_tx_dma_disable(adapter); | |
254 | ||
255 | /* Disable device interrupts */ | |
256 | et131x_disable_interrupts(adapter); | |
257 | ||
258 | /* Deregistering ISR */ | |
f6b35d66 | 259 | adapter->Flags &= ~fMP_ADAPTER_INTERRUPT_IN_USE; |
cfb739b4 GKH |
260 | free_irq(netdev->irq, netdev); |
261 | ||
262 | /* Stop the error timer */ | |
263 | del_timer_sync(&adapter->ErrorTimer); | |
cfb739b4 GKH |
264 | return 0; |
265 | } | |
266 | ||
267 | /** | |
268 | * et131x_ioctl_mii - The function which handles MII IOCTLs | |
269 | * @netdev: device on which the query is being made | |
270 | * @reqbuf: the request-specific data buffer | |
271 | * @cmd: the command request code | |
272 | * | |
273 | * Returns 0 on success, errno on failure (as defined in errno.h) | |
274 | */ | |
275 | int et131x_ioctl_mii(struct net_device *netdev, struct ifreq *reqbuf, int cmd) | |
276 | { | |
277 | int status = 0; | |
25ad00bb | 278 | struct et131x_adapter *etdev = netdev_priv(netdev); |
cfb739b4 GKH |
279 | struct mii_ioctl_data *data = if_mii(reqbuf); |
280 | ||
cfb739b4 GKH |
281 | switch (cmd) { |
282 | case SIOCGMIIPHY: | |
25ad00bb | 283 | data->phy_id = etdev->Stats.xcvr_addr; |
cfb739b4 GKH |
284 | break; |
285 | ||
286 | case SIOCGMIIREG: | |
15700039 | 287 | if (!capable(CAP_NET_ADMIN)) |
cfb739b4 | 288 | status = -EPERM; |
15700039 | 289 | else |
25ad00bb | 290 | status = MiRead(etdev, |
cfb739b4 | 291 | data->reg_num, &data->val_out); |
cfb739b4 GKH |
292 | break; |
293 | ||
294 | case SIOCSMIIREG: | |
15700039 | 295 | if (!capable(CAP_NET_ADMIN)) |
cfb739b4 | 296 | status = -EPERM; |
15700039 | 297 | else |
25ad00bb | 298 | status = MiWrite(etdev, data->reg_num, |
cfb739b4 | 299 | data->val_in); |
cfb739b4 GKH |
300 | break; |
301 | ||
302 | default: | |
303 | status = -EOPNOTSUPP; | |
304 | } | |
cfb739b4 GKH |
305 | return status; |
306 | } | |
307 | ||
308 | /** | |
309 | * et131x_ioctl - The I/O Control handler for the driver | |
310 | * @netdev: device on which the control request is being made | |
311 | * @reqbuf: a pointer to the IOCTL request buffer | |
312 | * @cmd: the IOCTL command code | |
313 | * | |
314 | * Returns 0 on success, errno on failure (as defined in errno.h) | |
315 | */ | |
316 | int et131x_ioctl(struct net_device *netdev, struct ifreq *reqbuf, int cmd) | |
317 | { | |
318 | int status = 0; | |
319 | ||
cfb739b4 GKH |
320 | switch (cmd) { |
321 | case SIOCGMIIPHY: | |
322 | case SIOCGMIIREG: | |
323 | case SIOCSMIIREG: | |
324 | status = et131x_ioctl_mii(netdev, reqbuf, cmd); | |
325 | break; | |
326 | ||
327 | default: | |
cfb739b4 GKH |
328 | status = -EOPNOTSUPP; |
329 | } | |
cfb739b4 GKH |
330 | return status; |
331 | } | |
332 | ||
333 | /** | |
334 | * et131x_set_packet_filter - Configures the Rx Packet filtering on the device | |
335 | * @adapter: pointer to our private adapter structure | |
336 | * | |
b186f331 AC |
337 | * FIXME: lot of dups with MAC code |
338 | * | |
cfb739b4 GKH |
339 | * Returns 0 on success, errno on failure |
340 | */ | |
341 | int et131x_set_packet_filter(struct et131x_adapter *adapter) | |
342 | { | |
343 | int status = 0; | |
344 | uint32_t filter = adapter->PacketFilter; | |
bd03d0d5 | 345 | u32 ctrl; |
b186f331 | 346 | u32 pf_ctrl; |
cfb739b4 | 347 | |
bd03d0d5 | 348 | ctrl = readl(&adapter->regs->rxmac.ctrl); |
b186f331 | 349 | pf_ctrl = readl(&adapter->regs->rxmac.pf_ctrl); |
cfb739b4 GKH |
350 | |
351 | /* Default to disabled packet filtering. Enable it in the individual | |
352 | * case statements that require the device to filter something | |
353 | */ | |
bd03d0d5 | 354 | ctrl |= 0x04; |
cfb739b4 GKH |
355 | |
356 | /* Set us to be in promiscuous mode so we receive everything, this | |
357 | * is also true when we get a packet filter of 0 | |
358 | */ | |
b186f331 AC |
359 | if ((filter & ET131X_PACKET_TYPE_PROMISCUOUS) || filter == 0) |
360 | pf_ctrl &= ~7; /* Clear filter bits */ | |
361 | else { | |
cfb739b4 GKH |
362 | /* |
363 | * Set us up with Multicast packet filtering. Three cases are | |
364 | * possible - (1) we have a multi-cast list, (2) we receive ALL | |
365 | * multicast entries or (3) we receive none. | |
366 | */ | |
b186f331 AC |
367 | if (filter & ET131X_PACKET_TYPE_ALL_MULTICAST) |
368 | pf_ctrl &= ~2; /* Multicast filter bit */ | |
369 | else { | |
cfb739b4 | 370 | SetupDeviceForMulticast(adapter); |
b186f331 | 371 | pf_ctrl |= 2; |
bd03d0d5 | 372 | ctrl &= ~0x04; |
cfb739b4 GKH |
373 | } |
374 | ||
375 | /* Set us up with Unicast packet filtering */ | |
376 | if (filter & ET131X_PACKET_TYPE_DIRECTED) { | |
cfb739b4 | 377 | SetupDeviceForUnicast(adapter); |
b186f331 | 378 | pf_ctrl |= 4; |
bd03d0d5 | 379 | ctrl &= ~0x04; |
cfb739b4 GKH |
380 | } |
381 | ||
382 | /* Set us up with Broadcast packet filtering */ | |
383 | if (filter & ET131X_PACKET_TYPE_BROADCAST) { | |
b186f331 | 384 | pf_ctrl |= 1; /* Broadcast filter bit */ |
bd03d0d5 | 385 | ctrl &= ~0x04; |
b186f331 AC |
386 | } else |
387 | pf_ctrl &= ~1; | |
cfb739b4 GKH |
388 | |
389 | /* Setup the receive mac configuration registers - Packet | |
390 | * Filter control + the enable / disable for packet filter | |
391 | * in the control reg. | |
392 | */ | |
b186f331 | 393 | writel(pf_ctrl, &adapter->regs->rxmac.pf_ctrl); |
bd03d0d5 | 394 | writel(ctrl, &adapter->regs->rxmac.ctrl); |
cfb739b4 | 395 | } |
cfb739b4 GKH |
396 | return status; |
397 | } | |
398 | ||
399 | /** | |
400 | * et131x_multicast - The handler to configure multicasting on the interface | |
401 | * @netdev: a pointer to a net_device struct representing the device | |
402 | */ | |
403 | void et131x_multicast(struct net_device *netdev) | |
404 | { | |
405 | struct et131x_adapter *adapter = netdev_priv(netdev); | |
406 | uint32_t PacketFilter = 0; | |
37628606 | 407 | unsigned long flags; |
22bedad3 | 408 | struct netdev_hw_addr *ha; |
d5907942 | 409 | int i; |
cfb739b4 | 410 | |
37628606 | 411 | spin_lock_irqsave(&adapter->Lock, flags); |
cfb739b4 GKH |
412 | |
413 | /* Before we modify the platform-independent filter flags, store them | |
414 | * locally. This allows us to determine if anything's changed and if | |
415 | * we even need to bother the hardware | |
416 | */ | |
417 | PacketFilter = adapter->PacketFilter; | |
418 | ||
419 | /* Clear the 'multicast' flag locally; becuase we only have a single | |
420 | * flag to check multicast, and multiple multicast addresses can be | |
421 | * set, this is the easiest way to determine if more than one | |
422 | * multicast address is being set. | |
423 | */ | |
424 | PacketFilter &= ~ET131X_PACKET_TYPE_MULTICAST; | |
425 | ||
426 | /* Check the net_device flags and set the device independent flags | |
427 | * accordingly | |
428 | */ | |
cfb739b4 GKH |
429 | |
430 | if (netdev->flags & IFF_PROMISC) { | |
cfb739b4 GKH |
431 | adapter->PacketFilter |= ET131X_PACKET_TYPE_PROMISCUOUS; |
432 | } else { | |
cfb739b4 GKH |
433 | adapter->PacketFilter &= ~ET131X_PACKET_TYPE_PROMISCUOUS; |
434 | } | |
435 | ||
436 | if (netdev->flags & IFF_ALLMULTI) { | |
cfb739b4 GKH |
437 | adapter->PacketFilter |= ET131X_PACKET_TYPE_ALL_MULTICAST; |
438 | } | |
439 | ||
4cd24eaf | 440 | if (netdev_mc_count(netdev) > NIC_MAX_MCAST_LIST) { |
cfb739b4 GKH |
441 | adapter->PacketFilter |= ET131X_PACKET_TYPE_ALL_MULTICAST; |
442 | } | |
443 | ||
4cd24eaf | 444 | if (netdev_mc_count(netdev) < 1) { |
cfb739b4 GKH |
445 | adapter->PacketFilter &= ~ET131X_PACKET_TYPE_ALL_MULTICAST; |
446 | adapter->PacketFilter &= ~ET131X_PACKET_TYPE_MULTICAST; | |
447 | } else { | |
cfb739b4 GKH |
448 | adapter->PacketFilter |= ET131X_PACKET_TYPE_MULTICAST; |
449 | } | |
450 | ||
451 | /* Set values in the private adapter struct */ | |
d5907942 | 452 | i = 0; |
22bedad3 | 453 | netdev_for_each_mc_addr(ha, netdev) { |
d5907942 JP |
454 | if (i == NIC_MAX_MCAST_LIST) |
455 | break; | |
22bedad3 | 456 | memcpy(adapter->MCList[i++], ha->addr, ETH_ALEN); |
cfb739b4 | 457 | } |
d5907942 | 458 | adapter->MCAddressCount = i; |
cfb739b4 GKH |
459 | |
460 | /* Are the new flags different from the previous ones? If not, then no | |
461 | * action is required | |
462 | * | |
463 | * NOTE - This block will always update the MCList with the hardware, | |
464 | * even if the addresses aren't the same. | |
465 | */ | |
466 | if (PacketFilter != adapter->PacketFilter) { | |
467 | /* Call the device's filter function */ | |
cfb739b4 | 468 | et131x_set_packet_filter(adapter); |
cfb739b4 | 469 | } |
37628606 | 470 | spin_unlock_irqrestore(&adapter->Lock, flags); |
cfb739b4 GKH |
471 | } |
472 | ||
473 | /** | |
474 | * et131x_tx - The handler to tx a packet on the device | |
475 | * @skb: data to be Tx'd | |
476 | * @netdev: device on which data is to be Tx'd | |
477 | * | |
478 | * Returns 0 on success, errno on failure (as defined in errno.h) | |
479 | */ | |
480 | int et131x_tx(struct sk_buff *skb, struct net_device *netdev) | |
481 | { | |
482 | int status = 0; | |
483 | ||
cfb739b4 GKH |
484 | /* Save the timestamp for the TX timeout watchdog */ |
485 | netdev->trans_start = jiffies; | |
486 | ||
487 | /* Call the device-specific data Tx routine */ | |
488 | status = et131x_send_packets(skb, netdev); | |
489 | ||
490 | /* Check status and manage the netif queue if necessary */ | |
491 | if (status != 0) { | |
492 | if (status == -ENOMEM) { | |
cfb739b4 GKH |
493 | /* Put the queue to sleep until resources are |
494 | * available | |
495 | */ | |
496 | netif_stop_queue(netdev); | |
5b548140 | 497 | status = NETDEV_TX_BUSY; |
cfb739b4 | 498 | } else { |
5b548140 | 499 | status = NETDEV_TX_OK; |
cfb739b4 GKH |
500 | } |
501 | } | |
cfb739b4 GKH |
502 | return status; |
503 | } | |
504 | ||
505 | /** | |
506 | * et131x_tx_timeout - Timeout handler | |
507 | * @netdev: a pointer to a net_device struct representing the device | |
508 | * | |
509 | * The handler called when a Tx request times out. The timeout period is | |
510 | * specified by the 'tx_timeo" element in the net_device structure (see | |
511 | * et131x_alloc_device() to see how this value is set). | |
512 | */ | |
513 | void et131x_tx_timeout(struct net_device *netdev) | |
514 | { | |
25ad00bb | 515 | struct et131x_adapter *etdev = netdev_priv(netdev); |
b711b2e0 | 516 | struct tcb *tcb; |
37628606 | 517 | unsigned long flags; |
cfb739b4 | 518 | |
cfb739b4 | 519 | /* Just skip this part if the adapter is doing link detection */ |
15700039 | 520 | if (etdev->Flags & fMP_ADAPTER_LINK_DETECTION) |
cfb739b4 | 521 | return; |
cfb739b4 GKH |
522 | |
523 | /* Any nonrecoverable hardware error? | |
524 | * Checks adapter->flags for any failure in phy reading | |
525 | */ | |
15700039 | 526 | if (etdev->Flags & fMP_ADAPTER_NON_RECOVER_ERROR) |
cfb739b4 | 527 | return; |
cfb739b4 GKH |
528 | |
529 | /* Hardware failure? */ | |
f6b35d66 | 530 | if (etdev->Flags & fMP_ADAPTER_HARDWARE_ERROR) { |
15700039 | 531 | dev_err(&etdev->pdev->dev, "hardware error - reset\n"); |
cfb739b4 GKH |
532 | return; |
533 | } | |
534 | ||
535 | /* Is send stuck? */ | |
37628606 | 536 | spin_lock_irqsave(&etdev->TCBSendQLock, flags); |
cfb739b4 | 537 | |
c78732ad | 538 | tcb = etdev->tx_ring.send_head; |
cfb739b4 | 539 | |
b711b2e0 | 540 | if (tcb != NULL) { |
c78732ad | 541 | tcb->count++; |
cfb739b4 | 542 | |
c78732ad | 543 | if (tcb->count > NIC_SEND_HANG_THRESHOLD) { |
25ad00bb | 544 | spin_unlock_irqrestore(&etdev->TCBSendQLock, |
37628606 | 545 | flags); |
cfb739b4 | 546 | |
15700039 | 547 | dev_warn(&etdev->pdev->dev, |
b711b2e0 | 548 | "Send stuck - reset. tcb->WrIndex %x, Flags 0x%08x\n", |
c78732ad AC |
549 | tcb->index, |
550 | tcb->flags); | |
cfb739b4 | 551 | |
cfb739b4 GKH |
552 | et131x_close(netdev); |
553 | et131x_open(netdev); | |
554 | ||
555 | return; | |
556 | } | |
557 | } | |
558 | ||
37628606 | 559 | spin_unlock_irqrestore(&etdev->TCBSendQLock, flags); |
cfb739b4 GKH |
560 | } |
561 | ||
562 | /** | |
563 | * et131x_change_mtu - The handler called to change the MTU for the device | |
564 | * @netdev: device whose MTU is to be changed | |
565 | * @new_mtu: the desired MTU | |
566 | * | |
567 | * Returns 0 on success, errno on failure (as defined in errno.h) | |
568 | */ | |
569 | int et131x_change_mtu(struct net_device *netdev, int new_mtu) | |
570 | { | |
571 | int result = 0; | |
572 | struct et131x_adapter *adapter = netdev_priv(netdev); | |
573 | ||
cfb739b4 | 574 | /* Make sure the requested MTU is valid */ |
15700039 | 575 | if (new_mtu < 64 || new_mtu > 9216) |
cfb739b4 | 576 | return -EINVAL; |
cfb739b4 GKH |
577 | |
578 | /* Stop the netif queue */ | |
579 | netif_stop_queue(netdev); | |
580 | ||
581 | /* Stop the Tx and Rx DMA engines */ | |
582 | et131x_rx_dma_disable(adapter); | |
583 | et131x_tx_dma_disable(adapter); | |
584 | ||
585 | /* Disable device interrupts */ | |
586 | et131x_disable_interrupts(adapter); | |
587 | et131x_handle_send_interrupt(adapter); | |
588 | et131x_handle_recv_interrupt(adapter); | |
589 | ||
590 | /* Set the new MTU */ | |
591 | netdev->mtu = new_mtu; | |
592 | ||
593 | /* Free Rx DMA memory */ | |
594 | et131x_adapter_memory_free(adapter); | |
595 | ||
596 | /* Set the config parameter for Jumbo Packet support */ | |
597 | adapter->RegistryJumboPacket = new_mtu + 14; | |
598 | et131x_soft_reset(adapter); | |
599 | ||
600 | /* Alloc and init Rx DMA memory */ | |
601 | result = et131x_adapter_memory_alloc(adapter); | |
602 | if (result != 0) { | |
15700039 | 603 | dev_warn(&adapter->pdev->dev, |
64f93036 | 604 | "Change MTU failed; couldn't re-alloc DMA memory\n"); |
cfb739b4 GKH |
605 | return result; |
606 | } | |
607 | ||
608 | et131x_init_send(adapter); | |
609 | ||
c431e3c0 | 610 | et131x_hwaddr_init(adapter); |
cfb739b4 GKH |
611 | memcpy(netdev->dev_addr, adapter->CurrentAddress, ETH_ALEN); |
612 | ||
613 | /* Init the device with the new settings */ | |
614 | et131x_adapter_setup(adapter); | |
615 | ||
616 | /* Enable interrupts */ | |
f6b35d66 | 617 | if (adapter->Flags & fMP_ADAPTER_INTERRUPT_IN_USE) |
cfb739b4 | 618 | et131x_enable_interrupts(adapter); |
cfb739b4 GKH |
619 | |
620 | /* Restart the Tx and Rx DMA engines */ | |
621 | et131x_rx_dma_enable(adapter); | |
622 | et131x_tx_dma_enable(adapter); | |
623 | ||
624 | /* Restart the netif queue */ | |
625 | netif_wake_queue(netdev); | |
cfb739b4 GKH |
626 | return result; |
627 | } | |
628 | ||
629 | /** | |
630 | * et131x_set_mac_addr - handler to change the MAC address for the device | |
631 | * @netdev: device whose MAC is to be changed | |
632 | * @new_mac: the desired MAC address | |
633 | * | |
634 | * Returns 0 on success, errno on failure (as defined in errno.h) | |
635 | * | |
636 | * IMPLEMENTED BY : blux http://berndlux.de 22.01.2007 21:14 | |
637 | */ | |
638 | int et131x_set_mac_addr(struct net_device *netdev, void *new_mac) | |
639 | { | |
640 | int result = 0; | |
641 | struct et131x_adapter *adapter = netdev_priv(netdev); | |
642 | struct sockaddr *address = new_mac; | |
643 | ||
64f93036 | 644 | /* begin blux */ |
cfb739b4 | 645 | |
15700039 | 646 | if (adapter == NULL) |
cfb739b4 | 647 | return -ENODEV; |
cfb739b4 GKH |
648 | |
649 | /* Make sure the requested MAC is valid */ | |
15700039 | 650 | if (!is_valid_ether_addr(address->sa_data)) |
cfb739b4 | 651 | return -EINVAL; |
cfb739b4 GKH |
652 | |
653 | /* Stop the netif queue */ | |
654 | netif_stop_queue(netdev); | |
655 | ||
656 | /* Stop the Tx and Rx DMA engines */ | |
657 | et131x_rx_dma_disable(adapter); | |
658 | et131x_tx_dma_disable(adapter); | |
659 | ||
660 | /* Disable device interrupts */ | |
661 | et131x_disable_interrupts(adapter); | |
662 | et131x_handle_send_interrupt(adapter); | |
663 | et131x_handle_recv_interrupt(adapter); | |
664 | ||
665 | /* Set the new MAC */ | |
64f93036 AC |
666 | /* netdev->set_mac_address = &new_mac; */ |
667 | /* netdev->mtu = new_mtu; */ | |
cfb739b4 GKH |
668 | |
669 | memcpy(netdev->dev_addr, address->sa_data, netdev->addr_len); | |
670 | ||
28a23334 HS |
671 | printk(KERN_INFO "%s: Setting MAC address to %pM\n", |
672 | netdev->name, netdev->dev_addr); | |
cfb739b4 GKH |
673 | |
674 | /* Free Rx DMA memory */ | |
675 | et131x_adapter_memory_free(adapter); | |
676 | ||
677 | /* Set the config parameter for Jumbo Packet support */ | |
64f93036 AC |
678 | /* adapter->RegistryJumboPacket = new_mtu + 14; */ |
679 | /* blux: not needet here, we'll change the MAC */ | |
cfb739b4 GKH |
680 | |
681 | et131x_soft_reset(adapter); | |
682 | ||
683 | /* Alloc and init Rx DMA memory */ | |
684 | result = et131x_adapter_memory_alloc(adapter); | |
685 | if (result != 0) { | |
15700039 | 686 | dev_err(&adapter->pdev->dev, |
64f93036 | 687 | "Change MAC failed; couldn't re-alloc DMA memory\n"); |
cfb739b4 GKH |
688 | return result; |
689 | } | |
690 | ||
691 | et131x_init_send(adapter); | |
692 | ||
c431e3c0 | 693 | et131x_hwaddr_init(adapter); |
cfb739b4 GKH |
694 | |
695 | /* Init the device with the new settings */ | |
696 | et131x_adapter_setup(adapter); | |
697 | ||
698 | /* Enable interrupts */ | |
f6b35d66 | 699 | if (adapter->Flags & fMP_ADAPTER_INTERRUPT_IN_USE) |
cfb739b4 | 700 | et131x_enable_interrupts(adapter); |
cfb739b4 GKH |
701 | |
702 | /* Restart the Tx and Rx DMA engines */ | |
703 | et131x_rx_dma_enable(adapter); | |
704 | et131x_tx_dma_enable(adapter); | |
705 | ||
706 | /* Restart the netif queue */ | |
707 | netif_wake_queue(netdev); | |
cfb739b4 GKH |
708 | return result; |
709 | } |