[e16e8f2] | 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 | }; |
---|