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