1 | /* |
---|
2 | sis190.c: Silicon Integrated Systems SiS190 ethernet driver |
---|
3 | |
---|
4 | Copyright (c) 2003 K.M. Liu <kmliu@sis.com> |
---|
5 | Copyright (c) 2003, 2004 Jeff Garzik <jgarzik@pobox.com> |
---|
6 | Copyright (c) 2003, 2004, 2005 Francois Romieu <romieu@fr.zoreil.com> |
---|
7 | |
---|
8 | Modified for gPXE 2009 by Thomas Miletich <thomas.miletich@gmail.com> |
---|
9 | |
---|
10 | Based on r8169.c, tg3.c, 8139cp.c, skge.c, epic100.c and SiS 190/191 |
---|
11 | genuine driver. |
---|
12 | |
---|
13 | This software may be used and distributed according to the terms of |
---|
14 | the GNU General Public License (GPL), incorporated herein by reference. |
---|
15 | Drivers based on or derived from this code fall under the GPL and must |
---|
16 | retain the authorship, copyright and license notice. This file is not |
---|
17 | a complete program and may only be used when the entire operating |
---|
18 | system is licensed under the GPL. |
---|
19 | |
---|
20 | See the file COPYING in this distribution for more information. |
---|
21 | |
---|
22 | */ |
---|
23 | |
---|
24 | FILE_LICENCE ( GPL_ANY ); |
---|
25 | |
---|
26 | #include "sis190.h" |
---|
27 | |
---|
28 | static struct pci_device_id sis190_pci_tbl[] = { |
---|
29 | PCI_ROM (0x1039, 0x0190, "sis190", "sis190", 0), |
---|
30 | PCI_ROM (0x1039, 0x0191, "sis191", "sis191", 0), |
---|
31 | }; |
---|
32 | |
---|
33 | /****************************************************************************** |
---|
34 | *************** HACK to keep ISA bridge in the PCI device list *************** |
---|
35 | ******************************************************************************/ |
---|
36 | |
---|
37 | /* Some sis190 variants store the MAC address in the BIOS CMOS. To read it, we |
---|
38 | * have to use a PCI to ISA bridge. To access the bridge we need a few things |
---|
39 | * from it's struct pci_device. We fake the successful probe of a driver to |
---|
40 | * keep the bridge's struct pci_device in the list of pci_devices. |
---|
41 | * See details in sis190_get_mac_addr_from_apc(). |
---|
42 | */ |
---|
43 | |
---|
44 | static struct pci_device_id sis190_isa_bridge_tbl[] = { |
---|
45 | PCI_ID (0x1039, 0x0965, "", "", 0), |
---|
46 | PCI_ID (0x1039, 0x0966, "", "", 0), |
---|
47 | PCI_ID (0x1039, 0x0968, "", "", 0), |
---|
48 | }; |
---|
49 | |
---|
50 | static int sis190_isa_bridge_probe(struct pci_device *pdev __unused, |
---|
51 | const struct pci_device_id *ent __unused) |
---|
52 | { |
---|
53 | return 0; |
---|
54 | } |
---|
55 | |
---|
56 | static void sis190_isa_bridge_remove(struct pci_device *pdev __unused) |
---|
57 | { |
---|
58 | return; |
---|
59 | } |
---|
60 | |
---|
61 | struct pci_driver sis190_isa_bridge_driver __pci_driver = { |
---|
62 | .ids = sis190_isa_bridge_tbl, |
---|
63 | .id_count = (sizeof(sis190_isa_bridge_tbl) / |
---|
64 | sizeof(sis190_isa_bridge_tbl[0])), |
---|
65 | .probe = sis190_isa_bridge_probe, |
---|
66 | .remove = sis190_isa_bridge_remove, |
---|
67 | }; |
---|
68 | |
---|
69 | /****************************************************************************** |
---|
70 | *********************************** </HACK> ********************************** |
---|
71 | ******************************************************************************/ |
---|
72 | |
---|
73 | static const u32 sis190_intr_mask = |
---|
74 | RxQEmpty | RxQInt | TxQ1Int | TxQ0Int | RxHalt | TxHalt | LinkChange; |
---|
75 | |
---|
76 | /* |
---|
77 | * Maximum number of multicast addresses to filter (vs. Rx-all-multicast). |
---|
78 | * The chips use a 64 element hash table based on the Ethernet CRC. |
---|
79 | */ |
---|
80 | static const int multicast_filter_limit = 32; |
---|
81 | |
---|
82 | static void __mdio_cmd(void *ioaddr, u32 ctl) |
---|
83 | { |
---|
84 | unsigned int i; |
---|
85 | |
---|
86 | SIS_W32(GMIIControl, ctl); |
---|
87 | |
---|
88 | mdelay(1); |
---|
89 | |
---|
90 | for (i = 0; i < 100; i++) { |
---|
91 | if (!(SIS_R32(GMIIControl) & EhnMIInotDone)) |
---|
92 | break; |
---|
93 | mdelay(1); |
---|
94 | } |
---|
95 | |
---|
96 | if (i > 99) |
---|
97 | DBG("sis190: PHY command timed out !\n"); |
---|
98 | } |
---|
99 | |
---|
100 | static void mdio_write(void *ioaddr, int phy_id, int reg, int val) |
---|
101 | { |
---|
102 | __mdio_cmd(ioaddr, EhnMIIreq | EhnMIIwrite | |
---|
103 | (((u32) reg) << EhnMIIregShift) | (phy_id << EhnMIIpmdShift) | |
---|
104 | (((u32) val) << EhnMIIdataShift)); |
---|
105 | } |
---|
106 | |
---|
107 | static int mdio_read(void *ioaddr, int phy_id, int reg) |
---|
108 | { |
---|
109 | __mdio_cmd(ioaddr, EhnMIIreq | EhnMIIread | |
---|
110 | (((u32) reg) << EhnMIIregShift) | (phy_id << EhnMIIpmdShift)); |
---|
111 | |
---|
112 | return (u16) (SIS_R32(GMIIControl) >> EhnMIIdataShift); |
---|
113 | } |
---|
114 | |
---|
115 | static void __mdio_write(struct net_device *dev, int phy_id, int reg, int val) |
---|
116 | { |
---|
117 | struct sis190_private *tp = netdev_priv(dev); |
---|
118 | |
---|
119 | mdio_write(tp->mmio_addr, phy_id, reg, val); |
---|
120 | } |
---|
121 | |
---|
122 | static int __mdio_read(struct net_device *dev, int phy_id, int reg) |
---|
123 | { |
---|
124 | struct sis190_private *tp = netdev_priv(dev); |
---|
125 | |
---|
126 | return mdio_read(tp->mmio_addr, phy_id, reg); |
---|
127 | } |
---|
128 | |
---|
129 | static u16 mdio_read_latched(void *ioaddr, int phy_id, int reg) |
---|
130 | { |
---|
131 | mdio_read(ioaddr, phy_id, reg); |
---|
132 | return mdio_read(ioaddr, phy_id, reg); |
---|
133 | } |
---|
134 | |
---|
135 | static u16 sis190_read_eeprom(void *ioaddr, u32 reg) |
---|
136 | { |
---|
137 | u16 data = 0xffff; |
---|
138 | unsigned int i; |
---|
139 | |
---|
140 | if (!(SIS_R32(ROMControl) & 0x0002)) |
---|
141 | return 0; |
---|
142 | |
---|
143 | SIS_W32(ROMInterface, EEREQ | EEROP | (reg << 10)); |
---|
144 | |
---|
145 | for (i = 0; i < 200; i++) { |
---|
146 | if (!(SIS_R32(ROMInterface) & EEREQ)) { |
---|
147 | data = (SIS_R32(ROMInterface) & 0xffff0000) >> 16; |
---|
148 | break; |
---|
149 | } |
---|
150 | mdelay(1); |
---|
151 | } |
---|
152 | |
---|
153 | return data; |
---|
154 | } |
---|
155 | |
---|
156 | static void sis190_irq_mask_and_ack(void *ioaddr) |
---|
157 | { |
---|
158 | SIS_W32(IntrMask, 0x00); |
---|
159 | SIS_W32(IntrStatus, 0xffffffff); |
---|
160 | SIS_PCI_COMMIT(); |
---|
161 | } |
---|
162 | |
---|
163 | static void sis190_asic_down(void *ioaddr) |
---|
164 | { |
---|
165 | /* Stop the chip's Tx and Rx DMA processes. */ |
---|
166 | |
---|
167 | SIS_W32(TxControl, 0x1a00); |
---|
168 | SIS_W32(RxControl, 0x1a00); |
---|
169 | |
---|
170 | sis190_irq_mask_and_ack(ioaddr); |
---|
171 | } |
---|
172 | |
---|
173 | static inline void sis190_mark_as_last_descriptor(struct RxDesc *desc) |
---|
174 | { |
---|
175 | desc->size |= cpu_to_le32(RingEnd); |
---|
176 | } |
---|
177 | |
---|
178 | static inline void sis190_give_to_asic(struct RxDesc *desc) |
---|
179 | { |
---|
180 | u32 eor = le32_to_cpu(desc->size) & RingEnd; |
---|
181 | |
---|
182 | desc->PSize = 0x0; |
---|
183 | desc->size = cpu_to_le32((RX_BUF_SIZE & RX_BUF_MASK) | eor); |
---|
184 | wmb(); |
---|
185 | desc->status = cpu_to_le32(OWNbit | INTbit); |
---|
186 | } |
---|
187 | |
---|
188 | static inline void sis190_map_to_asic(struct RxDesc *desc, u32 mapping) |
---|
189 | { |
---|
190 | desc->addr = cpu_to_le32(mapping); |
---|
191 | sis190_give_to_asic(desc); |
---|
192 | } |
---|
193 | |
---|
194 | static inline void sis190_make_unusable_by_asic(struct RxDesc *desc) |
---|
195 | { |
---|
196 | desc->PSize = 0x0; |
---|
197 | desc->addr = cpu_to_le32(0xdeadbeef); |
---|
198 | desc->size &= cpu_to_le32(RingEnd); |
---|
199 | wmb(); |
---|
200 | desc->status = 0x0; |
---|
201 | } |
---|
202 | |
---|
203 | static struct io_buffer *sis190_alloc_rx_iob(struct RxDesc *desc) |
---|
204 | { |
---|
205 | struct io_buffer *iob; |
---|
206 | |
---|
207 | iob = alloc_iob(RX_BUF_SIZE); |
---|
208 | if (iob) { |
---|
209 | u32 mapping; |
---|
210 | |
---|
211 | mapping = virt_to_bus(iob->data); |
---|
212 | sis190_map_to_asic(desc, mapping); |
---|
213 | } else { |
---|
214 | DBG("sis190: alloc_iob failed\n"); |
---|
215 | sis190_make_unusable_by_asic(desc); |
---|
216 | } |
---|
217 | |
---|
218 | return iob; |
---|
219 | } |
---|
220 | |
---|
221 | static u32 sis190_rx_fill(struct sis190_private *tp, u32 start, u32 end) |
---|
222 | { |
---|
223 | u32 cur; |
---|
224 | |
---|
225 | for (cur = start; cur < end; cur++) { |
---|
226 | unsigned int i = cur % NUM_RX_DESC; |
---|
227 | |
---|
228 | if (tp->Rx_iobuf[i]) |
---|
229 | continue; |
---|
230 | |
---|
231 | tp->Rx_iobuf[i] = sis190_alloc_rx_iob(tp->RxDescRing + i); |
---|
232 | |
---|
233 | if (!tp->Rx_iobuf[i]) |
---|
234 | break; |
---|
235 | } |
---|
236 | return cur - start; |
---|
237 | } |
---|
238 | |
---|
239 | static inline int sis190_rx_pkt_err(u32 status) |
---|
240 | { |
---|
241 | #define ErrMask (OVRUN | SHORT | LIMIT | MIIER | NIBON | COLON | ABORT) |
---|
242 | |
---|
243 | if ((status & CRCOK) && !(status & ErrMask)) |
---|
244 | return 0; |
---|
245 | |
---|
246 | return -1; |
---|
247 | } |
---|
248 | |
---|
249 | static int sis190_process_rx(struct sis190_private *tp) |
---|
250 | { |
---|
251 | u32 rx_left, cur_rx = tp->cur_rx; |
---|
252 | u32 delta, count; |
---|
253 | |
---|
254 | rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx; |
---|
255 | |
---|
256 | for (; rx_left > 0; rx_left--, cur_rx++) { |
---|
257 | unsigned int entry = cur_rx % NUM_RX_DESC; |
---|
258 | struct RxDesc *desc = tp->RxDescRing + entry; |
---|
259 | u32 status; |
---|
260 | |
---|
261 | if (le32_to_cpu(desc->status) & OWNbit) |
---|
262 | break; |
---|
263 | |
---|
264 | status = le32_to_cpu(desc->PSize); |
---|
265 | |
---|
266 | if (sis190_rx_pkt_err(status) < 0) { |
---|
267 | sis190_give_to_asic(desc); |
---|
268 | } else { |
---|
269 | struct io_buffer *iob = tp->Rx_iobuf[entry]; |
---|
270 | unsigned int pkt_size = (status & RxSizeMask) - 4; |
---|
271 | |
---|
272 | if (pkt_size > RX_BUF_SIZE) { |
---|
273 | DBG("sis190: (frag) status = %08x.\n", status); |
---|
274 | sis190_give_to_asic(desc); |
---|
275 | continue; |
---|
276 | } |
---|
277 | |
---|
278 | sis190_make_unusable_by_asic(desc); |
---|
279 | |
---|
280 | iob_put(iob, pkt_size); |
---|
281 | |
---|
282 | DBG2("sis190: received packet. len: %d\n", pkt_size); |
---|
283 | netdev_rx(tp->dev, iob); |
---|
284 | DBGIO_HD(iob->data, 60); |
---|
285 | tp->Rx_iobuf[entry] = NULL; |
---|
286 | } |
---|
287 | } |
---|
288 | count = cur_rx - tp->cur_rx; |
---|
289 | tp->cur_rx = cur_rx; |
---|
290 | |
---|
291 | delta = sis190_rx_fill(tp, tp->dirty_rx, tp->cur_rx); |
---|
292 | if (!delta && count) |
---|
293 | DBG("sis190: no Rx buffer allocated.\n"); |
---|
294 | tp->dirty_rx += delta; |
---|
295 | |
---|
296 | if (((tp->dirty_rx + NUM_RX_DESC) == tp->cur_rx)) |
---|
297 | DBG("sis190: Rx buffers exhausted.\n"); |
---|
298 | |
---|
299 | return count; |
---|
300 | } |
---|
301 | |
---|
302 | static inline int sis190_tx_pkt_err(u32 status) |
---|
303 | { |
---|
304 | #define TxErrMask (WND | TABRT | FIFO | LINK) |
---|
305 | |
---|
306 | if (!(status & TxErrMask)) |
---|
307 | return 0; |
---|
308 | |
---|
309 | return -1; |
---|
310 | } |
---|
311 | |
---|
312 | static void sis190_process_tx(struct sis190_private *tp) |
---|
313 | { |
---|
314 | u32 pending, dirty_tx = tp->dirty_tx; |
---|
315 | |
---|
316 | pending = tp->cur_tx - dirty_tx; |
---|
317 | |
---|
318 | for (; pending; pending--, dirty_tx++) { |
---|
319 | unsigned int entry = dirty_tx % NUM_TX_DESC; |
---|
320 | struct TxDesc *txd = tp->TxDescRing + entry; |
---|
321 | u32 status = le32_to_cpu(txd->status); |
---|
322 | struct io_buffer *iob; |
---|
323 | |
---|
324 | if (status & OWNbit) |
---|
325 | break; |
---|
326 | |
---|
327 | iob = tp->Tx_iobuf[entry]; |
---|
328 | |
---|
329 | if (!iob) |
---|
330 | break; |
---|
331 | |
---|
332 | if (sis190_tx_pkt_err(status) == 0) { |
---|
333 | DBG2("sis190: Transmitted packet: %#08x\n", status); |
---|
334 | netdev_tx_complete(tp->dev, iob); |
---|
335 | } else { |
---|
336 | DBG("sis190: Transmit error: %#08x\n", status); |
---|
337 | netdev_tx_complete_err(tp->dev, iob, -EINVAL); |
---|
338 | } |
---|
339 | |
---|
340 | tp->Tx_iobuf[entry] = NULL; |
---|
341 | } |
---|
342 | |
---|
343 | if (tp->dirty_tx != dirty_tx) |
---|
344 | tp->dirty_tx = dirty_tx; |
---|
345 | } |
---|
346 | |
---|
347 | /* |
---|
348 | * The interrupt handler does all of the Rx thread work and cleans up after |
---|
349 | * the Tx thread. |
---|
350 | */ |
---|
351 | static void sis190_poll(struct net_device *dev) |
---|
352 | { |
---|
353 | struct sis190_private *tp = netdev_priv(dev); |
---|
354 | void *ioaddr = tp->mmio_addr; |
---|
355 | u32 status; |
---|
356 | |
---|
357 | status = SIS_R32(IntrStatus); |
---|
358 | |
---|
359 | if ((status == 0xffffffff) || !status) |
---|
360 | return; |
---|
361 | |
---|
362 | SIS_W32(IntrStatus, status); |
---|
363 | |
---|
364 | /* sis190_phy_task() needs to be called in event of a LinkChange and |
---|
365 | * after auto-negotiation is finished. Finishing auto-neg won't generate |
---|
366 | * any indication, hence we call it every time if the link is bad. */ |
---|
367 | if ((status & LinkChange) || !netdev_link_ok(dev)) |
---|
368 | sis190_phy_task(tp); |
---|
369 | |
---|
370 | if (status & RxQInt) |
---|
371 | sis190_process_rx(tp); |
---|
372 | |
---|
373 | if (status & TxQ0Int) |
---|
374 | sis190_process_tx(tp); |
---|
375 | } |
---|
376 | |
---|
377 | static inline void sis190_init_ring_indexes(struct sis190_private *tp) |
---|
378 | { |
---|
379 | tp->dirty_tx = tp->dirty_rx = tp->cur_tx = tp->cur_rx = 0; |
---|
380 | } |
---|
381 | |
---|
382 | static int sis190_init_ring(struct net_device *dev) |
---|
383 | { |
---|
384 | struct sis190_private *tp = netdev_priv(dev); |
---|
385 | |
---|
386 | sis190_init_ring_indexes(tp); |
---|
387 | |
---|
388 | memset(tp->Tx_iobuf, 0, NUM_TX_DESC * sizeof(struct io_buffer *)); |
---|
389 | memset(tp->Rx_iobuf, 0, NUM_RX_DESC * sizeof(struct io_buffer *)); |
---|
390 | |
---|
391 | if (sis190_rx_fill(tp, 0, NUM_RX_DESC) != NUM_RX_DESC) |
---|
392 | goto err; |
---|
393 | |
---|
394 | sis190_mark_as_last_descriptor(tp->RxDescRing + NUM_RX_DESC - 1); |
---|
395 | |
---|
396 | return 0; |
---|
397 | |
---|
398 | err: |
---|
399 | sis190_free(dev); |
---|
400 | return -ENOMEM; |
---|
401 | } |
---|
402 | |
---|
403 | static void sis190_set_rx_mode(struct net_device *dev) |
---|
404 | { |
---|
405 | struct sis190_private *tp = netdev_priv(dev); |
---|
406 | void *ioaddr = tp->mmio_addr; |
---|
407 | u32 mc_filter[2]; /* Multicast hash filter */ |
---|
408 | u16 rx_mode; |
---|
409 | |
---|
410 | rx_mode = AcceptBroadcast | AcceptMyPhys | AcceptMulticast; |
---|
411 | mc_filter[1] = mc_filter[0] = 0xffffffff; |
---|
412 | |
---|
413 | SIS_W16(RxMacControl, rx_mode | 0x2); |
---|
414 | SIS_W32(RxHashTable, mc_filter[0]); |
---|
415 | SIS_W32(RxHashTable + 4, mc_filter[1]); |
---|
416 | |
---|
417 | } |
---|
418 | |
---|
419 | static void sis190_soft_reset(void *ioaddr) |
---|
420 | { |
---|
421 | SIS_W32(IntrControl, 0x8000); |
---|
422 | SIS_PCI_COMMIT(); |
---|
423 | SIS_W32(IntrControl, 0x0); |
---|
424 | sis190_asic_down(ioaddr); |
---|
425 | } |
---|
426 | |
---|
427 | static void sis190_hw_start(struct net_device *dev) |
---|
428 | { |
---|
429 | struct sis190_private *tp = netdev_priv(dev); |
---|
430 | void *ioaddr = tp->mmio_addr; |
---|
431 | |
---|
432 | sis190_soft_reset(ioaddr); |
---|
433 | |
---|
434 | SIS_W32(TxDescStartAddr, tp->tx_dma); |
---|
435 | SIS_W32(RxDescStartAddr, tp->rx_dma); |
---|
436 | |
---|
437 | SIS_W32(IntrStatus, 0xffffffff); |
---|
438 | SIS_W32(IntrMask, 0x0); |
---|
439 | SIS_W32(GMIIControl, 0x0); |
---|
440 | SIS_W32(TxMacControl, 0x60); |
---|
441 | SIS_W16(RxMacControl, 0x02); |
---|
442 | SIS_W32(RxHashTable, 0x0); |
---|
443 | SIS_W32(0x6c, 0x0); |
---|
444 | SIS_W32(RxWolCtrl, 0x0); |
---|
445 | SIS_W32(RxWolData, 0x0); |
---|
446 | |
---|
447 | SIS_PCI_COMMIT(); |
---|
448 | |
---|
449 | sis190_set_rx_mode(dev); |
---|
450 | |
---|
451 | SIS_W32(TxControl, 0x1a00 | CmdTxEnb); |
---|
452 | SIS_W32(RxControl, 0x1a1d); |
---|
453 | } |
---|
454 | |
---|
455 | static void sis190_phy_task(struct sis190_private *tp) |
---|
456 | { |
---|
457 | struct net_device *dev = tp->dev; |
---|
458 | void *ioaddr = tp->mmio_addr; |
---|
459 | int phy_id = tp->mii_if.phy_id; |
---|
460 | int cnt = 0; |
---|
461 | u16 val; |
---|
462 | |
---|
463 | val = mdio_read(ioaddr, phy_id, MII_BMCR); |
---|
464 | |
---|
465 | /* 100ms timeout is completely arbitrary. I have no datasheet to |
---|
466 | * check whether that's a sensible value or not. |
---|
467 | */ |
---|
468 | while ((val & BMCR_RESET) && (cnt < 100)) { |
---|
469 | val = mdio_read(ioaddr, phy_id, MII_BMCR); |
---|
470 | mdelay(1); |
---|
471 | cnt++; |
---|
472 | } |
---|
473 | |
---|
474 | if (cnt > 99) { |
---|
475 | DBG("sis190: BMCR_RESET timeout\n"); |
---|
476 | return; |
---|
477 | } |
---|
478 | |
---|
479 | if (!(mdio_read_latched(ioaddr, phy_id, MII_BMSR) & |
---|
480 | BMSR_ANEGCOMPLETE)) { |
---|
481 | DBG("sis190: auto-negotiating...\n"); |
---|
482 | netdev_link_down(dev); |
---|
483 | } else { |
---|
484 | /* Rejoice ! */ |
---|
485 | struct { |
---|
486 | int val; |
---|
487 | u32 ctl; |
---|
488 | const char *msg; |
---|
489 | } reg31[] = { |
---|
490 | { LPA_1000FULL, 0x07000c00 | 0x00001000, |
---|
491 | "1000 Mbps Full Duplex" }, |
---|
492 | { LPA_1000HALF, 0x07000c00, |
---|
493 | "1000 Mbps Half Duplex" }, |
---|
494 | { LPA_100FULL, 0x04000800 | 0x00001000, |
---|
495 | "100 Mbps Full Duplex" }, |
---|
496 | { LPA_100HALF, 0x04000800, |
---|
497 | "100 Mbps Half Duplex" }, |
---|
498 | { LPA_10FULL, 0x04000400 | 0x00001000, |
---|
499 | "10 Mbps Full Duplex" }, |
---|
500 | { LPA_10HALF, 0x04000400, |
---|
501 | "10 Mbps Half Duplex" }, |
---|
502 | { 0, 0x04000400, "unknown" } |
---|
503 | }, *p = NULL; |
---|
504 | u16 adv, autoexp, gigadv, gigrec; |
---|
505 | |
---|
506 | val = mdio_read(ioaddr, phy_id, 0x1f); |
---|
507 | |
---|
508 | val = mdio_read(ioaddr, phy_id, MII_LPA); |
---|
509 | adv = mdio_read(ioaddr, phy_id, MII_ADVERTISE); |
---|
510 | |
---|
511 | autoexp = mdio_read(ioaddr, phy_id, MII_EXPANSION); |
---|
512 | |
---|
513 | if (val & LPA_NPAGE && autoexp & EXPANSION_NWAY) { |
---|
514 | /* check for gigabit speed */ |
---|
515 | gigadv = mdio_read(ioaddr, phy_id, MII_CTRL1000); |
---|
516 | gigrec = mdio_read(ioaddr, phy_id, MII_STAT1000); |
---|
517 | val = (gigadv & (gigrec >> 2)); |
---|
518 | if (val & ADVERTISE_1000FULL) |
---|
519 | p = reg31; |
---|
520 | else if (val & ADVERTISE_1000HALF) |
---|
521 | p = reg31 + 1; |
---|
522 | } |
---|
523 | |
---|
524 | if (!p) { |
---|
525 | val &= adv; |
---|
526 | |
---|
527 | for (p = reg31; p->val; p++) { |
---|
528 | if ((val & p->val) == p->val) |
---|
529 | break; |
---|
530 | } |
---|
531 | } |
---|
532 | |
---|
533 | p->ctl |= SIS_R32(StationControl) & ~0x0f001c00; |
---|
534 | |
---|
535 | if ((tp->features & F_HAS_RGMII) && |
---|
536 | (tp->features & F_PHY_BCM5461)) { |
---|
537 | // Set Tx Delay in RGMII mode. |
---|
538 | mdio_write(ioaddr, phy_id, 0x18, 0xf1c7); |
---|
539 | udelay(200); |
---|
540 | mdio_write(ioaddr, phy_id, 0x1c, 0x8c00); |
---|
541 | p->ctl |= 0x03000000; |
---|
542 | } |
---|
543 | |
---|
544 | SIS_W32(StationControl, p->ctl); |
---|
545 | |
---|
546 | if (tp->features & F_HAS_RGMII) { |
---|
547 | SIS_W32(RGDelay, 0x0441); |
---|
548 | SIS_W32(RGDelay, 0x0440); |
---|
549 | } |
---|
550 | |
---|
551 | DBG("sis190: link on %s mode.\n", p->msg); |
---|
552 | netdev_link_up(dev); |
---|
553 | } |
---|
554 | } |
---|
555 | |
---|
556 | static int sis190_open(struct net_device *dev) |
---|
557 | { |
---|
558 | struct sis190_private *tp = netdev_priv(dev); |
---|
559 | int rc; |
---|
560 | |
---|
561 | /* Allocate TX ring */ |
---|
562 | tp->TxDescRing = malloc_dma(TX_RING_BYTES, RING_ALIGNMENT); |
---|
563 | if (!tp->TxDescRing) { |
---|
564 | DBG("sis190: TX ring allocation failed\n"); |
---|
565 | rc = -ENOMEM; |
---|
566 | goto out; |
---|
567 | } |
---|
568 | tp->tx_dma = cpu_to_le32(virt_to_bus(tp->TxDescRing)); |
---|
569 | |
---|
570 | /* Allocate RX ring */ |
---|
571 | tp->RxDescRing = malloc_dma(RX_RING_BYTES, RING_ALIGNMENT); |
---|
572 | if (!tp->RxDescRing) { |
---|
573 | DBG("sis190: RX ring allocation failed\n"); |
---|
574 | rc = -ENOMEM; |
---|
575 | goto error; |
---|
576 | } |
---|
577 | tp->rx_dma = cpu_to_le32(virt_to_bus(tp->RxDescRing)); |
---|
578 | |
---|
579 | rc = sis190_init_ring(dev); |
---|
580 | if (rc < 0) |
---|
581 | goto error; |
---|
582 | |
---|
583 | /* init rx filter, also program MAC address to card */ |
---|
584 | sis190_init_rxfilter(dev); |
---|
585 | |
---|
586 | sis190_hw_start(dev); |
---|
587 | out: |
---|
588 | return rc; |
---|
589 | |
---|
590 | error: |
---|
591 | sis190_free(dev); |
---|
592 | goto out; |
---|
593 | } |
---|
594 | |
---|
595 | static void sis190_down(struct net_device *dev) |
---|
596 | { |
---|
597 | struct sis190_private *tp = netdev_priv(dev); |
---|
598 | void *ioaddr = tp->mmio_addr; |
---|
599 | |
---|
600 | do { |
---|
601 | sis190_asic_down(ioaddr); |
---|
602 | } while (SIS_R32(IntrMask)); |
---|
603 | } |
---|
604 | |
---|
605 | static void sis190_free(struct net_device *dev) |
---|
606 | { |
---|
607 | struct sis190_private *tp = netdev_priv(dev); |
---|
608 | int i; |
---|
609 | |
---|
610 | free_dma(tp->TxDescRing, TX_RING_BYTES); |
---|
611 | free_dma(tp->RxDescRing, RX_RING_BYTES); |
---|
612 | |
---|
613 | tp->TxDescRing = NULL; |
---|
614 | tp->RxDescRing = NULL; |
---|
615 | |
---|
616 | tp->tx_dma = 0; |
---|
617 | tp->rx_dma = 0; |
---|
618 | |
---|
619 | tp->cur_tx = tp->dirty_tx = 0; |
---|
620 | tp->cur_rx = tp->dirty_rx = 0; |
---|
621 | |
---|
622 | for (i = 0; i < NUM_RX_DESC; i++) { |
---|
623 | free_iob(tp->Rx_iobuf[i]); |
---|
624 | tp->Rx_iobuf[i] = NULL; |
---|
625 | } |
---|
626 | |
---|
627 | /* tx io_buffers aren't owned by the driver, so don't free them */ |
---|
628 | for(i = 0; i < NUM_TX_DESC; i++) |
---|
629 | tp->Tx_iobuf[i] = NULL; |
---|
630 | } |
---|
631 | |
---|
632 | static void sis190_close(struct net_device *dev) |
---|
633 | { |
---|
634 | sis190_down(dev); |
---|
635 | sis190_free(dev); |
---|
636 | } |
---|
637 | |
---|
638 | static int sis190_transmit(struct net_device *dev, struct io_buffer *iob) |
---|
639 | { |
---|
640 | struct sis190_private *tp = netdev_priv(dev); |
---|
641 | void *ioaddr = tp->mmio_addr; |
---|
642 | u32 len, entry; |
---|
643 | struct TxDesc *desc; |
---|
644 | |
---|
645 | len = iob_len(iob); |
---|
646 | if (len < ETH_ZLEN) { |
---|
647 | iob_pad(iob, ETH_ZLEN); |
---|
648 | len = ETH_ZLEN; |
---|
649 | } |
---|
650 | |
---|
651 | entry = tp->cur_tx % NUM_TX_DESC; |
---|
652 | desc = tp->TxDescRing + entry; |
---|
653 | |
---|
654 | if (le32_to_cpu(desc->status) & OWNbit) { |
---|
655 | DBG("sis190: Tx Ring full\n"); |
---|
656 | return -EINVAL; |
---|
657 | } |
---|
658 | |
---|
659 | tp->Tx_iobuf[entry] = iob; |
---|
660 | |
---|
661 | desc->PSize = cpu_to_le32(len); |
---|
662 | desc->addr = cpu_to_le32(virt_to_bus(iob->data)); |
---|
663 | |
---|
664 | desc->size = cpu_to_le32(len); |
---|
665 | if (entry == (NUM_TX_DESC - 1)) |
---|
666 | desc->size |= cpu_to_le32(RingEnd); |
---|
667 | |
---|
668 | wmb(); |
---|
669 | |
---|
670 | desc->status = cpu_to_le32(OWNbit | INTbit | DEFbit | CRCbit | PADbit); |
---|
671 | |
---|
672 | tp->cur_tx++; |
---|
673 | |
---|
674 | SIS_W32(TxControl, 0x1a00 | CmdReset | CmdTxEnb); |
---|
675 | |
---|
676 | return 0; |
---|
677 | } |
---|
678 | |
---|
679 | static void sis190_free_phy(struct list_head *first_phy) |
---|
680 | { |
---|
681 | struct sis190_phy *cur, *next; |
---|
682 | |
---|
683 | list_for_each_entry_safe(cur, next, first_phy, list) { |
---|
684 | free(cur); |
---|
685 | } |
---|
686 | } |
---|
687 | |
---|
688 | /** |
---|
689 | * sis190_default_phy - Select default PHY for sis190 mac. |
---|
690 | * @dev: the net device to probe for |
---|
691 | * |
---|
692 | * Select first detected PHY with link as default. |
---|
693 | * If no one is link on, select PHY whose types is HOME as default. |
---|
694 | * If HOME doesn't exist, select LAN. |
---|
695 | */ |
---|
696 | static u16 sis190_default_phy(struct sis190_private *tp) |
---|
697 | { |
---|
698 | struct sis190_phy *phy, *phy_home, *phy_default, *phy_lan; |
---|
699 | struct mii_if_info *mii_if = &tp->mii_if; |
---|
700 | void *ioaddr = tp->mmio_addr; |
---|
701 | u16 status; |
---|
702 | |
---|
703 | phy_home = phy_default = phy_lan = NULL; |
---|
704 | |
---|
705 | list_for_each_entry(phy, &tp->first_phy, list) { |
---|
706 | status = mdio_read_latched(ioaddr, phy->phy_id, MII_BMSR); |
---|
707 | |
---|
708 | // Link ON & Not select default PHY & not ghost PHY. |
---|
709 | if ((status & BMSR_LSTATUS) && |
---|
710 | !phy_default && |
---|
711 | (phy->type != UNKNOWN)) { |
---|
712 | phy_default = phy; |
---|
713 | } else { |
---|
714 | status = mdio_read(ioaddr, phy->phy_id, MII_BMCR); |
---|
715 | mdio_write(ioaddr, phy->phy_id, MII_BMCR, |
---|
716 | status | BMCR_ANENABLE | BMCR_ISOLATE); |
---|
717 | if (phy->type == HOME) |
---|
718 | phy_home = phy; |
---|
719 | else if (phy->type == LAN) |
---|
720 | phy_lan = phy; |
---|
721 | } |
---|
722 | } |
---|
723 | |
---|
724 | if (!phy_default) { |
---|
725 | if (phy_home) |
---|
726 | phy_default = phy_home; |
---|
727 | else if (phy_lan) |
---|
728 | phy_default = phy_lan; |
---|
729 | else |
---|
730 | phy_default = list_entry(&tp->first_phy, |
---|
731 | struct sis190_phy, list); |
---|
732 | } |
---|
733 | |
---|
734 | if (mii_if->phy_id != phy_default->phy_id) { |
---|
735 | mii_if->phy_id = phy_default->phy_id; |
---|
736 | DBG("sis190: Using transceiver at address %d as default.\n", |
---|
737 | mii_if->phy_id); |
---|
738 | } |
---|
739 | |
---|
740 | status = mdio_read(ioaddr, mii_if->phy_id, MII_BMCR); |
---|
741 | status &= (~BMCR_ISOLATE); |
---|
742 | |
---|
743 | mdio_write(ioaddr, mii_if->phy_id, MII_BMCR, status); |
---|
744 | status = mdio_read_latched(ioaddr, mii_if->phy_id, MII_BMSR); |
---|
745 | |
---|
746 | return status; |
---|
747 | } |
---|
748 | |
---|
749 | static void sis190_init_phy(struct sis190_private *tp, |
---|
750 | struct sis190_phy *phy, unsigned int phy_id, |
---|
751 | u16 mii_status) |
---|
752 | { |
---|
753 | void *ioaddr = tp->mmio_addr; |
---|
754 | struct mii_chip_info *p; |
---|
755 | |
---|
756 | INIT_LIST_HEAD(&phy->list); |
---|
757 | phy->status = mii_status; |
---|
758 | phy->phy_id = phy_id; |
---|
759 | |
---|
760 | phy->id[0] = mdio_read(ioaddr, phy_id, MII_PHYSID1); |
---|
761 | phy->id[1] = mdio_read(ioaddr, phy_id, MII_PHYSID2); |
---|
762 | |
---|
763 | for (p = mii_chip_table; p->type; p++) { |
---|
764 | if ((p->id[0] == phy->id[0]) && |
---|
765 | (p->id[1] == (phy->id[1] & 0xfff0))) { |
---|
766 | break; |
---|
767 | } |
---|
768 | } |
---|
769 | |
---|
770 | if (p->id[1]) { |
---|
771 | phy->type = (p->type == MIX) ? |
---|
772 | ((mii_status & (BMSR_100FULL | BMSR_100HALF)) ? |
---|
773 | LAN : HOME) : p->type; |
---|
774 | tp->features |= p->feature; |
---|
775 | |
---|
776 | DBG("sis190: %s transceiver at address %d.\n", p->name, phy_id); |
---|
777 | } else { |
---|
778 | phy->type = UNKNOWN; |
---|
779 | |
---|
780 | DBG("sis190: unknown PHY 0x%x:0x%x transceiver at address %d\n", |
---|
781 | phy->id[0], (phy->id[1] & 0xfff0), phy_id); |
---|
782 | } |
---|
783 | } |
---|
784 | |
---|
785 | static void sis190_mii_probe_88e1111_fixup(struct sis190_private *tp) |
---|
786 | { |
---|
787 | if (tp->features & F_PHY_88E1111) { |
---|
788 | void *ioaddr = tp->mmio_addr; |
---|
789 | int phy_id = tp->mii_if.phy_id; |
---|
790 | u16 reg[2][2] = { |
---|
791 | { 0x808b, 0x0ce1 }, |
---|
792 | { 0x808f, 0x0c60 } |
---|
793 | }, *p; |
---|
794 | |
---|
795 | p = (tp->features & F_HAS_RGMII) ? reg[0] : reg[1]; |
---|
796 | |
---|
797 | mdio_write(ioaddr, phy_id, 0x1b, p[0]); |
---|
798 | udelay(200); |
---|
799 | mdio_write(ioaddr, phy_id, 0x14, p[1]); |
---|
800 | udelay(200); |
---|
801 | } |
---|
802 | } |
---|
803 | |
---|
804 | /** |
---|
805 | * sis190_mii_probe - Probe MII PHY for sis190 |
---|
806 | * @dev: the net device to probe for |
---|
807 | * |
---|
808 | * Search for total of 32 possible mii phy addresses. |
---|
809 | * Identify and set current phy if found one, |
---|
810 | * return error if it failed to found. |
---|
811 | */ |
---|
812 | static int sis190_mii_probe(struct net_device *dev) |
---|
813 | { |
---|
814 | struct sis190_private *tp = netdev_priv(dev); |
---|
815 | struct mii_if_info *mii_if = &tp->mii_if; |
---|
816 | void *ioaddr = tp->mmio_addr; |
---|
817 | int phy_id; |
---|
818 | int rc = 0; |
---|
819 | |
---|
820 | INIT_LIST_HEAD(&tp->first_phy); |
---|
821 | |
---|
822 | for (phy_id = 0; phy_id < PHY_MAX_ADDR; phy_id++) { |
---|
823 | struct sis190_phy *phy; |
---|
824 | u16 status; |
---|
825 | |
---|
826 | status = mdio_read_latched(ioaddr, phy_id, MII_BMSR); |
---|
827 | |
---|
828 | // Try next mii if the current one is not accessible. |
---|
829 | if (status == 0xffff || status == 0x0000) |
---|
830 | continue; |
---|
831 | |
---|
832 | phy = zalloc(sizeof(*phy)); |
---|
833 | if (!phy) { |
---|
834 | sis190_free_phy(&tp->first_phy); |
---|
835 | rc = -ENOMEM; |
---|
836 | goto out; |
---|
837 | } |
---|
838 | |
---|
839 | DBG("sis190: found PHY\n"); |
---|
840 | |
---|
841 | sis190_init_phy(tp, phy, phy_id, status); |
---|
842 | |
---|
843 | list_add(&tp->first_phy, &phy->list); |
---|
844 | } |
---|
845 | |
---|
846 | if (list_empty(&tp->first_phy)) { |
---|
847 | DBG("sis190: No MII transceivers found!\n"); |
---|
848 | rc = -EIO; |
---|
849 | goto out; |
---|
850 | } |
---|
851 | |
---|
852 | /* Select default PHY for mac */ |
---|
853 | sis190_default_phy(tp); |
---|
854 | |
---|
855 | sis190_mii_probe_88e1111_fixup(tp); |
---|
856 | |
---|
857 | mii_if->dev = dev; |
---|
858 | mii_if->mdio_read = __mdio_read; |
---|
859 | mii_if->mdio_write = __mdio_write; |
---|
860 | mii_if->phy_id_mask = PHY_ID_ANY; |
---|
861 | mii_if->reg_num_mask = MII_REG_ANY; |
---|
862 | out: |
---|
863 | return rc; |
---|
864 | } |
---|
865 | |
---|
866 | static void sis190_mii_remove(struct net_device *dev) |
---|
867 | { |
---|
868 | struct sis190_private *tp = netdev_priv(dev); |
---|
869 | |
---|
870 | sis190_free_phy(&tp->first_phy); |
---|
871 | } |
---|
872 | |
---|
873 | static int sis190_init_board(struct pci_device *pdev, struct net_device **netdev) |
---|
874 | { |
---|
875 | struct sis190_private *tp; |
---|
876 | struct net_device *dev; |
---|
877 | void *ioaddr; |
---|
878 | int rc; |
---|
879 | |
---|
880 | dev = alloc_etherdev(sizeof(*tp)); |
---|
881 | if (!dev) { |
---|
882 | DBG("sis190: unable to alloc new etherdev\n"); |
---|
883 | rc = -ENOMEM; |
---|
884 | goto err; |
---|
885 | } |
---|
886 | |
---|
887 | dev->dev = &pdev->dev; |
---|
888 | |
---|
889 | tp = netdev_priv(dev); |
---|
890 | memset(tp, 0, sizeof(*tp)); |
---|
891 | |
---|
892 | tp->dev = dev; |
---|
893 | |
---|
894 | adjust_pci_device(pdev); |
---|
895 | |
---|
896 | ioaddr = ioremap(pdev->membase, SIS190_REGS_SIZE); |
---|
897 | if (!ioaddr) { |
---|
898 | DBG("sis190: cannot remap MMIO, aborting\n"); |
---|
899 | rc = -EIO; |
---|
900 | goto err; |
---|
901 | } |
---|
902 | |
---|
903 | tp->pci_device = pdev; |
---|
904 | tp->mmio_addr = ioaddr; |
---|
905 | |
---|
906 | sis190_irq_mask_and_ack(ioaddr); |
---|
907 | |
---|
908 | sis190_soft_reset(ioaddr); |
---|
909 | |
---|
910 | *netdev = dev; |
---|
911 | |
---|
912 | return 0; |
---|
913 | |
---|
914 | err: |
---|
915 | return rc; |
---|
916 | } |
---|
917 | |
---|
918 | static void sis190_set_rgmii(struct sis190_private *tp, u8 reg) |
---|
919 | { |
---|
920 | tp->features |= (reg & 0x80) ? F_HAS_RGMII : 0; |
---|
921 | } |
---|
922 | |
---|
923 | static int sis190_get_mac_addr_from_eeprom(struct pci_device *pdev __unused, |
---|
924 | struct net_device *dev) |
---|
925 | { |
---|
926 | struct sis190_private *tp = netdev_priv(dev); |
---|
927 | void *ioaddr = tp->mmio_addr; |
---|
928 | u16 sig; |
---|
929 | int i; |
---|
930 | |
---|
931 | DBG("sis190: Read MAC address from EEPROM\n"); |
---|
932 | |
---|
933 | /* Check to see if there is a sane EEPROM */ |
---|
934 | sig = (u16) sis190_read_eeprom(ioaddr, EEPROMSignature); |
---|
935 | |
---|
936 | if ((sig == 0xffff) || (sig == 0x0000)) { |
---|
937 | DBG("sis190: Error EEPROM read.\n"); |
---|
938 | return -EIO; |
---|
939 | } |
---|
940 | |
---|
941 | /* Get MAC address from EEPROM */ |
---|
942 | for (i = 0; i < ETH_ALEN / 2; i++) { |
---|
943 | u16 w = sis190_read_eeprom(ioaddr, EEPROMMACAddr + i); |
---|
944 | |
---|
945 | ((u16 *)dev->hw_addr)[i] = cpu_to_le16(w); |
---|
946 | } |
---|
947 | |
---|
948 | sis190_set_rgmii(tp, sis190_read_eeprom(ioaddr, EEPROMInfo)); |
---|
949 | |
---|
950 | return 0; |
---|
951 | } |
---|
952 | |
---|
953 | /** |
---|
954 | * sis190_get_mac_addr_from_apc - Get MAC address for SiS96x model |
---|
955 | * @pdev: PCI device |
---|
956 | * @dev: network device to get address for |
---|
957 | * |
---|
958 | * SiS96x model, use APC CMOS RAM to store MAC address. |
---|
959 | * APC CMOS RAM is accessed through ISA bridge. |
---|
960 | * MAC address is read into @net_dev->dev_addr. |
---|
961 | */ |
---|
962 | static int sis190_get_mac_addr_from_apc(struct pci_device *pdev, |
---|
963 | struct net_device *dev) |
---|
964 | { |
---|
965 | struct sis190_private *tp = netdev_priv(dev); |
---|
966 | struct pci_device *isa_bridge = NULL; |
---|
967 | struct device *d; |
---|
968 | u8 reg, tmp8; |
---|
969 | unsigned int i; |
---|
970 | |
---|
971 | DBG("sis190: Read MAC address from APC.\n"); |
---|
972 | |
---|
973 | list_for_each_entry(d, &(pdev->dev.siblings), siblings) { |
---|
974 | unsigned int i; |
---|
975 | isa_bridge = container_of(d, struct pci_device, dev); |
---|
976 | for(i = 0; i < sis190_isa_bridge_driver.id_count; i++) { |
---|
977 | if(isa_bridge->vendor == |
---|
978 | sis190_isa_bridge_driver.ids[i].vendor |
---|
979 | && isa_bridge->device == |
---|
980 | sis190_isa_bridge_driver.ids[i].device) { |
---|
981 | DBG("sis190: ISA bridge found\n"); |
---|
982 | break; |
---|
983 | } else { |
---|
984 | isa_bridge = NULL; |
---|
985 | } |
---|
986 | } |
---|
987 | if(isa_bridge) |
---|
988 | break; |
---|
989 | } |
---|
990 | |
---|
991 | if (!isa_bridge) { |
---|
992 | DBG("sis190: Can not find ISA bridge.\n"); |
---|
993 | return -EIO; |
---|
994 | } |
---|
995 | |
---|
996 | /* Enable port 78h & 79h to access APC Registers. */ |
---|
997 | pci_read_config_byte(isa_bridge, 0x48, &tmp8); |
---|
998 | reg = (tmp8 & ~0x02); |
---|
999 | pci_write_config_byte(isa_bridge, 0x48, reg); |
---|
1000 | udelay(50); |
---|
1001 | pci_read_config_byte(isa_bridge, 0x48, ®); |
---|
1002 | |
---|
1003 | for (i = 0; i < ETH_ALEN; i++) { |
---|
1004 | outb(0x9 + i, 0x78); |
---|
1005 | dev->hw_addr[i] = inb(0x79); |
---|
1006 | } |
---|
1007 | |
---|
1008 | outb(0x12, 0x78); |
---|
1009 | reg = inb(0x79); |
---|
1010 | |
---|
1011 | sis190_set_rgmii(tp, reg); |
---|
1012 | |
---|
1013 | /* Restore the value to ISA Bridge */ |
---|
1014 | pci_write_config_byte(isa_bridge, 0x48, tmp8); |
---|
1015 | |
---|
1016 | return 0; |
---|
1017 | } |
---|
1018 | |
---|
1019 | /** |
---|
1020 | * sis190_init_rxfilter - Initialize the Rx filter |
---|
1021 | * @dev: network device to initialize |
---|
1022 | * |
---|
1023 | * Set receive filter address to our MAC address |
---|
1024 | * and enable packet filtering. |
---|
1025 | */ |
---|
1026 | static inline void sis190_init_rxfilter(struct net_device *dev) |
---|
1027 | { |
---|
1028 | struct sis190_private *tp = netdev_priv(dev); |
---|
1029 | void *ioaddr = tp->mmio_addr; |
---|
1030 | u16 ctl; |
---|
1031 | int i; |
---|
1032 | |
---|
1033 | ctl = SIS_R16(RxMacControl); |
---|
1034 | /* |
---|
1035 | * Disable packet filtering before setting filter. |
---|
1036 | * Note: SiS's driver writes 32 bits but RxMacControl is 16 bits |
---|
1037 | * only and followed by RxMacAddr (6 bytes). Strange. -- FR |
---|
1038 | */ |
---|
1039 | SIS_W16(RxMacControl, ctl & ~0x0f00); |
---|
1040 | |
---|
1041 | for (i = 0; i < ETH_ALEN; i++) |
---|
1042 | SIS_W8(RxMacAddr + i, dev->ll_addr[i]); |
---|
1043 | |
---|
1044 | SIS_W16(RxMacControl, ctl); |
---|
1045 | SIS_PCI_COMMIT(); |
---|
1046 | } |
---|
1047 | |
---|
1048 | static int sis190_get_mac_addr(struct pci_device *pdev, |
---|
1049 | struct net_device *dev) |
---|
1050 | { |
---|
1051 | int rc; |
---|
1052 | |
---|
1053 | rc = sis190_get_mac_addr_from_eeprom(pdev, dev); |
---|
1054 | if (rc < 0) { |
---|
1055 | u8 reg; |
---|
1056 | |
---|
1057 | pci_read_config_byte(pdev, 0x73, ®); |
---|
1058 | |
---|
1059 | if (reg & 0x00000001) |
---|
1060 | rc = sis190_get_mac_addr_from_apc(pdev, dev); |
---|
1061 | } |
---|
1062 | return rc; |
---|
1063 | } |
---|
1064 | |
---|
1065 | static void sis190_set_speed_auto(struct net_device *dev) |
---|
1066 | { |
---|
1067 | struct sis190_private *tp = netdev_priv(dev); |
---|
1068 | void *ioaddr = tp->mmio_addr; |
---|
1069 | int phy_id = tp->mii_if.phy_id; |
---|
1070 | int val; |
---|
1071 | |
---|
1072 | DBG("sis190: Enabling Auto-negotiation.\n"); |
---|
1073 | |
---|
1074 | val = mdio_read(ioaddr, phy_id, MII_ADVERTISE); |
---|
1075 | |
---|
1076 | // Enable 10/100 Full/Half Mode, leave MII_ADVERTISE bit4:0 |
---|
1077 | // unchanged. |
---|
1078 | mdio_write(ioaddr, phy_id, MII_ADVERTISE, (val & ADVERTISE_SLCT) | |
---|
1079 | ADVERTISE_100FULL | ADVERTISE_10FULL | |
---|
1080 | ADVERTISE_100HALF | ADVERTISE_10HALF); |
---|
1081 | |
---|
1082 | // Enable 1000 Full Mode. |
---|
1083 | mdio_write(ioaddr, phy_id, MII_CTRL1000, ADVERTISE_1000FULL); |
---|
1084 | |
---|
1085 | // Enable auto-negotiation and restart auto-negotiation. |
---|
1086 | mdio_write(ioaddr, phy_id, MII_BMCR, |
---|
1087 | BMCR_ANENABLE | BMCR_ANRESTART | BMCR_RESET); |
---|
1088 | } |
---|
1089 | |
---|
1090 | static void sis190_irq(struct net_device *dev, int enable) |
---|
1091 | { |
---|
1092 | struct sis190_private *tp = netdev_priv(dev); |
---|
1093 | void *ioaddr = tp->mmio_addr; |
---|
1094 | |
---|
1095 | SIS_W32(IntrStatus, 0xffffffff); |
---|
1096 | |
---|
1097 | if (enable == 0) |
---|
1098 | SIS_W32(IntrMask, 0x00); |
---|
1099 | else |
---|
1100 | SIS_W32(IntrMask, sis190_intr_mask); |
---|
1101 | |
---|
1102 | SIS_PCI_COMMIT(); |
---|
1103 | } |
---|
1104 | |
---|
1105 | static struct net_device_operations sis190_netdev_ops = { |
---|
1106 | .open = sis190_open, |
---|
1107 | .close = sis190_close, |
---|
1108 | .poll = sis190_poll, |
---|
1109 | .transmit = sis190_transmit, |
---|
1110 | .irq = sis190_irq, |
---|
1111 | }; |
---|
1112 | |
---|
1113 | static int sis190_probe(struct pci_device *pdev, |
---|
1114 | const struct pci_device_id *ent __unused) |
---|
1115 | { |
---|
1116 | struct sis190_private *tp; |
---|
1117 | struct net_device *dev; |
---|
1118 | void *ioaddr; |
---|
1119 | int rc; |
---|
1120 | |
---|
1121 | rc = sis190_init_board(pdev, &dev); |
---|
1122 | if (rc < 0) |
---|
1123 | goto out; |
---|
1124 | |
---|
1125 | pci_set_drvdata(pdev, dev); |
---|
1126 | |
---|
1127 | tp = netdev_priv(dev); |
---|
1128 | ioaddr = tp->mmio_addr; |
---|
1129 | |
---|
1130 | rc = sis190_get_mac_addr(pdev, dev); |
---|
1131 | if (rc < 0) |
---|
1132 | goto err; |
---|
1133 | |
---|
1134 | rc = sis190_mii_probe(dev); |
---|
1135 | if (rc < 0) |
---|
1136 | goto err; |
---|
1137 | |
---|
1138 | rc = register_netdev(dev); |
---|
1139 | if (rc < 0) |
---|
1140 | goto err; |
---|
1141 | |
---|
1142 | sis190_set_speed_auto(dev); |
---|
1143 | sis190_phy_task(tp); |
---|
1144 | |
---|
1145 | netdev_init(dev, &sis190_netdev_ops); |
---|
1146 | netdev_link_down(dev); |
---|
1147 | out: |
---|
1148 | return rc; |
---|
1149 | |
---|
1150 | err: |
---|
1151 | sis190_mii_remove(dev); |
---|
1152 | iounmap(tp->mmio_addr); |
---|
1153 | goto out; |
---|
1154 | } |
---|
1155 | |
---|
1156 | static void sis190_remove(struct pci_device *pdev) |
---|
1157 | { |
---|
1158 | struct net_device *dev = pci_get_drvdata(pdev); |
---|
1159 | struct sis190_private *tp = dev->priv; |
---|
1160 | void *ioaddr = tp->mmio_addr; |
---|
1161 | |
---|
1162 | sis190_mii_remove(dev); |
---|
1163 | |
---|
1164 | /* shutdown chip, disable interrupts, etc */ |
---|
1165 | sis190_soft_reset(ioaddr); |
---|
1166 | |
---|
1167 | iounmap(tp->mmio_addr); |
---|
1168 | |
---|
1169 | unregister_netdev(dev); |
---|
1170 | netdev_nullify(dev); |
---|
1171 | netdev_put(dev); |
---|
1172 | } |
---|
1173 | |
---|
1174 | struct pci_driver sis190_pci_driver __pci_driver = { |
---|
1175 | .ids = sis190_pci_tbl, |
---|
1176 | .id_count = (sizeof(sis190_pci_tbl) / sizeof(sis190_pci_tbl[0])), |
---|
1177 | .probe = sis190_probe, |
---|
1178 | .remove = sis190_remove, |
---|
1179 | }; |
---|