]>
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 | { | |
69a43ac0 RB |
67 | writel(readl(&lp->evm_saa9730_regs->InterruptBlock1) | EVM_LAN_INT, |
68 | &lp->evm_saa9730_regs->InterruptBlock1); | |
69 | writel(readl(&lp->evm_saa9730_regs->InterruptStatus1) | EVM_LAN_INT, | |
70 | &lp->evm_saa9730_regs->InterruptStatus1); | |
71 | writel(readl(&lp->evm_saa9730_regs->InterruptEnable1) | EVM_LAN_INT | | |
72 | EVM_MASTER_EN, &lp->evm_saa9730_regs->InterruptEnable1); | |
1da177e4 | 73 | } |
05d9c84d | 74 | |
1da177e4 LT |
75 | static void evm_saa9730_disable_lan_int(struct lan_saa9730_private *lp) |
76 | { | |
69a43ac0 RB |
77 | writel(readl(&lp->evm_saa9730_regs->InterruptBlock1) & ~EVM_LAN_INT, |
78 | &lp->evm_saa9730_regs->InterruptBlock1); | |
79 | writel(readl(&lp->evm_saa9730_regs->InterruptEnable1) & ~EVM_LAN_INT, | |
80 | &lp->evm_saa9730_regs->InterruptEnable1); | |
1da177e4 LT |
81 | } |
82 | ||
83 | static void evm_saa9730_clear_lan_int(struct lan_saa9730_private *lp) | |
84 | { | |
69a43ac0 | 85 | writel(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 | { | |
69a43ac0 RB |
90 | writel(readl(&lp->evm_saa9730_regs->InterruptBlock1) & ~EVM_LAN_INT, |
91 | &lp->evm_saa9730_regs->InterruptBlock1); | |
1da177e4 LT |
92 | } |
93 | ||
94 | static void evm_saa9730_unblock_lan_int(struct lan_saa9730_private *lp) | |
95 | { | |
69a43ac0 RB |
96 | writel(readl(&lp->evm_saa9730_regs->InterruptBlock1) | EVM_LAN_INT, |
97 | &lp->evm_saa9730_regs->InterruptBlock1); | |
1da177e4 LT |
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++) { |
69a43ac0 | 150 | writel(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 | 153 | } |
09f75cd7 JG |
154 | printk("dev->stats.tx_packets = %lx\n", dev->stats.tx_packets); |
155 | printk("dev->stats.tx_errors = %lx\n", dev->stats.tx_errors); | |
156 | printk("dev->stats.tx_aborted_errors = %lx\n", | |
157 | dev->stats.tx_aborted_errors); | |
158 | printk("dev->stats.tx_window_errors = %lx\n", | |
159 | dev->stats.tx_window_errors); | |
160 | printk("dev->stats.tx_carrier_errors = %lx\n", | |
161 | dev->stats.tx_carrier_errors); | |
162 | printk("dev->stats.tx_fifo_errors = %lx\n", | |
163 | dev->stats.tx_fifo_errors); | |
164 | printk("dev->stats.tx_heartbeat_errors = %lx\n", | |
165 | dev->stats.tx_heartbeat_errors); | |
166 | printk("dev->stats.collisions = %lx\n", dev->stats.collisions); | |
167 | ||
168 | printk("dev->stats.rx_packets = %lx\n", dev->stats.rx_packets); | |
169 | printk("dev->stats.rx_errors = %lx\n", dev->stats.rx_errors); | |
170 | printk("dev->stats.rx_dropped = %lx\n", dev->stats.rx_dropped); | |
171 | printk("dev->stats.rx_crc_errors = %lx\n", dev->stats.rx_crc_errors); | |
172 | printk("dev->stats.rx_frame_errors = %lx\n", | |
173 | dev->stats.rx_frame_errors); | |
174 | printk("dev->stats.rx_fifo_errors = %lx\n", | |
175 | dev->stats.rx_fifo_errors); | |
176 | printk("dev->stats.rx_length_errors = %lx\n", | |
177 | dev->stats.rx_length_errors); | |
1da177e4 LT |
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 | */ | |
69a43ac0 RB |
291 | writel(lp->dma_addr + rxoffset, &lp->lan_saa9730_regs->RxBuffA); |
292 | writel(lp->dma_addr + rxoffset + | |
293 | LAN_SAA9730_PACKET_SIZE * LAN_SAA9730_RCV_Q_SIZE, | |
294 | &lp->lan_saa9730_regs->RxBuffB); | |
1da177e4 | 295 | |
62ff0d0a | 296 | /* |
1da177e4 | 297 | * Set txm_buf_a and txm_buf_b to point to the first two buffer |
62ff0d0a | 298 | * space |
1da177e4 | 299 | */ |
69a43ac0 RB |
300 | writel(lp->dma_addr + txoffset, |
301 | &lp->lan_saa9730_regs->TxBuffA); | |
302 | writel(lp->dma_addr + txoffset + | |
303 | LAN_SAA9730_PACKET_SIZE * LAN_SAA9730_TXM_Q_SIZE, | |
304 | &lp->lan_saa9730_regs->TxBuffB); | |
1da177e4 LT |
305 | |
306 | /* Set packet number */ | |
69a43ac0 RB |
307 | writel((lp->DmaRcvPackets << PK_COUNT_RX_A_SHF) | |
308 | (lp->DmaRcvPackets << PK_COUNT_RX_B_SHF) | | |
309 | (lp->DmaTxmPackets << PK_COUNT_TX_A_SHF) | | |
310 | (lp->DmaTxmPackets << PK_COUNT_TX_B_SHF), | |
311 | &lp->lan_saa9730_regs->PacketCount); | |
1da177e4 LT |
312 | |
313 | return 0; | |
05d9c84d RB |
314 | |
315 | out: | |
316 | return ret; | |
1da177e4 LT |
317 | } |
318 | ||
319 | static int lan_saa9730_cam_load(struct lan_saa9730_private *lp) | |
320 | { | |
321 | unsigned int i; | |
322 | unsigned char *NetworkAddress; | |
323 | ||
324 | NetworkAddress = (unsigned char *) &lp->PhysicalAddress[0][0]; | |
325 | ||
326 | for (i = 0; i < LAN_SAA9730_CAM_DWORDS; i++) { | |
327 | /* First set address to where data is written */ | |
69a43ac0 RB |
328 | writel(i, &lp->lan_saa9730_regs->CamAddress); |
329 | writel((NetworkAddress[0] << 24) | (NetworkAddress[1] << 16) | | |
330 | (NetworkAddress[2] << 8) | NetworkAddress[3], | |
331 | &lp->lan_saa9730_regs->CamData); | |
1da177e4 LT |
332 | NetworkAddress += 4; |
333 | } | |
334 | return 0; | |
335 | } | |
336 | ||
337 | static int lan_saa9730_cam_init(struct net_device *dev) | |
338 | { | |
05d9c84d | 339 | struct lan_saa9730_private *lp = netdev_priv(dev); |
1da177e4 LT |
340 | unsigned int i; |
341 | ||
342 | /* Copy MAC-address into all entries. */ | |
343 | for (i = 0; i < LAN_SAA9730_CAM_ENTRIES; i++) { | |
344 | memcpy((unsigned char *) lp->PhysicalAddress[i], | |
345 | (unsigned char *) dev->dev_addr, 6); | |
346 | } | |
347 | ||
348 | return 0; | |
349 | } | |
350 | ||
351 | static int lan_saa9730_mii_init(struct lan_saa9730_private *lp) | |
352 | { | |
353 | int i, l; | |
354 | ||
355 | /* Check link status, spin here till station is not busy. */ | |
356 | i = 0; | |
05d9c84d | 357 | while (readl(&lp->lan_saa9730_regs->StationMgmtCtl) & MD_CA_BUSY) { |
1da177e4 LT |
358 | i++; |
359 | if (i > 100) { | |
360 | printk("Error: lan_saa9730_mii_init: timeout\n"); | |
361 | return -1; | |
362 | } | |
363 | mdelay(1); /* wait 1 ms. */ | |
364 | } | |
365 | ||
366 | /* Now set the control and address register. */ | |
69a43ac0 RB |
367 | writel(MD_CA_BUSY | PHY_STATUS | PHY_ADDRESS << MD_CA_PHY_SHF, |
368 | &lp->lan_saa9730_regs->StationMgmtCtl); | |
1da177e4 LT |
369 | |
370 | /* check link status, spin here till station is not busy */ | |
371 | i = 0; | |
05d9c84d | 372 | while (readl(&lp->lan_saa9730_regs->StationMgmtCtl) & MD_CA_BUSY) { |
1da177e4 LT |
373 | i++; |
374 | if (i > 100) { | |
375 | printk("Error: lan_saa9730_mii_init: timeout\n"); | |
376 | return -1; | |
377 | } | |
378 | mdelay(1); /* wait 1 ms. */ | |
379 | } | |
380 | ||
381 | /* Wait for 1 ms. */ | |
382 | mdelay(1); | |
383 | ||
384 | /* Check the link status. */ | |
05d9c84d | 385 | if (readl(&lp->lan_saa9730_regs->StationMgmtData) & |
1da177e4 LT |
386 | PHY_STATUS_LINK_UP) { |
387 | /* Link is up. */ | |
388 | return 0; | |
389 | } else { | |
390 | /* Link is down, reset the PHY first. */ | |
391 | ||
392 | /* set PHY address = 'CONTROL' */ | |
69a43ac0 RB |
393 | writel(PHY_ADDRESS << MD_CA_PHY_SHF | MD_CA_WR | PHY_CONTROL, |
394 | &lp->lan_saa9730_regs->StationMgmtCtl); | |
1da177e4 LT |
395 | |
396 | /* Wait for 1 ms. */ | |
397 | mdelay(1); | |
398 | ||
399 | /* set 'CONTROL' = force reset and renegotiate */ | |
69a43ac0 RB |
400 | writel(PHY_CONTROL_RESET | PHY_CONTROL_AUTO_NEG | |
401 | PHY_CONTROL_RESTART_AUTO_NEG, | |
402 | &lp->lan_saa9730_regs->StationMgmtData); | |
1da177e4 LT |
403 | |
404 | /* Wait for 50 ms. */ | |
405 | mdelay(50); | |
406 | ||
407 | /* set 'BUSY' to start operation */ | |
69a43ac0 RB |
408 | writel(MD_CA_BUSY | PHY_ADDRESS << MD_CA_PHY_SHF | MD_CA_WR | |
409 | PHY_CONTROL, &lp->lan_saa9730_regs->StationMgmtCtl); | |
1da177e4 LT |
410 | |
411 | /* await completion */ | |
412 | i = 0; | |
05d9c84d | 413 | while (readl(&lp->lan_saa9730_regs->StationMgmtCtl) & |
1da177e4 LT |
414 | MD_CA_BUSY) { |
415 | i++; | |
416 | if (i > 100) { | |
417 | printk | |
418 | ("Error: lan_saa9730_mii_init: timeout\n"); | |
419 | return -1; | |
420 | } | |
421 | mdelay(1); /* wait 1 ms. */ | |
422 | } | |
423 | ||
424 | /* Wait for 1 ms. */ | |
425 | mdelay(1); | |
426 | ||
427 | for (l = 0; l < 2; l++) { | |
428 | /* set PHY address = 'STATUS' */ | |
69a43ac0 RB |
429 | writel(MD_CA_BUSY | PHY_ADDRESS << MD_CA_PHY_SHF | |
430 | PHY_STATUS, | |
431 | &lp->lan_saa9730_regs->StationMgmtCtl); | |
1da177e4 LT |
432 | |
433 | /* await completion */ | |
434 | i = 0; | |
05d9c84d | 435 | while (readl(&lp->lan_saa9730_regs->StationMgmtCtl) & |
1da177e4 LT |
436 | MD_CA_BUSY) { |
437 | i++; | |
438 | if (i > 100) { | |
439 | printk | |
440 | ("Error: lan_saa9730_mii_init: timeout\n"); | |
441 | return -1; | |
442 | } | |
443 | mdelay(1); /* wait 1 ms. */ | |
444 | } | |
445 | ||
446 | /* wait for 3 sec. */ | |
447 | mdelay(3000); | |
448 | ||
449 | /* check the link status */ | |
05d9c84d | 450 | if (readl(&lp->lan_saa9730_regs->StationMgmtData) & |
1da177e4 LT |
451 | PHY_STATUS_LINK_UP) { |
452 | /* link is up */ | |
453 | break; | |
454 | } | |
455 | } | |
456 | } | |
457 | ||
458 | return 0; | |
459 | } | |
460 | ||
461 | static int lan_saa9730_control_init(struct lan_saa9730_private *lp) | |
462 | { | |
463 | /* Initialize DMA control register. */ | |
69a43ac0 RB |
464 | writel((LANMB_ANY << DMA_CTL_MAX_XFER_SHF) | |
465 | (LANEND_LITTLE << DMA_CTL_ENDIAN_SHF) | | |
466 | (LAN_SAA9730_RCV_Q_INT_THRESHOLD << DMA_CTL_RX_INT_COUNT_SHF) | |
467 | | DMA_CTL_RX_INT_TO_EN | DMA_CTL_RX_INT_EN | | |
468 | DMA_CTL_MAC_RX_INT_EN | DMA_CTL_MAC_TX_INT_EN, | |
469 | &lp->lan_saa9730_regs->LanDmaCtl); | |
1da177e4 LT |
470 | |
471 | /* Initial MAC control register. */ | |
69a43ac0 RB |
472 | writel((MACCM_MII << MAC_CONTROL_CONN_SHF) | MAC_CONTROL_FULL_DUP, |
473 | &lp->lan_saa9730_regs->MacCtl); | |
1da177e4 LT |
474 | |
475 | /* Initialize CAM control register. */ | |
69a43ac0 RB |
476 | writel(CAM_CONTROL_COMP_EN | CAM_CONTROL_BROAD_ACC, |
477 | &lp->lan_saa9730_regs->CamCtl); | |
1da177e4 | 478 | |
62ff0d0a | 479 | /* |
1da177e4 | 480 | * Initialize CAM enable register, only turn on first entry, should |
62ff0d0a | 481 | * contain own addr. |
1da177e4 | 482 | */ |
69a43ac0 | 483 | writel(0x0001, &lp->lan_saa9730_regs->CamEnable); |
1da177e4 LT |
484 | |
485 | /* Initialize Tx control register */ | |
69a43ac0 | 486 | writel(TX_CTL_EN_COMP, &lp->lan_saa9730_regs->TxCtl); |
1da177e4 LT |
487 | |
488 | /* Initialize Rcv control register */ | |
69a43ac0 | 489 | writel(RX_CTL_STRIP_CRC, &lp->lan_saa9730_regs->RxCtl); |
1da177e4 LT |
490 | |
491 | /* Reset DMA engine */ | |
69a43ac0 | 492 | writel(DMA_TEST_SW_RESET, &lp->lan_saa9730_regs->DmaTest); |
1da177e4 LT |
493 | |
494 | return 0; | |
495 | } | |
496 | ||
497 | static int lan_saa9730_stop(struct lan_saa9730_private *lp) | |
498 | { | |
499 | int i; | |
500 | ||
501 | /* Stop DMA first */ | |
69a43ac0 RB |
502 | writel(readl(&lp->lan_saa9730_regs->LanDmaCtl) & |
503 | ~(DMA_CTL_EN_TX_DMA | DMA_CTL_EN_RX_DMA), | |
504 | &lp->lan_saa9730_regs->LanDmaCtl); | |
1da177e4 LT |
505 | |
506 | /* Set the SW Reset bits in DMA and MAC control registers */ | |
69a43ac0 RB |
507 | writel(DMA_TEST_SW_RESET, &lp->lan_saa9730_regs->DmaTest); |
508 | writel(readl(&lp->lan_saa9730_regs->MacCtl) | MAC_CONTROL_RESET, | |
509 | &lp->lan_saa9730_regs->MacCtl); | |
1da177e4 | 510 | |
62ff0d0a | 511 | /* |
1da177e4 LT |
512 | * Wait for MAC reset to have finished. The reset bit is auto cleared |
513 | * when the reset is done. | |
514 | */ | |
515 | i = 0; | |
05d9c84d | 516 | while (readl(&lp->lan_saa9730_regs->MacCtl) & MAC_CONTROL_RESET) { |
1da177e4 LT |
517 | i++; |
518 | if (i > 100) { | |
519 | printk | |
520 | ("Error: lan_sa9730_stop: MAC reset timeout\n"); | |
521 | return -1; | |
522 | } | |
523 | mdelay(1); /* wait 1 ms. */ | |
524 | } | |
525 | ||
526 | return 0; | |
527 | } | |
528 | ||
529 | static int lan_saa9730_dma_init(struct lan_saa9730_private *lp) | |
530 | { | |
531 | /* Stop lan controller. */ | |
532 | lan_saa9730_stop(lp); | |
533 | ||
69a43ac0 RB |
534 | writel(LAN_SAA9730_DEFAULT_TIME_OUT_CNT, |
535 | &lp->lan_saa9730_regs->Timeout); | |
1da177e4 LT |
536 | |
537 | return 0; | |
538 | } | |
539 | ||
540 | static int lan_saa9730_start(struct lan_saa9730_private *lp) | |
541 | { | |
542 | lan_saa9730_buffer_init(lp); | |
543 | ||
544 | /* Initialize Rx Buffer Index */ | |
545 | lp->NextRcvPacketIndex = 0; | |
05d9c84d | 546 | lp->NextRcvBufferIndex = 0; |
1da177e4 | 547 | |
05d9c84d | 548 | /* Set current buffer index & next available packet index */ |
1da177e4 LT |
549 | lp->NextTxmPacketIndex = 0; |
550 | lp->NextTxmBufferIndex = 0; | |
551 | lp->PendingTxmPacketIndex = 0; | |
552 | lp->PendingTxmBufferIndex = 0; | |
553 | ||
69a43ac0 RB |
554 | writel(readl(&lp->lan_saa9730_regs->LanDmaCtl) | DMA_CTL_EN_TX_DMA | |
555 | DMA_CTL_EN_RX_DMA, &lp->lan_saa9730_regs->LanDmaCtl); | |
1da177e4 LT |
556 | |
557 | /* For Tx, turn on MAC then DMA */ | |
69a43ac0 RB |
558 | writel(readl(&lp->lan_saa9730_regs->TxCtl) | TX_CTL_TX_EN, |
559 | &lp->lan_saa9730_regs->TxCtl); | |
1da177e4 LT |
560 | |
561 | /* For Rx, turn on DMA then MAC */ | |
69a43ac0 RB |
562 | writel(readl(&lp->lan_saa9730_regs->RxCtl) | RX_CTL_RX_EN, |
563 | &lp->lan_saa9730_regs->RxCtl); | |
1da177e4 | 564 | |
05d9c84d | 565 | /* Set Ok2Use to let hardware own the buffers. */ |
69a43ac0 | 566 | writel(OK2USE_RX_A | OK2USE_RX_B, &lp->lan_saa9730_regs->Ok2Use); |
1da177e4 LT |
567 | |
568 | return 0; | |
569 | } | |
570 | ||
571 | static int lan_saa9730_restart(struct lan_saa9730_private *lp) | |
572 | { | |
573 | lan_saa9730_stop(lp); | |
574 | lan_saa9730_start(lp); | |
575 | ||
576 | return 0; | |
577 | } | |
578 | ||
579 | static int lan_saa9730_tx(struct net_device *dev) | |
580 | { | |
05d9c84d | 581 | struct lan_saa9730_private *lp = netdev_priv(dev); |
1da177e4 LT |
582 | unsigned int *pPacket; |
583 | unsigned int tx_status; | |
584 | ||
585 | if (lan_saa9730_debug > 5) | |
586 | printk("lan_saa9730_tx interrupt\n"); | |
587 | ||
588 | /* Clear interrupt. */ | |
69a43ac0 | 589 | writel(DMA_STATUS_MAC_TX_INT, &lp->lan_saa9730_regs->DmaStatus); |
1da177e4 LT |
590 | |
591 | while (1) { | |
05d9c84d RB |
592 | pPacket = lp->TxmBuffer[lp->PendingTxmBufferIndex] |
593 | [lp->PendingTxmPacketIndex]; | |
1da177e4 LT |
594 | |
595 | /* Get status of first packet transmitted. */ | |
596 | tx_status = le32_to_cpu(*pPacket); | |
597 | ||
598 | /* Check ownership. */ | |
599 | if ((tx_status & TX_STAT_CTL_OWNER_MSK) != | |
600 | (TXSF_HWDONE << TX_STAT_CTL_OWNER_SHF)) break; | |
601 | ||
602 | /* Check for error. */ | |
603 | if (tx_status & TX_STAT_CTL_ERROR_MSK) { | |
604 | if (lan_saa9730_debug > 1) | |
605 | printk("lan_saa9730_tx: tx error = %x\n", | |
606 | tx_status); | |
607 | ||
09f75cd7 | 608 | dev->stats.tx_errors++; |
1da177e4 LT |
609 | if (tx_status & |
610 | (TX_STATUS_EX_COLL << TX_STAT_CTL_STATUS_SHF)) | |
09f75cd7 | 611 | dev->stats.tx_aborted_errors++; |
1da177e4 | 612 | if (tx_status & |
05d9c84d | 613 | (TX_STATUS_LATE_COLL << TX_STAT_CTL_STATUS_SHF)) |
09f75cd7 | 614 | dev->stats.tx_window_errors++; |
1da177e4 LT |
615 | if (tx_status & |
616 | (TX_STATUS_L_CARR << TX_STAT_CTL_STATUS_SHF)) | |
09f75cd7 | 617 | dev->stats.tx_carrier_errors++; |
1da177e4 LT |
618 | if (tx_status & |
619 | (TX_STATUS_UNDER << TX_STAT_CTL_STATUS_SHF)) | |
09f75cd7 | 620 | dev->stats.tx_fifo_errors++; |
1da177e4 LT |
621 | if (tx_status & |
622 | (TX_STATUS_SQ_ERR << TX_STAT_CTL_STATUS_SHF)) | |
09f75cd7 | 623 | dev->stats.tx_heartbeat_errors++; |
1da177e4 | 624 | |
09f75cd7 | 625 | dev->stats.collisions += |
05d9c84d | 626 | tx_status & TX_STATUS_TX_COLL_MSK; |
1da177e4 LT |
627 | } |
628 | ||
629 | /* Free buffer. */ | |
630 | *pPacket = | |
631 | cpu_to_le32(TXSF_EMPTY << TX_STAT_CTL_OWNER_SHF); | |
632 | ||
633 | /* Update pending index pointer. */ | |
634 | lp->PendingTxmPacketIndex++; | |
635 | if (lp->PendingTxmPacketIndex >= LAN_SAA9730_TXM_Q_SIZE) { | |
636 | lp->PendingTxmPacketIndex = 0; | |
637 | lp->PendingTxmBufferIndex ^= 1; | |
638 | } | |
639 | } | |
640 | ||
05d9c84d RB |
641 | /* The tx buffer is no longer full. */ |
642 | netif_wake_queue(dev); | |
1da177e4 LT |
643 | |
644 | return 0; | |
645 | } | |
646 | ||
647 | static int lan_saa9730_rx(struct net_device *dev) | |
648 | { | |
05d9c84d | 649 | struct lan_saa9730_private *lp = netdev_priv(dev); |
1da177e4 LT |
650 | int len = 0; |
651 | struct sk_buff *skb = 0; | |
652 | unsigned int rx_status; | |
653 | int BufferIndex; | |
654 | int PacketIndex; | |
655 | unsigned int *pPacket; | |
656 | unsigned char *pData; | |
657 | ||
658 | if (lan_saa9730_debug > 5) | |
659 | printk("lan_saa9730_rx interrupt\n"); | |
660 | ||
661 | /* Clear receive interrupts. */ | |
69a43ac0 RB |
662 | writel(DMA_STATUS_MAC_RX_INT | DMA_STATUS_RX_INT | |
663 | DMA_STATUS_RX_TO_INT, &lp->lan_saa9730_regs->DmaStatus); | |
1da177e4 LT |
664 | |
665 | /* Address next packet */ | |
05d9c84d | 666 | BufferIndex = lp->NextRcvBufferIndex; |
1da177e4 | 667 | PacketIndex = lp->NextRcvPacketIndex; |
05d9c84d | 668 | pPacket = lp->RcvBuffer[BufferIndex][PacketIndex]; |
1da177e4 LT |
669 | rx_status = le32_to_cpu(*pPacket); |
670 | ||
671 | /* Process each packet. */ | |
672 | while ((rx_status & RX_STAT_CTL_OWNER_MSK) == | |
673 | (RXSF_HWDONE << RX_STAT_CTL_OWNER_SHF)) { | |
674 | /* Check the rx status. */ | |
675 | if (rx_status & (RX_STATUS_GOOD << RX_STAT_CTL_STATUS_SHF)) { | |
676 | /* Received packet is good. */ | |
677 | len = (rx_status & RX_STAT_CTL_LENGTH_MSK) >> | |
678 | RX_STAT_CTL_LENGTH_SHF; | |
679 | ||
680 | pData = (unsigned char *) pPacket; | |
681 | pData += 4; | |
682 | skb = dev_alloc_skb(len + 2); | |
683 | if (skb == 0) { | |
684 | printk | |
685 | ("%s: Memory squeeze, deferring packet.\n", | |
686 | dev->name); | |
09f75cd7 | 687 | dev->stats.rx_dropped++; |
1da177e4 | 688 | } else { |
09f75cd7 JG |
689 | dev->stats.rx_bytes += len; |
690 | dev->stats.rx_packets++; | |
1da177e4 LT |
691 | skb_reserve(skb, 2); /* 16 byte align */ |
692 | skb_put(skb, len); /* make room */ | |
8c7b7faa | 693 | skb_copy_to_linear_data(skb, |
1da177e4 | 694 | (unsigned char *) pData, |
8c7b7faa | 695 | len); |
1da177e4 LT |
696 | skb->protocol = eth_type_trans(skb, dev); |
697 | netif_rx(skb); | |
698 | dev->last_rx = jiffies; | |
699 | } | |
700 | } else { | |
701 | /* We got an error packet. */ | |
702 | if (lan_saa9730_debug > 2) | |
703 | printk | |
704 | ("lan_saa9730_rx: We got an error packet = %x\n", | |
705 | rx_status); | |
706 | ||
09f75cd7 | 707 | dev->stats.rx_errors++; |
1da177e4 LT |
708 | if (rx_status & |
709 | (RX_STATUS_CRC_ERR << RX_STAT_CTL_STATUS_SHF)) | |
09f75cd7 | 710 | dev->stats.rx_crc_errors++; |
1da177e4 | 711 | if (rx_status & |
05d9c84d | 712 | (RX_STATUS_ALIGN_ERR << RX_STAT_CTL_STATUS_SHF)) |
09f75cd7 | 713 | dev->stats.rx_frame_errors++; |
1da177e4 LT |
714 | if (rx_status & |
715 | (RX_STATUS_OVERFLOW << RX_STAT_CTL_STATUS_SHF)) | |
09f75cd7 | 716 | dev->stats.rx_fifo_errors++; |
1da177e4 LT |
717 | if (rx_status & |
718 | (RX_STATUS_LONG_ERR << RX_STAT_CTL_STATUS_SHF)) | |
09f75cd7 | 719 | dev->stats.rx_length_errors++; |
1da177e4 LT |
720 | } |
721 | ||
722 | /* Indicate we have processed the buffer. */ | |
05d9c84d RB |
723 | *pPacket = cpu_to_le32(RXSF_READY << RX_STAT_CTL_OWNER_SHF); |
724 | ||
725 | /* Make sure A or B is available to hardware as appropriate. */ | |
69a43ac0 RB |
726 | writel(BufferIndex ? OK2USE_RX_B : OK2USE_RX_A, |
727 | &lp->lan_saa9730_regs->Ok2Use); | |
1da177e4 LT |
728 | |
729 | /* Go to next packet in sequence. */ | |
730 | lp->NextRcvPacketIndex++; | |
731 | if (lp->NextRcvPacketIndex >= LAN_SAA9730_RCV_Q_SIZE) { | |
732 | lp->NextRcvPacketIndex = 0; | |
05d9c84d | 733 | lp->NextRcvBufferIndex ^= 1; |
1da177e4 | 734 | } |
1da177e4 LT |
735 | |
736 | /* Address next packet */ | |
05d9c84d | 737 | BufferIndex = lp->NextRcvBufferIndex; |
1da177e4 | 738 | PacketIndex = lp->NextRcvPacketIndex; |
05d9c84d | 739 | pPacket = lp->RcvBuffer[BufferIndex][PacketIndex]; |
1da177e4 LT |
740 | rx_status = le32_to_cpu(*pPacket); |
741 | } | |
742 | ||
1da177e4 LT |
743 | return 0; |
744 | } | |
745 | ||
7d12e780 | 746 | static irqreturn_t lan_saa9730_interrupt(const int irq, void *dev_id) |
1da177e4 | 747 | { |
c31f28e7 | 748 | struct net_device *dev = dev_id; |
05d9c84d | 749 | struct lan_saa9730_private *lp = netdev_priv(dev); |
1da177e4 LT |
750 | |
751 | if (lan_saa9730_debug > 5) | |
752 | printk("lan_saa9730_interrupt\n"); | |
753 | ||
754 | /* Disable the EVM LAN interrupt. */ | |
755 | evm_saa9730_block_lan_int(lp); | |
756 | ||
757 | /* Clear the EVM LAN interrupt. */ | |
758 | evm_saa9730_clear_lan_int(lp); | |
759 | ||
760 | /* Service pending transmit interrupts. */ | |
05d9c84d | 761 | if (readl(&lp->lan_saa9730_regs->DmaStatus) & DMA_STATUS_MAC_TX_INT) |
1da177e4 LT |
762 | lan_saa9730_tx(dev); |
763 | ||
764 | /* Service pending receive interrupts. */ | |
05d9c84d | 765 | if (readl(&lp->lan_saa9730_regs->DmaStatus) & |
1da177e4 LT |
766 | (DMA_STATUS_MAC_RX_INT | DMA_STATUS_RX_INT | |
767 | DMA_STATUS_RX_TO_INT)) lan_saa9730_rx(dev); | |
768 | ||
769 | /* Enable the EVM LAN interrupt. */ | |
770 | evm_saa9730_unblock_lan_int(lp); | |
771 | ||
772 | return IRQ_HANDLED; | |
773 | } | |
774 | ||
1da177e4 LT |
775 | static int lan_saa9730_open(struct net_device *dev) |
776 | { | |
05d9c84d | 777 | struct lan_saa9730_private *lp = netdev_priv(dev); |
1da177e4 LT |
778 | |
779 | /* Associate IRQ with lan_saa9730_interrupt */ | |
780 | if (request_irq(dev->irq, &lan_saa9730_interrupt, 0, "SAA9730 Eth", | |
781 | dev)) { | |
782 | printk("lan_saa9730_open: Can't get irq %d\n", dev->irq); | |
783 | return -EAGAIN; | |
784 | } | |
785 | ||
786 | /* Enable the Lan interrupt in the event manager. */ | |
787 | evm_saa9730_enable_lan_int(lp); | |
788 | ||
789 | /* Start the LAN controller */ | |
790 | if (lan_saa9730_start(lp)) | |
791 | return -1; | |
792 | ||
793 | netif_start_queue(dev); | |
794 | ||
795 | return 0; | |
796 | } | |
797 | ||
798 | static int lan_saa9730_write(struct lan_saa9730_private *lp, | |
799 | struct sk_buff *skb, int skblen) | |
800 | { | |
801 | unsigned char *pbData = skb->data; | |
802 | unsigned int len = skblen; | |
803 | unsigned char *pbPacketData; | |
804 | unsigned int tx_status; | |
805 | int BufferIndex; | |
806 | int PacketIndex; | |
807 | ||
808 | if (lan_saa9730_debug > 5) | |
05d9c84d | 809 | printk("lan_saa9730_write: skb=%p\n", skb); |
1da177e4 LT |
810 | |
811 | BufferIndex = lp->NextTxmBufferIndex; | |
812 | PacketIndex = lp->NextTxmPacketIndex; | |
813 | ||
05d9c84d RB |
814 | tx_status = le32_to_cpu(*(unsigned int *)lp->TxmBuffer[BufferIndex] |
815 | [PacketIndex]); | |
1da177e4 LT |
816 | if ((tx_status & TX_STAT_CTL_OWNER_MSK) != |
817 | (TXSF_EMPTY << TX_STAT_CTL_OWNER_SHF)) { | |
818 | if (lan_saa9730_debug > 4) | |
819 | printk | |
820 | ("lan_saa9730_write: Tx buffer not available: tx_status = %x\n", | |
821 | tx_status); | |
822 | return -1; | |
823 | } | |
824 | ||
825 | lp->NextTxmPacketIndex++; | |
826 | if (lp->NextTxmPacketIndex >= LAN_SAA9730_TXM_Q_SIZE) { | |
827 | lp->NextTxmPacketIndex = 0; | |
828 | lp->NextTxmBufferIndex ^= 1; | |
829 | } | |
830 | ||
05d9c84d | 831 | pbPacketData = lp->TxmBuffer[BufferIndex][PacketIndex]; |
1da177e4 LT |
832 | pbPacketData += 4; |
833 | ||
834 | /* copy the bits */ | |
835 | memcpy(pbPacketData, pbData, len); | |
836 | ||
837 | /* Set transmit status for hardware */ | |
05d9c84d RB |
838 | *(unsigned int *)lp->TxmBuffer[BufferIndex][PacketIndex] = |
839 | cpu_to_le32((TXSF_READY << TX_STAT_CTL_OWNER_SHF) | | |
840 | (TX_STAT_CTL_INT_AFTER_TX << | |
841 | TX_STAT_CTL_FRAME_SHF) | | |
842 | (len << TX_STAT_CTL_LENGTH_SHF)); | |
843 | ||
844 | /* Make sure A or B is available to hardware as appropriate. */ | |
69a43ac0 RB |
845 | writel(BufferIndex ? OK2USE_TX_B : OK2USE_TX_A, |
846 | &lp->lan_saa9730_regs->Ok2Use); | |
1da177e4 LT |
847 | |
848 | return 0; | |
849 | } | |
850 | ||
851 | static void lan_saa9730_tx_timeout(struct net_device *dev) | |
852 | { | |
05d9c84d | 853 | struct lan_saa9730_private *lp = netdev_priv(dev); |
1da177e4 LT |
854 | |
855 | /* Transmitter timeout, serious problems */ | |
09f75cd7 | 856 | dev->stats.tx_errors++; |
1da177e4 LT |
857 | printk("%s: transmit timed out, reset\n", dev->name); |
858 | /*show_saa9730_regs(lp); */ | |
859 | lan_saa9730_restart(lp); | |
860 | ||
861 | dev->trans_start = jiffies; | |
05d9c84d | 862 | netif_wake_queue(dev); |
1da177e4 LT |
863 | } |
864 | ||
865 | static int lan_saa9730_start_xmit(struct sk_buff *skb, | |
866 | struct net_device *dev) | |
867 | { | |
05d9c84d | 868 | struct lan_saa9730_private *lp = netdev_priv(dev); |
1da177e4 LT |
869 | unsigned long flags; |
870 | int skblen; | |
871 | int len; | |
872 | ||
873 | if (lan_saa9730_debug > 4) | |
05d9c84d | 874 | printk("Send packet: skb=%p\n", skb); |
1da177e4 LT |
875 | |
876 | skblen = skb->len; | |
877 | ||
878 | spin_lock_irqsave(&lp->lock, flags); | |
879 | ||
880 | len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen; | |
881 | ||
882 | if (lan_saa9730_write(lp, skb, skblen)) { | |
883 | spin_unlock_irqrestore(&lp->lock, flags); | |
05d9c84d | 884 | printk("Error when writing packet to controller: skb=%p\n", skb); |
1da177e4 LT |
885 | netif_stop_queue(dev); |
886 | return -1; | |
887 | } | |
888 | ||
09f75cd7 JG |
889 | dev->stats.tx_bytes += len; |
890 | dev->stats.tx_packets++; | |
1da177e4 LT |
891 | |
892 | dev->trans_start = jiffies; | |
05d9c84d | 893 | netif_wake_queue(dev); |
1da177e4 LT |
894 | dev_kfree_skb(skb); |
895 | ||
896 | spin_unlock_irqrestore(&lp->lock, flags); | |
897 | ||
898 | return 0; | |
899 | } | |
900 | ||
901 | static int lan_saa9730_close(struct net_device *dev) | |
902 | { | |
05d9c84d | 903 | struct lan_saa9730_private *lp = netdev_priv(dev); |
1da177e4 LT |
904 | |
905 | if (lan_saa9730_debug > 1) | |
906 | printk("lan_saa9730_close:\n"); | |
907 | ||
908 | netif_stop_queue(dev); | |
909 | ||
910 | /* Disable the Lan interrupt in the event manager. */ | |
911 | evm_saa9730_disable_lan_int(lp); | |
912 | ||
913 | /* Stop the controller */ | |
914 | if (lan_saa9730_stop(lp)) | |
915 | return -1; | |
916 | ||
917 | free_irq(dev->irq, (void *) dev); | |
918 | ||
919 | return 0; | |
920 | } | |
921 | ||
1da177e4 LT |
922 | static void lan_saa9730_set_multicast(struct net_device *dev) |
923 | { | |
05d9c84d | 924 | struct lan_saa9730_private *lp = netdev_priv(dev); |
1da177e4 LT |
925 | |
926 | /* Stop the controller */ | |
927 | lan_saa9730_stop(lp); | |
928 | ||
929 | if (dev->flags & IFF_PROMISC) { | |
930 | /* accept all packets */ | |
69a43ac0 RB |
931 | writel(CAM_CONTROL_COMP_EN | CAM_CONTROL_STATION_ACC | |
932 | CAM_CONTROL_GROUP_ACC | CAM_CONTROL_BROAD_ACC, | |
933 | &lp->lan_saa9730_regs->CamCtl); | |
1da177e4 | 934 | } else { |
82a0244d | 935 | if (dev->flags & IFF_ALLMULTI || dev->mc_count) { |
1da177e4 | 936 | /* accept all multicast packets */ |
62ff0d0a | 937 | /* |
1da177e4 LT |
938 | * Will handle the multicast stuff later. -carstenl |
939 | */ | |
82a0244d YH |
940 | writel(CAM_CONTROL_COMP_EN | CAM_CONTROL_GROUP_ACC | |
941 | CAM_CONTROL_BROAD_ACC, | |
942 | &lp->lan_saa9730_regs->CamCtl); | |
1da177e4 LT |
943 | } |
944 | } | |
945 | ||
946 | lan_saa9730_restart(lp); | |
947 | } | |
948 | ||
949 | ||
950 | static void __devexit saa9730_remove_one(struct pci_dev *pdev) | |
951 | { | |
62ff0d0a | 952 | struct net_device *dev = pci_get_drvdata(pdev); |
05d9c84d | 953 | struct lan_saa9730_private *lp = netdev_priv(dev); |
1da177e4 | 954 | |
62ff0d0a RB |
955 | if (dev) { |
956 | unregister_netdev(dev); | |
05d9c84d RB |
957 | lan_saa9730_free_buffers(pdev, lp); |
958 | iounmap(lp->lan_saa9730_regs); | |
959 | iounmap(lp->evm_saa9730_regs); | |
62ff0d0a RB |
960 | free_netdev(dev); |
961 | pci_release_regions(pdev); | |
962 | pci_disable_device(pdev); | |
963 | pci_set_drvdata(pdev, NULL); | |
964 | } | |
1da177e4 LT |
965 | } |
966 | ||
967 | ||
05d9c84d RB |
968 | static int lan_saa9730_init(struct net_device *dev, struct pci_dev *pdev, |
969 | unsigned long ioaddr, int irq) | |
1da177e4 | 970 | { |
05d9c84d | 971 | struct lan_saa9730_private *lp = netdev_priv(dev); |
1da177e4 | 972 | unsigned char ethernet_addr[6]; |
05d9c84d | 973 | int ret; |
1da177e4 | 974 | |
05d9c84d RB |
975 | if (get_ethernet_addr(ethernet_addr)) { |
976 | ret = -ENODEV; | |
977 | goto out; | |
978 | } | |
62ff0d0a | 979 | |
1da177e4 LT |
980 | memcpy(dev->dev_addr, ethernet_addr, 6); |
981 | dev->base_addr = ioaddr; | |
982 | dev->irq = irq; | |
62ff0d0a | 983 | |
05d9c84d | 984 | lp->pci_dev = pdev; |
1da177e4 LT |
985 | |
986 | /* Set SAA9730 LAN base address. */ | |
05d9c84d RB |
987 | lp->lan_saa9730_regs = ioremap(ioaddr + SAA9730_LAN_REGS_ADDR, |
988 | SAA9730_LAN_REGS_SIZE); | |
989 | if (!lp->lan_saa9730_regs) { | |
990 | ret = -ENOMEM; | |
991 | goto out; | |
992 | } | |
1da177e4 LT |
993 | |
994 | /* Set SAA9730 EVM base address. */ | |
05d9c84d RB |
995 | lp->evm_saa9730_regs = ioremap(ioaddr + SAA9730_EVM_REGS_ADDR, |
996 | SAA9730_EVM_REGS_SIZE); | |
997 | if (!lp->evm_saa9730_regs) { | |
998 | ret = -ENOMEM; | |
999 | goto out_iounmap_lan; | |
1000 | } | |
1da177e4 LT |
1001 | |
1002 | /* Allocate LAN RX/TX frame buffer space. */ | |
05d9c84d RB |
1003 | if ((ret = lan_saa9730_allocate_buffers(pdev, lp))) |
1004 | goto out_iounmap; | |
1da177e4 LT |
1005 | |
1006 | /* Stop LAN controller. */ | |
62ff0d0a | 1007 | if ((ret = lan_saa9730_stop(lp))) |
05d9c84d | 1008 | goto out_free_consistent; |
62ff0d0a | 1009 | |
1da177e4 LT |
1010 | /* Initialize CAM registers. */ |
1011 | if ((ret = lan_saa9730_cam_init(dev))) | |
05d9c84d | 1012 | goto out_free_consistent; |
1da177e4 LT |
1013 | |
1014 | /* Initialize MII registers. */ | |
1015 | if ((ret = lan_saa9730_mii_init(lp))) | |
05d9c84d | 1016 | goto out_free_consistent; |
1da177e4 LT |
1017 | |
1018 | /* Initialize control registers. */ | |
62ff0d0a | 1019 | if ((ret = lan_saa9730_control_init(lp))) |
05d9c84d | 1020 | goto out_free_consistent; |
62ff0d0a | 1021 | |
1da177e4 | 1022 | /* Load CAM registers. */ |
62ff0d0a | 1023 | if ((ret = lan_saa9730_cam_load(lp))) |
05d9c84d | 1024 | goto out_free_consistent; |
62ff0d0a | 1025 | |
1da177e4 LT |
1026 | /* Initialize DMA context registers. */ |
1027 | if ((ret = lan_saa9730_dma_init(lp))) | |
05d9c84d | 1028 | goto out_free_consistent; |
62ff0d0a | 1029 | |
1da177e4 | 1030 | spin_lock_init(&lp->lock); |
62ff0d0a | 1031 | |
1da177e4 LT |
1032 | dev->open = lan_saa9730_open; |
1033 | dev->hard_start_xmit = lan_saa9730_start_xmit; | |
1034 | dev->stop = lan_saa9730_close; | |
1da177e4 LT |
1035 | dev->set_multicast_list = lan_saa9730_set_multicast; |
1036 | dev->tx_timeout = lan_saa9730_tx_timeout; | |
1037 | dev->watchdog_timeo = (HZ >> 1); | |
1038 | dev->dma = 0; | |
62ff0d0a | 1039 | |
05d9c84d | 1040 | ret = register_netdev (dev); |
1da177e4 | 1041 | if (ret) |
05d9c84d RB |
1042 | goto out_free_consistent; |
1043 | ||
1da177e4 LT |
1044 | return 0; |
1045 | ||
05d9c84d RB |
1046 | out_free_consistent: |
1047 | lan_saa9730_free_buffers(pdev, lp); | |
1048 | out_iounmap: | |
1049 | iounmap(lp->evm_saa9730_regs); | |
1050 | out_iounmap_lan: | |
1051 | iounmap(lp->lan_saa9730_regs); | |
1052 | out: | |
1da177e4 LT |
1053 | return ret; |
1054 | } | |
1055 | ||
1056 | ||
1057 | static int __devinit saa9730_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |
1058 | { | |
05d9c84d RB |
1059 | struct net_device *dev = NULL; |
1060 | unsigned long pci_ioaddr; | |
1da177e4 LT |
1061 | int err; |
1062 | ||
1063 | if (lan_saa9730_debug > 1) | |
1064 | printk("saa9730.c: PCI bios is present, checking for devices...\n"); | |
1065 | ||
1da177e4 | 1066 | err = pci_enable_device(pdev); |
62ff0d0a RB |
1067 | if (err) { |
1068 | printk(KERN_ERR "Cannot enable PCI device, aborting.\n"); | |
05d9c84d | 1069 | goto out; |
62ff0d0a | 1070 | } |
1da177e4 LT |
1071 | |
1072 | err = pci_request_regions(pdev, DRV_MODULE_NAME); | |
1073 | if (err) { | |
1074 | printk(KERN_ERR "Cannot obtain PCI resources, aborting.\n"); | |
05d9c84d | 1075 | goto out_disable_pdev; |
1da177e4 LT |
1076 | } |
1077 | ||
1078 | pci_irq_line = pdev->irq; | |
1079 | /* LAN base address in located at BAR 1. */ | |
1080 | ||
1081 | pci_ioaddr = pci_resource_start(pdev, 1); | |
1082 | pci_set_master(pdev); | |
1083 | ||
05d9c84d | 1084 | printk("Found SAA9730 (PCI) at %lx, irq %d.\n", |
1da177e4 LT |
1085 | pci_ioaddr, pci_irq_line); |
1086 | ||
05d9c84d RB |
1087 | dev = alloc_etherdev(sizeof(struct lan_saa9730_private)); |
1088 | if (!dev) | |
1089 | goto out_disable_pdev; | |
1090 | ||
1091 | err = lan_saa9730_init(dev, pdev, pci_ioaddr, pci_irq_line); | |
1da177e4 | 1092 | if (err) { |
05d9c84d RB |
1093 | printk("LAN init failed"); |
1094 | goto out_free_netdev; | |
1da177e4 LT |
1095 | } |
1096 | ||
1097 | pci_set_drvdata(pdev, dev); | |
1098 | SET_NETDEV_DEV(dev, &pdev->dev); | |
1099 | return 0; | |
62ff0d0a | 1100 | |
05d9c84d | 1101 | out_free_netdev: |
1da177e4 | 1102 | free_netdev(dev); |
05d9c84d RB |
1103 | out_disable_pdev: |
1104 | pci_disable_device(pdev); | |
1da177e4 | 1105 | out: |
05d9c84d | 1106 | pci_set_drvdata(pdev, NULL); |
1da177e4 LT |
1107 | return err; |
1108 | } | |
1109 | ||
1110 | ||
1111 | static struct pci_driver saa9730_driver = { | |
62ff0d0a RB |
1112 | .name = DRV_MODULE_NAME, |
1113 | .id_table = saa9730_pci_tbl, | |
1114 | .probe = saa9730_init_one, | |
1115 | .remove = __devexit_p(saa9730_remove_one), | |
1da177e4 LT |
1116 | }; |
1117 | ||
1118 | ||
1119 | static int __init saa9730_init(void) | |
1120 | { | |
29917620 | 1121 | return pci_register_driver(&saa9730_driver); |
1da177e4 LT |
1122 | } |
1123 | ||
1124 | static void __exit saa9730_cleanup(void) | |
1125 | { | |
62ff0d0a | 1126 | pci_unregister_driver(&saa9730_driver); |
1da177e4 LT |
1127 | } |
1128 | ||
1129 | module_init(saa9730_init); | |
1130 | module_exit(saa9730_cleanup); | |
1131 | ||
05d9c84d RB |
1132 | MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>"); |
1133 | MODULE_DESCRIPTION("Philips SAA9730 ethernet driver"); | |
1da177e4 | 1134 | MODULE_LICENSE("GPL"); |