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; |
22bedad3 | 407 | struct netdev_hw_addr *ha; |
d5907942 | 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 | ||
25985edc | 418 | /* Clear the 'multicast' flag locally; because we only have a single |
cfb739b4 GKH |
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 | 428 | |
f3fd4cd5 | 429 | if (netdev->flags & IFF_PROMISC) |
cfb739b4 | 430 | adapter->PacketFilter |= ET131X_PACKET_TYPE_PROMISCUOUS; |
f3fd4cd5 | 431 | else |
cfb739b4 | 432 | adapter->PacketFilter &= ~ET131X_PACKET_TYPE_PROMISCUOUS; |
cfb739b4 | 433 | |
f3fd4cd5 | 434 | if (netdev->flags & IFF_ALLMULTI) |
cfb739b4 | 435 | adapter->PacketFilter |= ET131X_PACKET_TYPE_ALL_MULTICAST; |
cfb739b4 | 436 | |
f3fd4cd5 | 437 | if (netdev_mc_count(netdev) > NIC_MAX_MCAST_LIST) |
cfb739b4 | 438 | adapter->PacketFilter |= ET131X_PACKET_TYPE_ALL_MULTICAST; |
cfb739b4 | 439 | |
4cd24eaf | 440 | if (netdev_mc_count(netdev) < 1) { |
cfb739b4 GKH |
441 | adapter->PacketFilter &= ~ET131X_PACKET_TYPE_ALL_MULTICAST; |
442 | adapter->PacketFilter &= ~ET131X_PACKET_TYPE_MULTICAST; | |
f3fd4cd5 | 443 | } else |
cfb739b4 | 444 | adapter->PacketFilter |= ET131X_PACKET_TYPE_MULTICAST; |
cfb739b4 GKH |
445 | |
446 | /* Set values in the private adapter struct */ | |
d5907942 | 447 | i = 0; |
22bedad3 | 448 | netdev_for_each_mc_addr(ha, netdev) { |
d5907942 JP |
449 | if (i == NIC_MAX_MCAST_LIST) |
450 | break; | |
22bedad3 | 451 | memcpy(adapter->MCList[i++], ha->addr, ETH_ALEN); |
cfb739b4 | 452 | } |
d5907942 | 453 | adapter->MCAddressCount = i; |
cfb739b4 GKH |
454 | |
455 | /* Are the new flags different from the previous ones? If not, then no | |
456 | * action is required | |
457 | * | |
458 | * NOTE - This block will always update the MCList with the hardware, | |
459 | * even if the addresses aren't the same. | |
460 | */ | |
461 | if (PacketFilter != adapter->PacketFilter) { | |
462 | /* Call the device's filter function */ | |
cfb739b4 | 463 | et131x_set_packet_filter(adapter); |
cfb739b4 | 464 | } |
37628606 | 465 | spin_unlock_irqrestore(&adapter->Lock, flags); |
cfb739b4 GKH |
466 | } |
467 | ||
468 | /** | |
469 | * et131x_tx - The handler to tx a packet on the device | |
470 | * @skb: data to be Tx'd | |
471 | * @netdev: device on which data is to be Tx'd | |
472 | * | |
473 | * Returns 0 on success, errno on failure (as defined in errno.h) | |
474 | */ | |
475 | int et131x_tx(struct sk_buff *skb, struct net_device *netdev) | |
476 | { | |
477 | int status = 0; | |
478 | ||
cfb739b4 GKH |
479 | /* Save the timestamp for the TX timeout watchdog */ |
480 | netdev->trans_start = jiffies; | |
481 | ||
482 | /* Call the device-specific data Tx routine */ | |
483 | status = et131x_send_packets(skb, netdev); | |
484 | ||
485 | /* Check status and manage the netif queue if necessary */ | |
486 | if (status != 0) { | |
487 | if (status == -ENOMEM) { | |
cfb739b4 GKH |
488 | /* Put the queue to sleep until resources are |
489 | * available | |
490 | */ | |
491 | netif_stop_queue(netdev); | |
5b548140 | 492 | status = NETDEV_TX_BUSY; |
cfb739b4 | 493 | } else { |
5b548140 | 494 | status = NETDEV_TX_OK; |
cfb739b4 GKH |
495 | } |
496 | } | |
cfb739b4 GKH |
497 | return status; |
498 | } | |
499 | ||
500 | /** | |
501 | * et131x_tx_timeout - Timeout handler | |
502 | * @netdev: a pointer to a net_device struct representing the device | |
503 | * | |
504 | * The handler called when a Tx request times out. The timeout period is | |
505 | * specified by the 'tx_timeo" element in the net_device structure (see | |
506 | * et131x_alloc_device() to see how this value is set). | |
507 | */ | |
508 | void et131x_tx_timeout(struct net_device *netdev) | |
509 | { | |
25ad00bb | 510 | struct et131x_adapter *etdev = netdev_priv(netdev); |
b711b2e0 | 511 | struct tcb *tcb; |
37628606 | 512 | unsigned long flags; |
cfb739b4 | 513 | |
cfb739b4 | 514 | /* Just skip this part if the adapter is doing link detection */ |
15700039 | 515 | if (etdev->Flags & fMP_ADAPTER_LINK_DETECTION) |
cfb739b4 | 516 | return; |
cfb739b4 GKH |
517 | |
518 | /* Any nonrecoverable hardware error? | |
519 | * Checks adapter->flags for any failure in phy reading | |
520 | */ | |
15700039 | 521 | if (etdev->Flags & fMP_ADAPTER_NON_RECOVER_ERROR) |
cfb739b4 | 522 | return; |
cfb739b4 GKH |
523 | |
524 | /* Hardware failure? */ | |
f6b35d66 | 525 | if (etdev->Flags & fMP_ADAPTER_HARDWARE_ERROR) { |
15700039 | 526 | dev_err(&etdev->pdev->dev, "hardware error - reset\n"); |
cfb739b4 GKH |
527 | return; |
528 | } | |
529 | ||
530 | /* Is send stuck? */ | |
37628606 | 531 | spin_lock_irqsave(&etdev->TCBSendQLock, flags); |
cfb739b4 | 532 | |
c78732ad | 533 | tcb = etdev->tx_ring.send_head; |
cfb739b4 | 534 | |
b711b2e0 | 535 | if (tcb != NULL) { |
c78732ad | 536 | tcb->count++; |
cfb739b4 | 537 | |
c78732ad | 538 | if (tcb->count > NIC_SEND_HANG_THRESHOLD) { |
25ad00bb | 539 | spin_unlock_irqrestore(&etdev->TCBSendQLock, |
37628606 | 540 | flags); |
cfb739b4 | 541 | |
15700039 | 542 | dev_warn(&etdev->pdev->dev, |
b711b2e0 | 543 | "Send stuck - reset. tcb->WrIndex %x, Flags 0x%08x\n", |
c78732ad AC |
544 | tcb->index, |
545 | tcb->flags); | |
cfb739b4 | 546 | |
cfb739b4 GKH |
547 | et131x_close(netdev); |
548 | et131x_open(netdev); | |
549 | ||
550 | return; | |
551 | } | |
552 | } | |
553 | ||
37628606 | 554 | spin_unlock_irqrestore(&etdev->TCBSendQLock, flags); |
cfb739b4 GKH |
555 | } |
556 | ||
557 | /** | |
558 | * et131x_change_mtu - The handler called to change the MTU for the device | |
559 | * @netdev: device whose MTU is to be changed | |
560 | * @new_mtu: the desired MTU | |
561 | * | |
562 | * Returns 0 on success, errno on failure (as defined in errno.h) | |
563 | */ | |
564 | int et131x_change_mtu(struct net_device *netdev, int new_mtu) | |
565 | { | |
566 | int result = 0; | |
567 | struct et131x_adapter *adapter = netdev_priv(netdev); | |
568 | ||
cfb739b4 | 569 | /* Make sure the requested MTU is valid */ |
15700039 | 570 | if (new_mtu < 64 || new_mtu > 9216) |
cfb739b4 | 571 | return -EINVAL; |
cfb739b4 GKH |
572 | |
573 | /* Stop the netif queue */ | |
574 | netif_stop_queue(netdev); | |
575 | ||
576 | /* Stop the Tx and Rx DMA engines */ | |
577 | et131x_rx_dma_disable(adapter); | |
578 | et131x_tx_dma_disable(adapter); | |
579 | ||
580 | /* Disable device interrupts */ | |
581 | et131x_disable_interrupts(adapter); | |
582 | et131x_handle_send_interrupt(adapter); | |
583 | et131x_handle_recv_interrupt(adapter); | |
584 | ||
585 | /* Set the new MTU */ | |
586 | netdev->mtu = new_mtu; | |
587 | ||
588 | /* Free Rx DMA memory */ | |
589 | et131x_adapter_memory_free(adapter); | |
590 | ||
591 | /* Set the config parameter for Jumbo Packet support */ | |
592 | adapter->RegistryJumboPacket = new_mtu + 14; | |
593 | et131x_soft_reset(adapter); | |
594 | ||
595 | /* Alloc and init Rx DMA memory */ | |
596 | result = et131x_adapter_memory_alloc(adapter); | |
597 | if (result != 0) { | |
15700039 | 598 | dev_warn(&adapter->pdev->dev, |
64f93036 | 599 | "Change MTU failed; couldn't re-alloc DMA memory\n"); |
cfb739b4 GKH |
600 | return result; |
601 | } | |
602 | ||
603 | et131x_init_send(adapter); | |
604 | ||
c431e3c0 | 605 | et131x_hwaddr_init(adapter); |
072e9f60 | 606 | memcpy(netdev->dev_addr, adapter->addr, ETH_ALEN); |
cfb739b4 GKH |
607 | |
608 | /* Init the device with the new settings */ | |
609 | et131x_adapter_setup(adapter); | |
610 | ||
611 | /* Enable interrupts */ | |
f6b35d66 | 612 | if (adapter->Flags & fMP_ADAPTER_INTERRUPT_IN_USE) |
cfb739b4 | 613 | et131x_enable_interrupts(adapter); |
cfb739b4 GKH |
614 | |
615 | /* Restart the Tx and Rx DMA engines */ | |
616 | et131x_rx_dma_enable(adapter); | |
617 | et131x_tx_dma_enable(adapter); | |
618 | ||
619 | /* Restart the netif queue */ | |
620 | netif_wake_queue(netdev); | |
cfb739b4 GKH |
621 | return result; |
622 | } | |
623 | ||
624 | /** | |
625 | * et131x_set_mac_addr - handler to change the MAC address for the device | |
626 | * @netdev: device whose MAC is to be changed | |
627 | * @new_mac: the desired MAC address | |
628 | * | |
629 | * Returns 0 on success, errno on failure (as defined in errno.h) | |
630 | * | |
631 | * IMPLEMENTED BY : blux http://berndlux.de 22.01.2007 21:14 | |
632 | */ | |
633 | int et131x_set_mac_addr(struct net_device *netdev, void *new_mac) | |
634 | { | |
635 | int result = 0; | |
636 | struct et131x_adapter *adapter = netdev_priv(netdev); | |
637 | struct sockaddr *address = new_mac; | |
638 | ||
64f93036 | 639 | /* begin blux */ |
cfb739b4 | 640 | |
15700039 | 641 | if (adapter == NULL) |
cfb739b4 | 642 | return -ENODEV; |
cfb739b4 GKH |
643 | |
644 | /* Make sure the requested MAC is valid */ | |
15700039 | 645 | if (!is_valid_ether_addr(address->sa_data)) |
cfb739b4 | 646 | return -EINVAL; |
cfb739b4 GKH |
647 | |
648 | /* Stop the netif queue */ | |
649 | netif_stop_queue(netdev); | |
650 | ||
651 | /* Stop the Tx and Rx DMA engines */ | |
652 | et131x_rx_dma_disable(adapter); | |
653 | et131x_tx_dma_disable(adapter); | |
654 | ||
655 | /* Disable device interrupts */ | |
656 | et131x_disable_interrupts(adapter); | |
657 | et131x_handle_send_interrupt(adapter); | |
658 | et131x_handle_recv_interrupt(adapter); | |
659 | ||
660 | /* Set the new MAC */ | |
64f93036 AC |
661 | /* netdev->set_mac_address = &new_mac; */ |
662 | /* netdev->mtu = new_mtu; */ | |
cfb739b4 GKH |
663 | |
664 | memcpy(netdev->dev_addr, address->sa_data, netdev->addr_len); | |
665 | ||
28a23334 HS |
666 | printk(KERN_INFO "%s: Setting MAC address to %pM\n", |
667 | netdev->name, netdev->dev_addr); | |
cfb739b4 GKH |
668 | |
669 | /* Free Rx DMA memory */ | |
670 | et131x_adapter_memory_free(adapter); | |
671 | ||
672 | /* Set the config parameter for Jumbo Packet support */ | |
64f93036 AC |
673 | /* adapter->RegistryJumboPacket = new_mtu + 14; */ |
674 | /* blux: not needet here, we'll change the MAC */ | |
cfb739b4 GKH |
675 | |
676 | et131x_soft_reset(adapter); | |
677 | ||
678 | /* Alloc and init Rx DMA memory */ | |
679 | result = et131x_adapter_memory_alloc(adapter); | |
680 | if (result != 0) { | |
15700039 | 681 | dev_err(&adapter->pdev->dev, |
64f93036 | 682 | "Change MAC failed; couldn't re-alloc DMA memory\n"); |
cfb739b4 GKH |
683 | return result; |
684 | } | |
685 | ||
686 | et131x_init_send(adapter); | |
687 | ||
c431e3c0 | 688 | et131x_hwaddr_init(adapter); |
cfb739b4 GKH |
689 | |
690 | /* Init the device with the new settings */ | |
691 | et131x_adapter_setup(adapter); | |
692 | ||
693 | /* Enable interrupts */ | |
f6b35d66 | 694 | if (adapter->Flags & fMP_ADAPTER_INTERRUPT_IN_USE) |
cfb739b4 | 695 | et131x_enable_interrupts(adapter); |
cfb739b4 GKH |
696 | |
697 | /* Restart the Tx and Rx DMA engines */ | |
698 | et131x_rx_dma_enable(adapter); | |
699 | et131x_tx_dma_enable(adapter); | |
700 | ||
701 | /* Restart the netif queue */ | |
702 | netif_wake_queue(netdev); | |
cfb739b4 GKH |
703 | return result; |
704 | } |