Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
05d9c84d RB |
2 | * Copyright (C) 2000, 2005 MIPS Technologies, Inc. All rights reserved. |
3 | * Authors: Carsten Langgaard <carstenl@mips.com> | |
4 | * Maciej W. Rozycki <macro@mips.com> | |
5 | * Copyright (C) 2004 Ralf Baechle <ralf@linux-mips.org> | |
1da177e4 LT |
6 | * |
7 | * This program is free software; you can distribute it and/or modify it | |
8 | * under the terms of the GNU General Public License (Version 2) as | |
9 | * published by the Free Software Foundation. | |
10 | * | |
11 | * This program is distributed in the hope it will be useful, but WITHOUT | |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 | * for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License along | |
17 | * with this program; if not, write to the Free Software Foundation, Inc., | |
18 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
19 | * | |
1da177e4 LT |
20 | * SAA9730 ethernet driver. |
21 | * | |
22 | * Changes: | |
05d9c84d RB |
23 | * Angelo Dell'Aera <buffer@antifork.org> : Conversion to the new PCI API |
24 | * (pci_driver). | |
25 | * Conversion to spinlocks. | |
26 | * Error handling fixes. | |
1da177e4 LT |
27 | */ |
28 | ||
29 | #include <linux/init.h> | |
30 | #include <linux/netdevice.h> | |
31 | #include <linux/delay.h> | |
32 | #include <linux/etherdevice.h> | |
33 | #include <linux/module.h> | |
34 | #include <linux/skbuff.h> | |
35 | #include <linux/pci.h> | |
36 | #include <linux/spinlock.h> | |
05d9c84d | 37 | #include <linux/types.h> |
1da177e4 LT |
38 | |
39 | #include <asm/addrspace.h> | |
05d9c84d RB |
40 | #include <asm/io.h> |
41 | ||
1da177e4 LT |
42 | #include <asm/mips-boards/prom.h> |
43 | ||
44 | #include "saa9730.h" | |
45 | ||
46 | #ifdef LAN_SAA9730_DEBUG | |
47 | int lan_saa9730_debug = LAN_SAA9730_DEBUG; | |
48 | #else | |
49 | int lan_saa9730_debug; | |
50 | #endif | |
51 | ||
52 | #define DRV_MODULE_NAME "saa9730" | |
53 | ||
54 | static struct pci_device_id saa9730_pci_tbl[] = { | |
05d9c84d | 55 | { PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA9730, |
62ff0d0a | 56 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, |
1da177e4 LT |
57 | { 0, } |
58 | }; | |
59 | ||
60 | MODULE_DEVICE_TABLE(pci, saa9730_pci_tbl); | |
61 | ||
62 | /* Non-zero only if the current card is a PCI with BIOS-set IRQ. */ | |
63 | static unsigned int pci_irq_line; | |
64 | ||
1da177e4 LT |
65 | static void evm_saa9730_enable_lan_int(struct lan_saa9730_private *lp) |
66 | { | |
05d9c84d | 67 | outl(readl(&lp->evm_saa9730_regs->InterruptBlock1) | EVM_LAN_INT, |
1da177e4 | 68 | &lp->evm_saa9730_regs->InterruptBlock1); |
05d9c84d | 69 | outl(readl(&lp->evm_saa9730_regs->InterruptStatus1) | EVM_LAN_INT, |
1da177e4 | 70 | &lp->evm_saa9730_regs->InterruptStatus1); |
05d9c84d | 71 | outl(readl(&lp->evm_saa9730_regs->InterruptEnable1) | EVM_LAN_INT | |
1da177e4 LT |
72 | EVM_MASTER_EN, &lp->evm_saa9730_regs->InterruptEnable1); |
73 | } | |
05d9c84d | 74 | |
1da177e4 LT |
75 | static void evm_saa9730_disable_lan_int(struct lan_saa9730_private *lp) |
76 | { | |
05d9c84d | 77 | outl(readl(&lp->evm_saa9730_regs->InterruptBlock1) & ~EVM_LAN_INT, |
1da177e4 | 78 | &lp->evm_saa9730_regs->InterruptBlock1); |
05d9c84d | 79 | outl(readl(&lp->evm_saa9730_regs->InterruptEnable1) & ~EVM_LAN_INT, |
1da177e4 LT |
80 | &lp->evm_saa9730_regs->InterruptEnable1); |
81 | } | |
82 | ||
83 | static void evm_saa9730_clear_lan_int(struct lan_saa9730_private *lp) | |
84 | { | |
05d9c84d | 85 | outl(EVM_LAN_INT, &lp->evm_saa9730_regs->InterruptStatus1); |
1da177e4 LT |
86 | } |
87 | ||
88 | static void evm_saa9730_block_lan_int(struct lan_saa9730_private *lp) | |
89 | { | |
05d9c84d | 90 | outl(readl(&lp->evm_saa9730_regs->InterruptBlock1) & ~EVM_LAN_INT, |
1da177e4 LT |
91 | &lp->evm_saa9730_regs->InterruptBlock1); |
92 | } | |
93 | ||
94 | static void evm_saa9730_unblock_lan_int(struct lan_saa9730_private *lp) | |
95 | { | |
05d9c84d | 96 | outl(readl(&lp->evm_saa9730_regs->InterruptBlock1) | EVM_LAN_INT, |
1da177e4 LT |
97 | &lp->evm_saa9730_regs->InterruptBlock1); |
98 | } | |
99 | ||
05d9c84d | 100 | static void __attribute_used__ show_saa9730_regs(struct lan_saa9730_private *lp) |
1da177e4 LT |
101 | { |
102 | int i, j; | |
05d9c84d RB |
103 | printk("TxmBufferA = %p\n", lp->TxmBuffer[0][0]); |
104 | printk("TxmBufferB = %p\n", lp->TxmBuffer[1][0]); | |
105 | printk("RcvBufferA = %p\n", lp->RcvBuffer[0][0]); | |
106 | printk("RcvBufferB = %p\n", lp->RcvBuffer[1][0]); | |
1da177e4 LT |
107 | for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { |
108 | for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) { | |
109 | printk("TxmBuffer[%d][%d] = %x\n", i, j, | |
110 | le32_to_cpu(*(unsigned int *) | |
111 | lp->TxmBuffer[i][j])); | |
112 | } | |
113 | } | |
114 | for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { | |
115 | for (j = 0; j < LAN_SAA9730_RCV_Q_SIZE; j++) { | |
116 | printk("RcvBuffer[%d][%d] = %x\n", i, j, | |
117 | le32_to_cpu(*(unsigned int *) | |
118 | lp->RcvBuffer[i][j])); | |
119 | } | |
120 | } | |
121 | printk("lp->evm_saa9730_regs->InterruptBlock1 = %x\n", | |
05d9c84d | 122 | readl(&lp->evm_saa9730_regs->InterruptBlock1)); |
1da177e4 | 123 | printk("lp->evm_saa9730_regs->InterruptStatus1 = %x\n", |
05d9c84d | 124 | readl(&lp->evm_saa9730_regs->InterruptStatus1)); |
1da177e4 | 125 | printk("lp->evm_saa9730_regs->InterruptEnable1 = %x\n", |
05d9c84d | 126 | readl(&lp->evm_saa9730_regs->InterruptEnable1)); |
1da177e4 | 127 | printk("lp->lan_saa9730_regs->Ok2Use = %x\n", |
05d9c84d | 128 | readl(&lp->lan_saa9730_regs->Ok2Use)); |
1da177e4 LT |
129 | printk("lp->NextTxmBufferIndex = %x\n", lp->NextTxmBufferIndex); |
130 | printk("lp->NextTxmPacketIndex = %x\n", lp->NextTxmPacketIndex); | |
131 | printk("lp->PendingTxmBufferIndex = %x\n", | |
132 | lp->PendingTxmBufferIndex); | |
133 | printk("lp->PendingTxmPacketIndex = %x\n", | |
134 | lp->PendingTxmPacketIndex); | |
135 | printk("lp->lan_saa9730_regs->LanDmaCtl = %x\n", | |
05d9c84d | 136 | readl(&lp->lan_saa9730_regs->LanDmaCtl)); |
1da177e4 | 137 | printk("lp->lan_saa9730_regs->DmaStatus = %x\n", |
05d9c84d | 138 | readl(&lp->lan_saa9730_regs->DmaStatus)); |
1da177e4 | 139 | printk("lp->lan_saa9730_regs->CamCtl = %x\n", |
05d9c84d | 140 | readl(&lp->lan_saa9730_regs->CamCtl)); |
1da177e4 | 141 | printk("lp->lan_saa9730_regs->TxCtl = %x\n", |
05d9c84d | 142 | readl(&lp->lan_saa9730_regs->TxCtl)); |
1da177e4 | 143 | printk("lp->lan_saa9730_regs->TxStatus = %x\n", |
05d9c84d | 144 | readl(&lp->lan_saa9730_regs->TxStatus)); |
1da177e4 | 145 | printk("lp->lan_saa9730_regs->RxCtl = %x\n", |
05d9c84d | 146 | readl(&lp->lan_saa9730_regs->RxCtl)); |
1da177e4 | 147 | printk("lp->lan_saa9730_regs->RxStatus = %x\n", |
05d9c84d | 148 | readl(&lp->lan_saa9730_regs->RxStatus)); |
1da177e4 | 149 | for (i = 0; i < LAN_SAA9730_CAM_DWORDS; i++) { |
05d9c84d | 150 | outl(i, &lp->lan_saa9730_regs->CamAddress); |
1da177e4 | 151 | printk("lp->lan_saa9730_regs->CamData = %x\n", |
05d9c84d | 152 | readl(&lp->lan_saa9730_regs->CamData)); |
1da177e4 LT |
153 | } |
154 | printk("lp->stats.tx_packets = %lx\n", lp->stats.tx_packets); | |
155 | printk("lp->stats.tx_errors = %lx\n", lp->stats.tx_errors); | |
156 | printk("lp->stats.tx_aborted_errors = %lx\n", | |
157 | lp->stats.tx_aborted_errors); | |
158 | printk("lp->stats.tx_window_errors = %lx\n", | |
159 | lp->stats.tx_window_errors); | |
160 | printk("lp->stats.tx_carrier_errors = %lx\n", | |
161 | lp->stats.tx_carrier_errors); | |
162 | printk("lp->stats.tx_fifo_errors = %lx\n", | |
163 | lp->stats.tx_fifo_errors); | |
164 | printk("lp->stats.tx_heartbeat_errors = %lx\n", | |
165 | lp->stats.tx_heartbeat_errors); | |
166 | printk("lp->stats.collisions = %lx\n", lp->stats.collisions); | |
167 | ||
168 | printk("lp->stats.rx_packets = %lx\n", lp->stats.rx_packets); | |
169 | printk("lp->stats.rx_errors = %lx\n", lp->stats.rx_errors); | |
170 | printk("lp->stats.rx_dropped = %lx\n", lp->stats.rx_dropped); | |
171 | printk("lp->stats.rx_crc_errors = %lx\n", lp->stats.rx_crc_errors); | |
172 | printk("lp->stats.rx_frame_errors = %lx\n", | |
173 | lp->stats.rx_frame_errors); | |
174 | printk("lp->stats.rx_fifo_errors = %lx\n", | |
175 | lp->stats.rx_fifo_errors); | |
176 | printk("lp->stats.rx_length_errors = %lx\n", | |
177 | lp->stats.rx_length_errors); | |
178 | ||
179 | printk("lp->lan_saa9730_regs->DebugPCIMasterAddr = %x\n", | |
05d9c84d | 180 | readl(&lp->lan_saa9730_regs->DebugPCIMasterAddr)); |
1da177e4 | 181 | printk("lp->lan_saa9730_regs->DebugLanTxStateMachine = %x\n", |
05d9c84d | 182 | readl(&lp->lan_saa9730_regs->DebugLanTxStateMachine)); |
1da177e4 | 183 | printk("lp->lan_saa9730_regs->DebugLanRxStateMachine = %x\n", |
05d9c84d | 184 | readl(&lp->lan_saa9730_regs->DebugLanRxStateMachine)); |
1da177e4 | 185 | printk("lp->lan_saa9730_regs->DebugLanTxFifoPointers = %x\n", |
05d9c84d | 186 | readl(&lp->lan_saa9730_regs->DebugLanTxFifoPointers)); |
1da177e4 | 187 | printk("lp->lan_saa9730_regs->DebugLanRxFifoPointers = %x\n", |
05d9c84d | 188 | readl(&lp->lan_saa9730_regs->DebugLanRxFifoPointers)); |
1da177e4 | 189 | printk("lp->lan_saa9730_regs->DebugLanCtlStateMachine = %x\n", |
05d9c84d | 190 | readl(&lp->lan_saa9730_regs->DebugLanCtlStateMachine)); |
1da177e4 LT |
191 | } |
192 | ||
193 | static void lan_saa9730_buffer_init(struct lan_saa9730_private *lp) | |
194 | { | |
195 | int i, j; | |
196 | ||
197 | /* Init RX buffers */ | |
198 | for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { | |
199 | for (j = 0; j < LAN_SAA9730_RCV_Q_SIZE; j++) { | |
200 | *(unsigned int *) lp->RcvBuffer[i][j] = | |
201 | cpu_to_le32(RXSF_READY << | |
202 | RX_STAT_CTL_OWNER_SHF); | |
203 | } | |
204 | } | |
205 | ||
206 | /* Init TX buffers */ | |
207 | for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { | |
208 | for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) { | |
209 | *(unsigned int *) lp->TxmBuffer[i][j] = | |
210 | cpu_to_le32(TXSF_EMPTY << | |
211 | TX_STAT_CTL_OWNER_SHF); | |
212 | } | |
213 | } | |
214 | } | |
215 | ||
05d9c84d RB |
216 | static void lan_saa9730_free_buffers(struct pci_dev *pdev, |
217 | struct lan_saa9730_private *lp) | |
218 | { | |
219 | pci_free_consistent(pdev, lp->buffer_size, lp->buffer_start, | |
220 | lp->dma_addr); | |
221 | } | |
222 | ||
223 | static int lan_saa9730_allocate_buffers(struct pci_dev *pdev, | |
224 | struct lan_saa9730_private *lp) | |
1da177e4 | 225 | { |
1da177e4 | 226 | void *Pa; |
05d9c84d RB |
227 | unsigned int i, j, rxoffset, txoffset; |
228 | int ret; | |
229 | ||
230 | /* Initialize buffer space */ | |
231 | lp->DmaRcvPackets = LAN_SAA9730_RCV_Q_SIZE; | |
232 | lp->DmaTxmPackets = LAN_SAA9730_TXM_Q_SIZE; | |
233 | ||
234 | /* Initialize Rx Buffer Index */ | |
235 | lp->NextRcvPacketIndex = 0; | |
236 | lp->NextRcvBufferIndex = 0; | |
237 | ||
238 | /* Set current buffer index & next available packet index */ | |
239 | lp->NextTxmPacketIndex = 0; | |
240 | lp->NextTxmBufferIndex = 0; | |
241 | lp->PendingTxmPacketIndex = 0; | |
242 | lp->PendingTxmBufferIndex = 0; | |
1da177e4 | 243 | |
62ff0d0a RB |
244 | /* |
245 | * Allocate all RX and TX packets in one chunk. | |
1da177e4 LT |
246 | * The Rx and Tx packets must be PACKET_SIZE aligned. |
247 | */ | |
05d9c84d RB |
248 | lp->buffer_size = ((LAN_SAA9730_RCV_Q_SIZE + LAN_SAA9730_TXM_Q_SIZE) * |
249 | LAN_SAA9730_PACKET_SIZE * LAN_SAA9730_BUFFERS) + | |
250 | LAN_SAA9730_PACKET_SIZE; | |
251 | lp->buffer_start = pci_alloc_consistent(pdev, lp->buffer_size, | |
252 | &lp->dma_addr); | |
253 | if (!lp->buffer_start) { | |
254 | ret = -ENOMEM; | |
255 | goto out; | |
256 | } | |
1da177e4 | 257 | |
05d9c84d RB |
258 | Pa = (void *)ALIGN((unsigned long)lp->buffer_start, |
259 | LAN_SAA9730_PACKET_SIZE); | |
1da177e4 | 260 | |
05d9c84d | 261 | rxoffset = Pa - lp->buffer_start; |
1da177e4 LT |
262 | |
263 | /* Init RX buffers */ | |
264 | for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { | |
265 | for (j = 0; j < LAN_SAA9730_RCV_Q_SIZE; j++) { | |
266 | *(unsigned int *) Pa = | |
267 | cpu_to_le32(RXSF_READY << | |
268 | RX_STAT_CTL_OWNER_SHF); | |
05d9c84d RB |
269 | lp->RcvBuffer[i][j] = Pa; |
270 | Pa += LAN_SAA9730_PACKET_SIZE; | |
1da177e4 LT |
271 | } |
272 | } | |
273 | ||
05d9c84d RB |
274 | txoffset = Pa - lp->buffer_start; |
275 | ||
1da177e4 LT |
276 | /* Init TX buffers */ |
277 | for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { | |
278 | for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) { | |
279 | *(unsigned int *) Pa = | |
280 | cpu_to_le32(TXSF_EMPTY << | |
281 | TX_STAT_CTL_OWNER_SHF); | |
05d9c84d RB |
282 | lp->TxmBuffer[i][j] = Pa; |
283 | Pa += LAN_SAA9730_PACKET_SIZE; | |
1da177e4 LT |
284 | } |
285 | } | |
286 | ||
62ff0d0a RB |
287 | /* |
288 | * Set rx buffer A and rx buffer B to point to the first two buffer | |
1da177e4 LT |
289 | * spaces. |
290 | */ | |
05d9c84d | 291 | outl(lp->dma_addr + rxoffset, |
1da177e4 | 292 | &lp->lan_saa9730_regs->RxBuffA); |
05d9c84d RB |
293 | outl(lp->dma_addr + rxoffset + |
294 | LAN_SAA9730_PACKET_SIZE * LAN_SAA9730_RCV_Q_SIZE, | |
1da177e4 LT |
295 | &lp->lan_saa9730_regs->RxBuffB); |
296 | ||
62ff0d0a | 297 | /* |
1da177e4 | 298 | * Set txm_buf_a and txm_buf_b to point to the first two buffer |
62ff0d0a | 299 | * space |
1da177e4 | 300 | */ |
05d9c84d | 301 | outl(lp->dma_addr + txoffset, |
1da177e4 | 302 | &lp->lan_saa9730_regs->TxBuffA); |
05d9c84d RB |
303 | outl(lp->dma_addr + txoffset + |
304 | LAN_SAA9730_PACKET_SIZE * LAN_SAA9730_TXM_Q_SIZE, | |
1da177e4 LT |
305 | &lp->lan_saa9730_regs->TxBuffB); |
306 | ||
307 | /* Set packet number */ | |
05d9c84d | 308 | outl((lp->DmaRcvPackets << PK_COUNT_RX_A_SHF) | |
1da177e4 LT |
309 | (lp->DmaRcvPackets << PK_COUNT_RX_B_SHF) | |
310 | (lp->DmaTxmPackets << PK_COUNT_TX_A_SHF) | | |
311 | (lp->DmaTxmPackets << PK_COUNT_TX_B_SHF), | |
312 | &lp->lan_saa9730_regs->PacketCount); | |
313 | ||
314 | return 0; | |
05d9c84d RB |
315 | |
316 | out: | |
317 | return ret; | |
1da177e4 LT |
318 | } |
319 | ||
320 | static int lan_saa9730_cam_load(struct lan_saa9730_private *lp) | |
321 | { | |
322 | unsigned int i; | |
323 | unsigned char *NetworkAddress; | |
324 | ||
325 | NetworkAddress = (unsigned char *) &lp->PhysicalAddress[0][0]; | |
326 | ||
327 | for (i = 0; i < LAN_SAA9730_CAM_DWORDS; i++) { | |
328 | /* First set address to where data is written */ | |
05d9c84d RB |
329 | outl(i, &lp->lan_saa9730_regs->CamAddress); |
330 | outl((NetworkAddress[0] << 24) | (NetworkAddress[1] << 16) | |
1da177e4 LT |
331 | | (NetworkAddress[2] << 8) | NetworkAddress[3], |
332 | &lp->lan_saa9730_regs->CamData); | |
333 | NetworkAddress += 4; | |
334 | } | |
335 | return 0; | |
336 | } | |
337 | ||
338 | static int lan_saa9730_cam_init(struct net_device *dev) | |
339 | { | |
05d9c84d | 340 | struct lan_saa9730_private *lp = netdev_priv(dev); |
1da177e4 LT |
341 | unsigned int i; |
342 | ||
343 | /* Copy MAC-address into all entries. */ | |
344 | for (i = 0; i < LAN_SAA9730_CAM_ENTRIES; i++) { | |
345 | memcpy((unsigned char *) lp->PhysicalAddress[i], | |
346 | (unsigned char *) dev->dev_addr, 6); | |
347 | } | |
348 | ||
349 | return 0; | |
350 | } | |
351 | ||
352 | static int lan_saa9730_mii_init(struct lan_saa9730_private *lp) | |
353 | { | |
354 | int i, l; | |
355 | ||
356 | /* Check link status, spin here till station is not busy. */ | |
357 | i = 0; | |
05d9c84d | 358 | while (readl(&lp->lan_saa9730_regs->StationMgmtCtl) & MD_CA_BUSY) { |
1da177e4 LT |
359 | i++; |
360 | if (i > 100) { | |
361 | printk("Error: lan_saa9730_mii_init: timeout\n"); | |
362 | return -1; | |
363 | } | |
364 | mdelay(1); /* wait 1 ms. */ | |
365 | } | |
366 | ||
367 | /* Now set the control and address register. */ | |
05d9c84d | 368 | outl(MD_CA_BUSY | PHY_STATUS | PHY_ADDRESS << MD_CA_PHY_SHF, |
1da177e4 LT |
369 | &lp->lan_saa9730_regs->StationMgmtCtl); |
370 | ||
371 | /* check link status, spin here till station is not busy */ | |
372 | i = 0; | |
05d9c84d | 373 | while (readl(&lp->lan_saa9730_regs->StationMgmtCtl) & MD_CA_BUSY) { |
1da177e4 LT |
374 | i++; |
375 | if (i > 100) { | |
376 | printk("Error: lan_saa9730_mii_init: timeout\n"); | |
377 | return -1; | |
378 | } | |
379 | mdelay(1); /* wait 1 ms. */ | |
380 | } | |
381 | ||
382 | /* Wait for 1 ms. */ | |
383 | mdelay(1); | |
384 | ||
385 | /* Check the link status. */ | |
05d9c84d | 386 | if (readl(&lp->lan_saa9730_regs->StationMgmtData) & |
1da177e4 LT |
387 | PHY_STATUS_LINK_UP) { |
388 | /* Link is up. */ | |
389 | return 0; | |
390 | } else { | |
391 | /* Link is down, reset the PHY first. */ | |
392 | ||
393 | /* set PHY address = 'CONTROL' */ | |
05d9c84d | 394 | outl(PHY_ADDRESS << MD_CA_PHY_SHF | MD_CA_WR | PHY_CONTROL, |
1da177e4 LT |
395 | &lp->lan_saa9730_regs->StationMgmtCtl); |
396 | ||
397 | /* Wait for 1 ms. */ | |
398 | mdelay(1); | |
399 | ||
400 | /* set 'CONTROL' = force reset and renegotiate */ | |
05d9c84d | 401 | outl(PHY_CONTROL_RESET | PHY_CONTROL_AUTO_NEG | |
1da177e4 LT |
402 | PHY_CONTROL_RESTART_AUTO_NEG, |
403 | &lp->lan_saa9730_regs->StationMgmtData); | |
404 | ||
405 | /* Wait for 50 ms. */ | |
406 | mdelay(50); | |
407 | ||
408 | /* set 'BUSY' to start operation */ | |
05d9c84d | 409 | outl(MD_CA_BUSY | PHY_ADDRESS << MD_CA_PHY_SHF | MD_CA_WR | |
1da177e4 LT |
410 | PHY_CONTROL, &lp->lan_saa9730_regs->StationMgmtCtl); |
411 | ||
412 | /* await completion */ | |
413 | i = 0; | |
05d9c84d | 414 | while (readl(&lp->lan_saa9730_regs->StationMgmtCtl) & |
1da177e4 LT |
415 | MD_CA_BUSY) { |
416 | i++; | |
417 | if (i > 100) { | |
418 | printk | |
419 | ("Error: lan_saa9730_mii_init: timeout\n"); | |
420 | return -1; | |
421 | } | |
422 | mdelay(1); /* wait 1 ms. */ | |
423 | } | |
424 | ||
425 | /* Wait for 1 ms. */ | |
426 | mdelay(1); | |
427 | ||
428 | for (l = 0; l < 2; l++) { | |
429 | /* set PHY address = 'STATUS' */ | |
05d9c84d | 430 | outl(MD_CA_BUSY | PHY_ADDRESS << MD_CA_PHY_SHF | |
1da177e4 LT |
431 | PHY_STATUS, |
432 | &lp->lan_saa9730_regs->StationMgmtCtl); | |
433 | ||
434 | /* await completion */ | |
435 | i = 0; | |
05d9c84d | 436 | while (readl(&lp->lan_saa9730_regs->StationMgmtCtl) & |
1da177e4 LT |
437 | MD_CA_BUSY) { |
438 | i++; | |
439 | if (i > 100) { | |
440 | printk | |
441 | ("Error: lan_saa9730_mii_init: timeout\n"); | |
442 | return -1; | |
443 | } | |
444 | mdelay(1); /* wait 1 ms. */ | |
445 | } | |
446 | ||
447 | /* wait for 3 sec. */ | |
448 | mdelay(3000); | |
449 | ||
450 | /* check the link status */ | |
05d9c84d | 451 | if (readl(&lp->lan_saa9730_regs->StationMgmtData) & |
1da177e4 LT |
452 | PHY_STATUS_LINK_UP) { |
453 | /* link is up */ | |
454 | break; | |
455 | } | |
456 | } | |
457 | } | |
458 | ||
459 | return 0; | |
460 | } | |
461 | ||
462 | static int lan_saa9730_control_init(struct lan_saa9730_private *lp) | |
463 | { | |
464 | /* Initialize DMA control register. */ | |
05d9c84d | 465 | outl((LANMB_ANY << DMA_CTL_MAX_XFER_SHF) | |
1da177e4 LT |
466 | (LANEND_LITTLE << DMA_CTL_ENDIAN_SHF) | |
467 | (LAN_SAA9730_RCV_Q_INT_THRESHOLD << DMA_CTL_RX_INT_COUNT_SHF) | |
468 | | DMA_CTL_RX_INT_TO_EN | DMA_CTL_RX_INT_EN | | |
469 | DMA_CTL_MAC_RX_INT_EN | DMA_CTL_MAC_TX_INT_EN, | |
470 | &lp->lan_saa9730_regs->LanDmaCtl); | |
471 | ||
472 | /* Initial MAC control register. */ | |
05d9c84d | 473 | outl((MACCM_MII << MAC_CONTROL_CONN_SHF) | MAC_CONTROL_FULL_DUP, |
1da177e4 LT |
474 | &lp->lan_saa9730_regs->MacCtl); |
475 | ||
476 | /* Initialize CAM control register. */ | |
05d9c84d | 477 | outl(CAM_CONTROL_COMP_EN | CAM_CONTROL_BROAD_ACC, |
1da177e4 LT |
478 | &lp->lan_saa9730_regs->CamCtl); |
479 | ||
62ff0d0a | 480 | /* |
1da177e4 | 481 | * Initialize CAM enable register, only turn on first entry, should |
62ff0d0a | 482 | * contain own addr. |
1da177e4 | 483 | */ |
05d9c84d | 484 | outl(0x0001, &lp->lan_saa9730_regs->CamEnable); |
1da177e4 LT |
485 | |
486 | /* Initialize Tx control register */ | |
05d9c84d | 487 | outl(TX_CTL_EN_COMP, &lp->lan_saa9730_regs->TxCtl); |
1da177e4 LT |
488 | |
489 | /* Initialize Rcv control register */ | |
05d9c84d | 490 | outl(RX_CTL_STRIP_CRC, &lp->lan_saa9730_regs->RxCtl); |
1da177e4 LT |
491 | |
492 | /* Reset DMA engine */ | |
05d9c84d | 493 | outl(DMA_TEST_SW_RESET, &lp->lan_saa9730_regs->DmaTest); |
1da177e4 LT |
494 | |
495 | return 0; | |
496 | } | |
497 | ||
498 | static int lan_saa9730_stop(struct lan_saa9730_private *lp) | |
499 | { | |
500 | int i; | |
501 | ||
502 | /* Stop DMA first */ | |
05d9c84d | 503 | outl(readl(&lp->lan_saa9730_regs->LanDmaCtl) & |
1da177e4 LT |
504 | ~(DMA_CTL_EN_TX_DMA | DMA_CTL_EN_RX_DMA), |
505 | &lp->lan_saa9730_regs->LanDmaCtl); | |
506 | ||
507 | /* Set the SW Reset bits in DMA and MAC control registers */ | |
05d9c84d RB |
508 | outl(DMA_TEST_SW_RESET, &lp->lan_saa9730_regs->DmaTest); |
509 | outl(readl(&lp->lan_saa9730_regs->MacCtl) | MAC_CONTROL_RESET, | |
1da177e4 LT |
510 | &lp->lan_saa9730_regs->MacCtl); |
511 | ||
62ff0d0a | 512 | /* |
1da177e4 LT |
513 | * Wait for MAC reset to have finished. The reset bit is auto cleared |
514 | * when the reset is done. | |
515 | */ | |
516 | i = 0; | |
05d9c84d | 517 | while (readl(&lp->lan_saa9730_regs->MacCtl) & MAC_CONTROL_RESET) { |
1da177e4 LT |
518 | i++; |
519 | if (i > 100) { | |
520 | printk | |
521 | ("Error: lan_sa9730_stop: MAC reset timeout\n"); | |
522 | return -1; | |
523 | } | |
524 | mdelay(1); /* wait 1 ms. */ | |
525 | } | |
526 | ||
527 | return 0; | |
528 | } | |
529 | ||
530 | static int lan_saa9730_dma_init(struct lan_saa9730_private *lp) | |
531 | { | |
532 | /* Stop lan controller. */ | |
533 | lan_saa9730_stop(lp); | |
534 | ||
05d9c84d | 535 | outl(LAN_SAA9730_DEFAULT_TIME_OUT_CNT, |
1da177e4 LT |
536 | &lp->lan_saa9730_regs->Timeout); |
537 | ||
538 | return 0; | |
539 | } | |
540 | ||
541 | static int lan_saa9730_start(struct lan_saa9730_private *lp) | |
542 | { | |
543 | lan_saa9730_buffer_init(lp); | |
544 | ||
545 | /* Initialize Rx Buffer Index */ | |
546 | lp->NextRcvPacketIndex = 0; | |
05d9c84d | 547 | lp->NextRcvBufferIndex = 0; |
1da177e4 | 548 | |
05d9c84d | 549 | /* Set current buffer index & next available packet index */ |
1da177e4 LT |
550 | lp->NextTxmPacketIndex = 0; |
551 | lp->NextTxmBufferIndex = 0; | |
552 | lp->PendingTxmPacketIndex = 0; | |
553 | lp->PendingTxmBufferIndex = 0; | |
554 | ||
05d9c84d | 555 | outl(readl(&lp->lan_saa9730_regs->LanDmaCtl) | DMA_CTL_EN_TX_DMA | |
1da177e4 LT |
556 | DMA_CTL_EN_RX_DMA, &lp->lan_saa9730_regs->LanDmaCtl); |
557 | ||
558 | /* For Tx, turn on MAC then DMA */ | |
05d9c84d | 559 | outl(readl(&lp->lan_saa9730_regs->TxCtl) | TX_CTL_TX_EN, |
1da177e4 LT |
560 | &lp->lan_saa9730_regs->TxCtl); |
561 | ||
562 | /* For Rx, turn on DMA then MAC */ | |
05d9c84d | 563 | outl(readl(&lp->lan_saa9730_regs->RxCtl) | RX_CTL_RX_EN, |
1da177e4 LT |
564 | &lp->lan_saa9730_regs->RxCtl); |
565 | ||
05d9c84d RB |
566 | /* Set Ok2Use to let hardware own the buffers. */ |
567 | outl(OK2USE_RX_A | OK2USE_RX_B, &lp->lan_saa9730_regs->Ok2Use); | |
1da177e4 LT |
568 | |
569 | return 0; | |
570 | } | |
571 | ||
572 | static int lan_saa9730_restart(struct lan_saa9730_private *lp) | |
573 | { | |
574 | lan_saa9730_stop(lp); | |
575 | lan_saa9730_start(lp); | |
576 | ||
577 | return 0; | |
578 | } | |
579 | ||
580 | static int lan_saa9730_tx(struct net_device *dev) | |
581 | { | |
05d9c84d | 582 | struct lan_saa9730_private *lp = netdev_priv(dev); |
1da177e4 LT |
583 | unsigned int *pPacket; |
584 | unsigned int tx_status; | |
585 | ||
586 | if (lan_saa9730_debug > 5) | |
587 | printk("lan_saa9730_tx interrupt\n"); | |
588 | ||
589 | /* Clear interrupt. */ | |
05d9c84d | 590 | outl(DMA_STATUS_MAC_TX_INT, &lp->lan_saa9730_regs->DmaStatus); |
1da177e4 LT |
591 | |
592 | while (1) { | |
05d9c84d RB |
593 | pPacket = lp->TxmBuffer[lp->PendingTxmBufferIndex] |
594 | [lp->PendingTxmPacketIndex]; | |
1da177e4 LT |
595 | |
596 | /* Get status of first packet transmitted. */ | |
597 | tx_status = le32_to_cpu(*pPacket); | |
598 | ||
599 | /* Check ownership. */ | |
600 | if ((tx_status & TX_STAT_CTL_OWNER_MSK) != | |
601 | (TXSF_HWDONE << TX_STAT_CTL_OWNER_SHF)) break; | |
602 | ||
603 | /* Check for error. */ | |
604 | if (tx_status & TX_STAT_CTL_ERROR_MSK) { | |
605 | if (lan_saa9730_debug > 1) | |
606 | printk("lan_saa9730_tx: tx error = %x\n", | |
607 | tx_status); | |
608 | ||
609 | lp->stats.tx_errors++; | |
610 | if (tx_status & | |
611 | (TX_STATUS_EX_COLL << TX_STAT_CTL_STATUS_SHF)) | |
05d9c84d | 612 | lp->stats.tx_aborted_errors++; |
1da177e4 | 613 | if (tx_status & |
05d9c84d RB |
614 | (TX_STATUS_LATE_COLL << TX_STAT_CTL_STATUS_SHF)) |
615 | lp->stats.tx_window_errors++; | |
1da177e4 LT |
616 | if (tx_status & |
617 | (TX_STATUS_L_CARR << TX_STAT_CTL_STATUS_SHF)) | |
05d9c84d | 618 | lp->stats.tx_carrier_errors++; |
1da177e4 LT |
619 | if (tx_status & |
620 | (TX_STATUS_UNDER << TX_STAT_CTL_STATUS_SHF)) | |
05d9c84d | 621 | lp->stats.tx_fifo_errors++; |
1da177e4 LT |
622 | if (tx_status & |
623 | (TX_STATUS_SQ_ERR << TX_STAT_CTL_STATUS_SHF)) | |
05d9c84d | 624 | lp->stats.tx_heartbeat_errors++; |
1da177e4 LT |
625 | |
626 | lp->stats.collisions += | |
05d9c84d | 627 | tx_status & TX_STATUS_TX_COLL_MSK; |
1da177e4 LT |
628 | } |
629 | ||
630 | /* Free buffer. */ | |
631 | *pPacket = | |
632 | cpu_to_le32(TXSF_EMPTY << TX_STAT_CTL_OWNER_SHF); | |
633 | ||
634 | /* Update pending index pointer. */ | |
635 | lp->PendingTxmPacketIndex++; | |
636 | if (lp->PendingTxmPacketIndex >= LAN_SAA9730_TXM_Q_SIZE) { | |
637 | lp->PendingTxmPacketIndex = 0; | |
638 | lp->PendingTxmBufferIndex ^= 1; | |
639 | } | |
640 | } | |
641 | ||
05d9c84d RB |
642 | /* The tx buffer is no longer full. */ |
643 | netif_wake_queue(dev); | |
1da177e4 LT |
644 | |
645 | return 0; | |
646 | } | |
647 | ||
648 | static int lan_saa9730_rx(struct net_device *dev) | |
649 | { | |
05d9c84d | 650 | struct lan_saa9730_private *lp = netdev_priv(dev); |
1da177e4 LT |
651 | int len = 0; |
652 | struct sk_buff *skb = 0; | |
653 | unsigned int rx_status; | |
654 | int BufferIndex; | |
655 | int PacketIndex; | |
656 | unsigned int *pPacket; | |
657 | unsigned char *pData; | |
658 | ||
659 | if (lan_saa9730_debug > 5) | |
660 | printk("lan_saa9730_rx interrupt\n"); | |
661 | ||
662 | /* Clear receive interrupts. */ | |
05d9c84d | 663 | outl(DMA_STATUS_MAC_RX_INT | DMA_STATUS_RX_INT | |
1da177e4 LT |
664 | DMA_STATUS_RX_TO_INT, &lp->lan_saa9730_regs->DmaStatus); |
665 | ||
666 | /* Address next packet */ | |
05d9c84d | 667 | BufferIndex = lp->NextRcvBufferIndex; |
1da177e4 | 668 | PacketIndex = lp->NextRcvPacketIndex; |
05d9c84d | 669 | pPacket = lp->RcvBuffer[BufferIndex][PacketIndex]; |
1da177e4 LT |
670 | rx_status = le32_to_cpu(*pPacket); |
671 | ||
672 | /* Process each packet. */ | |
673 | while ((rx_status & RX_STAT_CTL_OWNER_MSK) == | |
674 | (RXSF_HWDONE << RX_STAT_CTL_OWNER_SHF)) { | |
675 | /* Check the rx status. */ | |
676 | if (rx_status & (RX_STATUS_GOOD << RX_STAT_CTL_STATUS_SHF)) { | |
677 | /* Received packet is good. */ | |
678 | len = (rx_status & RX_STAT_CTL_LENGTH_MSK) >> | |
679 | RX_STAT_CTL_LENGTH_SHF; | |
680 | ||
681 | pData = (unsigned char *) pPacket; | |
682 | pData += 4; | |
683 | skb = dev_alloc_skb(len + 2); | |
684 | if (skb == 0) { | |
685 | printk | |
686 | ("%s: Memory squeeze, deferring packet.\n", | |
687 | dev->name); | |
688 | lp->stats.rx_dropped++; | |
689 | } else { | |
690 | lp->stats.rx_bytes += len; | |
691 | lp->stats.rx_packets++; | |
692 | skb->dev = dev; | |
693 | skb_reserve(skb, 2); /* 16 byte align */ | |
694 | skb_put(skb, len); /* make room */ | |
695 | eth_copy_and_sum(skb, | |
696 | (unsigned char *) pData, | |
697 | len, 0); | |
698 | skb->protocol = eth_type_trans(skb, dev); | |
699 | netif_rx(skb); | |
700 | dev->last_rx = jiffies; | |
701 | } | |
702 | } else { | |
703 | /* We got an error packet. */ | |
704 | if (lan_saa9730_debug > 2) | |
705 | printk | |
706 | ("lan_saa9730_rx: We got an error packet = %x\n", | |
707 | rx_status); | |
708 | ||
709 | lp->stats.rx_errors++; | |
710 | if (rx_status & | |
711 | (RX_STATUS_CRC_ERR << RX_STAT_CTL_STATUS_SHF)) | |
05d9c84d | 712 | lp->stats.rx_crc_errors++; |
1da177e4 | 713 | if (rx_status & |
05d9c84d RB |
714 | (RX_STATUS_ALIGN_ERR << RX_STAT_CTL_STATUS_SHF)) |
715 | lp->stats.rx_frame_errors++; | |
1da177e4 LT |
716 | if (rx_status & |
717 | (RX_STATUS_OVERFLOW << RX_STAT_CTL_STATUS_SHF)) | |
05d9c84d | 718 | lp->stats.rx_fifo_errors++; |
1da177e4 LT |
719 | if (rx_status & |
720 | (RX_STATUS_LONG_ERR << RX_STAT_CTL_STATUS_SHF)) | |
05d9c84d | 721 | lp->stats.rx_length_errors++; |
1da177e4 LT |
722 | } |
723 | ||
724 | /* Indicate we have processed the buffer. */ | |
05d9c84d RB |
725 | *pPacket = cpu_to_le32(RXSF_READY << RX_STAT_CTL_OWNER_SHF); |
726 | ||
727 | /* Make sure A or B is available to hardware as appropriate. */ | |
728 | outl(BufferIndex ? OK2USE_RX_B : OK2USE_RX_A, | |
729 | &lp->lan_saa9730_regs->Ok2Use); | |
1da177e4 LT |
730 | |
731 | /* Go to next packet in sequence. */ | |
732 | lp->NextRcvPacketIndex++; | |
733 | if (lp->NextRcvPacketIndex >= LAN_SAA9730_RCV_Q_SIZE) { | |
734 | lp->NextRcvPacketIndex = 0; | |
05d9c84d | 735 | lp->NextRcvBufferIndex ^= 1; |
1da177e4 | 736 | } |
1da177e4 LT |
737 | |
738 | /* Address next packet */ | |
05d9c84d | 739 | BufferIndex = lp->NextRcvBufferIndex; |
1da177e4 | 740 | PacketIndex = lp->NextRcvPacketIndex; |
05d9c84d | 741 | pPacket = lp->RcvBuffer[BufferIndex][PacketIndex]; |
1da177e4 LT |
742 | rx_status = le32_to_cpu(*pPacket); |
743 | } | |
744 | ||
1da177e4 LT |
745 | return 0; |
746 | } | |
747 | ||
748 | static irqreturn_t lan_saa9730_interrupt(const int irq, void *dev_id, | |
749 | struct pt_regs *regs) | |
750 | { | |
751 | struct net_device *dev = (struct net_device *) dev_id; | |
05d9c84d | 752 | struct lan_saa9730_private *lp = netdev_priv(dev); |
1da177e4 LT |
753 | |
754 | if (lan_saa9730_debug > 5) | |
755 | printk("lan_saa9730_interrupt\n"); | |
756 | ||
757 | /* Disable the EVM LAN interrupt. */ | |
758 | evm_saa9730_block_lan_int(lp); | |
759 | ||
760 | /* Clear the EVM LAN interrupt. */ | |
761 | evm_saa9730_clear_lan_int(lp); | |
762 | ||
763 | /* Service pending transmit interrupts. */ | |
05d9c84d | 764 | if (readl(&lp->lan_saa9730_regs->DmaStatus) & DMA_STATUS_MAC_TX_INT) |
1da177e4 LT |
765 | lan_saa9730_tx(dev); |
766 | ||
767 | /* Service pending receive interrupts. */ | |
05d9c84d | 768 | if (readl(&lp->lan_saa9730_regs->DmaStatus) & |
1da177e4 LT |
769 | (DMA_STATUS_MAC_RX_INT | DMA_STATUS_RX_INT | |
770 | DMA_STATUS_RX_TO_INT)) lan_saa9730_rx(dev); | |
771 | ||
772 | /* Enable the EVM LAN interrupt. */ | |
773 | evm_saa9730_unblock_lan_int(lp); | |
774 | ||
775 | return IRQ_HANDLED; | |
776 | } | |
777 | ||
1da177e4 LT |
778 | static int lan_saa9730_open(struct net_device *dev) |
779 | { | |
05d9c84d | 780 | struct lan_saa9730_private *lp = netdev_priv(dev); |
1da177e4 LT |
781 | |
782 | /* Associate IRQ with lan_saa9730_interrupt */ | |
783 | if (request_irq(dev->irq, &lan_saa9730_interrupt, 0, "SAA9730 Eth", | |
784 | dev)) { | |
785 | printk("lan_saa9730_open: Can't get irq %d\n", dev->irq); | |
786 | return -EAGAIN; | |
787 | } | |
788 | ||
789 | /* Enable the Lan interrupt in the event manager. */ | |
790 | evm_saa9730_enable_lan_int(lp); | |
791 | ||
792 | /* Start the LAN controller */ | |
793 | if (lan_saa9730_start(lp)) | |
794 | return -1; | |
795 | ||
796 | netif_start_queue(dev); | |
797 | ||
798 | return 0; | |
799 | } | |
800 | ||
801 | static int lan_saa9730_write(struct lan_saa9730_private *lp, | |
802 | struct sk_buff *skb, int skblen) | |
803 | { | |
804 | unsigned char *pbData = skb->data; | |
805 | unsigned int len = skblen; | |
806 | unsigned char *pbPacketData; | |
807 | unsigned int tx_status; | |
808 | int BufferIndex; | |
809 | int PacketIndex; | |
810 | ||
811 | if (lan_saa9730_debug > 5) | |
05d9c84d | 812 | printk("lan_saa9730_write: skb=%p\n", skb); |
1da177e4 LT |
813 | |
814 | BufferIndex = lp->NextTxmBufferIndex; | |
815 | PacketIndex = lp->NextTxmPacketIndex; | |
816 | ||
05d9c84d RB |
817 | tx_status = le32_to_cpu(*(unsigned int *)lp->TxmBuffer[BufferIndex] |
818 | [PacketIndex]); | |
1da177e4 LT |
819 | if ((tx_status & TX_STAT_CTL_OWNER_MSK) != |
820 | (TXSF_EMPTY << TX_STAT_CTL_OWNER_SHF)) { | |
821 | if (lan_saa9730_debug > 4) | |
822 | printk | |
823 | ("lan_saa9730_write: Tx buffer not available: tx_status = %x\n", | |
824 | tx_status); | |
825 | return -1; | |
826 | } | |
827 | ||
828 | lp->NextTxmPacketIndex++; | |
829 | if (lp->NextTxmPacketIndex >= LAN_SAA9730_TXM_Q_SIZE) { | |
830 | lp->NextTxmPacketIndex = 0; | |
831 | lp->NextTxmBufferIndex ^= 1; | |
832 | } | |
833 | ||
05d9c84d | 834 | pbPacketData = lp->TxmBuffer[BufferIndex][PacketIndex]; |
1da177e4 LT |
835 | pbPacketData += 4; |
836 | ||
837 | /* copy the bits */ | |
838 | memcpy(pbPacketData, pbData, len); | |
839 | ||
840 | /* Set transmit status for hardware */ | |
05d9c84d RB |
841 | *(unsigned int *)lp->TxmBuffer[BufferIndex][PacketIndex] = |
842 | cpu_to_le32((TXSF_READY << TX_STAT_CTL_OWNER_SHF) | | |
843 | (TX_STAT_CTL_INT_AFTER_TX << | |
844 | TX_STAT_CTL_FRAME_SHF) | | |
845 | (len << TX_STAT_CTL_LENGTH_SHF)); | |
846 | ||
847 | /* Make sure A or B is available to hardware as appropriate. */ | |
848 | outl(BufferIndex ? OK2USE_TX_B : OK2USE_TX_A, | |
849 | &lp->lan_saa9730_regs->Ok2Use); | |
1da177e4 LT |
850 | |
851 | return 0; | |
852 | } | |
853 | ||
854 | static void lan_saa9730_tx_timeout(struct net_device *dev) | |
855 | { | |
05d9c84d | 856 | struct lan_saa9730_private *lp = netdev_priv(dev); |
1da177e4 LT |
857 | |
858 | /* Transmitter timeout, serious problems */ | |
859 | lp->stats.tx_errors++; | |
860 | printk("%s: transmit timed out, reset\n", dev->name); | |
861 | /*show_saa9730_regs(lp); */ | |
862 | lan_saa9730_restart(lp); | |
863 | ||
864 | dev->trans_start = jiffies; | |
05d9c84d | 865 | netif_wake_queue(dev); |
1da177e4 LT |
866 | } |
867 | ||
868 | static int lan_saa9730_start_xmit(struct sk_buff *skb, | |
869 | struct net_device *dev) | |
870 | { | |
05d9c84d | 871 | struct lan_saa9730_private *lp = netdev_priv(dev); |
1da177e4 LT |
872 | unsigned long flags; |
873 | int skblen; | |
874 | int len; | |
875 | ||
876 | if (lan_saa9730_debug > 4) | |
05d9c84d | 877 | printk("Send packet: skb=%p\n", skb); |
1da177e4 LT |
878 | |
879 | skblen = skb->len; | |
880 | ||
881 | spin_lock_irqsave(&lp->lock, flags); | |
882 | ||
883 | len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen; | |
884 | ||
885 | if (lan_saa9730_write(lp, skb, skblen)) { | |
886 | spin_unlock_irqrestore(&lp->lock, flags); | |
05d9c84d | 887 | printk("Error when writing packet to controller: skb=%p\n", skb); |
1da177e4 LT |
888 | netif_stop_queue(dev); |
889 | return -1; | |
890 | } | |
891 | ||
892 | lp->stats.tx_bytes += len; | |
893 | lp->stats.tx_packets++; | |
894 | ||
895 | dev->trans_start = jiffies; | |
05d9c84d | 896 | netif_wake_queue(dev); |
1da177e4 LT |
897 | dev_kfree_skb(skb); |
898 | ||
899 | spin_unlock_irqrestore(&lp->lock, flags); | |
900 | ||
901 | return 0; | |
902 | } | |
903 | ||
904 | static int lan_saa9730_close(struct net_device *dev) | |
905 | { | |
05d9c84d | 906 | struct lan_saa9730_private *lp = netdev_priv(dev); |
1da177e4 LT |
907 | |
908 | if (lan_saa9730_debug > 1) | |
909 | printk("lan_saa9730_close:\n"); | |
910 | ||
911 | netif_stop_queue(dev); | |
912 | ||
913 | /* Disable the Lan interrupt in the event manager. */ | |
914 | evm_saa9730_disable_lan_int(lp); | |
915 | ||
916 | /* Stop the controller */ | |
917 | if (lan_saa9730_stop(lp)) | |
918 | return -1; | |
919 | ||
920 | free_irq(dev->irq, (void *) dev); | |
921 | ||
922 | return 0; | |
923 | } | |
924 | ||
925 | static struct net_device_stats *lan_saa9730_get_stats(struct net_device | |
926 | *dev) | |
927 | { | |
05d9c84d | 928 | struct lan_saa9730_private *lp = netdev_priv(dev); |
1da177e4 LT |
929 | |
930 | return &lp->stats; | |
931 | } | |
932 | ||
933 | static void lan_saa9730_set_multicast(struct net_device *dev) | |
934 | { | |
05d9c84d | 935 | struct lan_saa9730_private *lp = netdev_priv(dev); |
1da177e4 LT |
936 | |
937 | /* Stop the controller */ | |
938 | lan_saa9730_stop(lp); | |
939 | ||
940 | if (dev->flags & IFF_PROMISC) { | |
941 | /* accept all packets */ | |
05d9c84d | 942 | outl(CAM_CONTROL_COMP_EN | CAM_CONTROL_STATION_ACC | |
1da177e4 LT |
943 | CAM_CONTROL_GROUP_ACC | CAM_CONTROL_BROAD_ACC, |
944 | &lp->lan_saa9730_regs->CamCtl); | |
945 | } else { | |
946 | if (dev->flags & IFF_ALLMULTI) { | |
947 | /* accept all multicast packets */ | |
05d9c84d | 948 | outl(CAM_CONTROL_COMP_EN | CAM_CONTROL_GROUP_ACC | |
1da177e4 LT |
949 | CAM_CONTROL_BROAD_ACC, |
950 | &lp->lan_saa9730_regs->CamCtl); | |
951 | } else { | |
62ff0d0a | 952 | /* |
1da177e4 LT |
953 | * Will handle the multicast stuff later. -carstenl |
954 | */ | |
955 | } | |
956 | } | |
957 | ||
958 | lan_saa9730_restart(lp); | |
959 | } | |
960 | ||
961 | ||
962 | static void __devexit saa9730_remove_one(struct pci_dev *pdev) | |
963 | { | |
62ff0d0a | 964 | struct net_device *dev = pci_get_drvdata(pdev); |
05d9c84d | 965 | struct lan_saa9730_private *lp = netdev_priv(dev); |
1da177e4 | 966 | |
62ff0d0a RB |
967 | if (dev) { |
968 | unregister_netdev(dev); | |
05d9c84d RB |
969 | lan_saa9730_free_buffers(pdev, lp); |
970 | iounmap(lp->lan_saa9730_regs); | |
971 | iounmap(lp->evm_saa9730_regs); | |
62ff0d0a RB |
972 | free_netdev(dev); |
973 | pci_release_regions(pdev); | |
974 | pci_disable_device(pdev); | |
975 | pci_set_drvdata(pdev, NULL); | |
976 | } | |
1da177e4 LT |
977 | } |
978 | ||
979 | ||
05d9c84d RB |
980 | static int lan_saa9730_init(struct net_device *dev, struct pci_dev *pdev, |
981 | unsigned long ioaddr, int irq) | |
1da177e4 | 982 | { |
05d9c84d | 983 | struct lan_saa9730_private *lp = netdev_priv(dev); |
1da177e4 | 984 | unsigned char ethernet_addr[6]; |
05d9c84d | 985 | int ret; |
1da177e4 | 986 | |
05d9c84d RB |
987 | if (get_ethernet_addr(ethernet_addr)) { |
988 | ret = -ENODEV; | |
989 | goto out; | |
990 | } | |
62ff0d0a | 991 | |
1da177e4 LT |
992 | memcpy(dev->dev_addr, ethernet_addr, 6); |
993 | dev->base_addr = ioaddr; | |
994 | dev->irq = irq; | |
62ff0d0a | 995 | |
05d9c84d | 996 | lp->pci_dev = pdev; |
1da177e4 LT |
997 | |
998 | /* Set SAA9730 LAN base address. */ | |
05d9c84d RB |
999 | lp->lan_saa9730_regs = ioremap(ioaddr + SAA9730_LAN_REGS_ADDR, |
1000 | SAA9730_LAN_REGS_SIZE); | |
1001 | if (!lp->lan_saa9730_regs) { | |
1002 | ret = -ENOMEM; | |
1003 | goto out; | |
1004 | } | |
1da177e4 LT |
1005 | |
1006 | /* Set SAA9730 EVM base address. */ | |
05d9c84d RB |
1007 | lp->evm_saa9730_regs = ioremap(ioaddr + SAA9730_EVM_REGS_ADDR, |
1008 | SAA9730_EVM_REGS_SIZE); | |
1009 | if (!lp->evm_saa9730_regs) { | |
1010 | ret = -ENOMEM; | |
1011 | goto out_iounmap_lan; | |
1012 | } | |
1da177e4 LT |
1013 | |
1014 | /* Allocate LAN RX/TX frame buffer space. */ | |
05d9c84d RB |
1015 | if ((ret = lan_saa9730_allocate_buffers(pdev, lp))) |
1016 | goto out_iounmap; | |
1da177e4 LT |
1017 | |
1018 | /* Stop LAN controller. */ | |
62ff0d0a | 1019 | if ((ret = lan_saa9730_stop(lp))) |
05d9c84d | 1020 | goto out_free_consistent; |
62ff0d0a | 1021 | |
1da177e4 LT |
1022 | /* Initialize CAM registers. */ |
1023 | if ((ret = lan_saa9730_cam_init(dev))) | |
05d9c84d | 1024 | goto out_free_consistent; |
1da177e4 LT |
1025 | |
1026 | /* Initialize MII registers. */ | |
1027 | if ((ret = lan_saa9730_mii_init(lp))) | |
05d9c84d | 1028 | goto out_free_consistent; |
1da177e4 LT |
1029 | |
1030 | /* Initialize control registers. */ | |
62ff0d0a | 1031 | if ((ret = lan_saa9730_control_init(lp))) |
05d9c84d | 1032 | goto out_free_consistent; |
62ff0d0a | 1033 | |
1da177e4 | 1034 | /* Load CAM registers. */ |
62ff0d0a | 1035 | if ((ret = lan_saa9730_cam_load(lp))) |
05d9c84d | 1036 | goto out_free_consistent; |
62ff0d0a | 1037 | |
1da177e4 LT |
1038 | /* Initialize DMA context registers. */ |
1039 | if ((ret = lan_saa9730_dma_init(lp))) | |
05d9c84d | 1040 | goto out_free_consistent; |
62ff0d0a | 1041 | |
1da177e4 | 1042 | spin_lock_init(&lp->lock); |
62ff0d0a | 1043 | |
1da177e4 LT |
1044 | dev->open = lan_saa9730_open; |
1045 | dev->hard_start_xmit = lan_saa9730_start_xmit; | |
1046 | dev->stop = lan_saa9730_close; | |
1047 | dev->get_stats = lan_saa9730_get_stats; | |
1048 | dev->set_multicast_list = lan_saa9730_set_multicast; | |
1049 | dev->tx_timeout = lan_saa9730_tx_timeout; | |
1050 | dev->watchdog_timeo = (HZ >> 1); | |
1051 | dev->dma = 0; | |
62ff0d0a | 1052 | |
05d9c84d | 1053 | ret = register_netdev (dev); |
1da177e4 | 1054 | if (ret) |
05d9c84d RB |
1055 | goto out_free_consistent; |
1056 | ||
1da177e4 LT |
1057 | return 0; |
1058 | ||
05d9c84d RB |
1059 | out_free_consistent: |
1060 | lan_saa9730_free_buffers(pdev, lp); | |
1061 | out_iounmap: | |
1062 | iounmap(lp->evm_saa9730_regs); | |
1063 | out_iounmap_lan: | |
1064 | iounmap(lp->lan_saa9730_regs); | |
1065 | out: | |
1da177e4 LT |
1066 | return ret; |
1067 | } | |
1068 | ||
1069 | ||
1070 | static int __devinit saa9730_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |
1071 | { | |
05d9c84d RB |
1072 | struct net_device *dev = NULL; |
1073 | unsigned long pci_ioaddr; | |
1da177e4 LT |
1074 | int err; |
1075 | ||
1076 | if (lan_saa9730_debug > 1) | |
1077 | printk("saa9730.c: PCI bios is present, checking for devices...\n"); | |
1078 | ||
1da177e4 | 1079 | err = pci_enable_device(pdev); |
62ff0d0a RB |
1080 | if (err) { |
1081 | printk(KERN_ERR "Cannot enable PCI device, aborting.\n"); | |
05d9c84d | 1082 | goto out; |
62ff0d0a | 1083 | } |
1da177e4 LT |
1084 | |
1085 | err = pci_request_regions(pdev, DRV_MODULE_NAME); | |
1086 | if (err) { | |
1087 | printk(KERN_ERR "Cannot obtain PCI resources, aborting.\n"); | |
05d9c84d | 1088 | goto out_disable_pdev; |
1da177e4 LT |
1089 | } |
1090 | ||
1091 | pci_irq_line = pdev->irq; | |
1092 | /* LAN base address in located at BAR 1. */ | |
1093 | ||
1094 | pci_ioaddr = pci_resource_start(pdev, 1); | |
1095 | pci_set_master(pdev); | |
1096 | ||
05d9c84d | 1097 | printk("Found SAA9730 (PCI) at %lx, irq %d.\n", |
1da177e4 LT |
1098 | pci_ioaddr, pci_irq_line); |
1099 | ||
05d9c84d RB |
1100 | dev = alloc_etherdev(sizeof(struct lan_saa9730_private)); |
1101 | if (!dev) | |
1102 | goto out_disable_pdev; | |
1103 | ||
1104 | err = lan_saa9730_init(dev, pdev, pci_ioaddr, pci_irq_line); | |
1da177e4 | 1105 | if (err) { |
05d9c84d RB |
1106 | printk("LAN init failed"); |
1107 | goto out_free_netdev; | |
1da177e4 LT |
1108 | } |
1109 | ||
1110 | pci_set_drvdata(pdev, dev); | |
1111 | SET_NETDEV_DEV(dev, &pdev->dev); | |
1112 | return 0; | |
62ff0d0a | 1113 | |
05d9c84d | 1114 | out_free_netdev: |
1da177e4 | 1115 | free_netdev(dev); |
05d9c84d RB |
1116 | out_disable_pdev: |
1117 | pci_disable_device(pdev); | |
1da177e4 | 1118 | out: |
05d9c84d | 1119 | pci_set_drvdata(pdev, NULL); |
1da177e4 LT |
1120 | return err; |
1121 | } | |
1122 | ||
1123 | ||
1124 | static struct pci_driver saa9730_driver = { | |
62ff0d0a RB |
1125 | .name = DRV_MODULE_NAME, |
1126 | .id_table = saa9730_pci_tbl, | |
1127 | .probe = saa9730_init_one, | |
1128 | .remove = __devexit_p(saa9730_remove_one), | |
1da177e4 LT |
1129 | }; |
1130 | ||
1131 | ||
1132 | static int __init saa9730_init(void) | |
1133 | { | |
62ff0d0a | 1134 | return pci_module_init(&saa9730_driver); |
1da177e4 LT |
1135 | } |
1136 | ||
1137 | static void __exit saa9730_cleanup(void) | |
1138 | { | |
62ff0d0a | 1139 | pci_unregister_driver(&saa9730_driver); |
1da177e4 LT |
1140 | } |
1141 | ||
1142 | module_init(saa9730_init); | |
1143 | module_exit(saa9730_cleanup); | |
1144 | ||
05d9c84d RB |
1145 | MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>"); |
1146 | MODULE_DESCRIPTION("Philips SAA9730 ethernet driver"); | |
1da177e4 | 1147 | MODULE_LICENSE("GPL"); |