00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 FILE_LICENCE ( BSD2 );
00040
00041 #include <stdint.h>
00042 #include <stdio.h>
00043 #include <stdlib.h>
00044 #include <stddef.h>
00045 #include <string.h>
00046 #include <unistd.h>
00047 #include <assert.h>
00048 #include <byteswap.h>
00049 #include <errno.h>
00050 #include <gpxe/ethernet.h>
00051 #include <gpxe/if_ether.h>
00052 #include <gpxe/io.h>
00053 #include <gpxe/iobuf.h>
00054 #include <gpxe/malloc.h>
00055 #include <gpxe/netdevice.h>
00056 #include <gpxe/pci.h>
00057 #include <gpxe/timer.h>
00058 #include <gpxe/nvs.h>
00059
00060 #include "3c90x.h"
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070 static void a3c90x_internal_IssueCommand(int ioaddr, int cmd, int param)
00071 {
00072 unsigned int val = (cmd << 11) | param;
00073 int cnt = 0;
00074
00075 DBGP("a3c90x_internal_IssueCommand\n");
00076
00077
00078 outw(val, ioaddr + regCommandIntStatus_w);
00079
00080
00081 for (cnt = 0; cnt < 100000; cnt++) {
00082 if (inw(ioaddr + regCommandIntStatus_w) & INT_CMDINPROGRESS) {
00083 continue;
00084 } else {
00085 DBG2("Command 0x%04X finished in time. cnt = %d.\n", cmd, cnt);
00086 return;
00087 }
00088 }
00089
00090 DBG("Command 0x%04X DID NOT finish in time. cnt = %d.\n", cmd, cnt);
00091 }
00092
00093
00094
00095
00096
00097
00098
00099 static void a3c90x_internal_SetWindow(struct INF_3C90X *inf_3c90x, int window)
00100 {
00101 DBGP("a3c90x_internal_SetWindow\n");
00102
00103 if (inf_3c90x->CurrentWindow == window)
00104 return;
00105
00106
00107 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr,
00108 cmdSelectRegisterWindow, window);
00109 inf_3c90x->CurrentWindow = window;
00110
00111 return;
00112 }
00113
00114 static void a3c90x_internal_WaitForEeprom(struct INF_3C90X *inf_3c90x)
00115 {
00116 int cnt = 0;
00117
00118 DBGP("a3c90x_internal_WaitForEeprom\n");
00119
00120 while (eepromBusy & inw(inf_3c90x->IOAddr + regEepromCommand_0_w)) {
00121 if (cnt == EEPROM_TIMEOUT) {
00122 DBG("Read from eeprom failed: timeout\n");
00123 return;
00124 }
00125 udelay(1);
00126 cnt++;
00127 }
00128 }
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140 static int
00141 a3c90x_internal_ReadEeprom(struct nvs_device *nvs, unsigned int address, void *data, size_t len)
00142 {
00143 unsigned short *dest = (unsigned short *) data;
00144 struct INF_3C90X *inf_3c90x =
00145 container_of(nvs, struct INF_3C90X, nvs);
00146
00147 DBGP("a3c90x_internal_ReadEeprom\n");
00148
00149
00150 assert(len == 2);
00151
00152
00153 a3c90x_internal_SetWindow(inf_3c90x, winEepromBios0);
00154
00155
00156 address += (inf_3c90x->is3c556 ? eepromRead_556 : eepromRead);
00157
00158 a3c90x_internal_WaitForEeprom(inf_3c90x);
00159
00160 outw(address, inf_3c90x->IOAddr + regEepromCommand_0_w);
00161 a3c90x_internal_WaitForEeprom(inf_3c90x);
00162
00163
00164 *dest = inw(inf_3c90x->IOAddr + regEepromData_0_w);
00165
00166 return 0;
00167 }
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178 static int
00179 a3c90x_internal_WriteEeprom(struct nvs_device *nvs __unused,
00180 unsigned int address __unused,
00181 const void *data __unused, size_t len __unused)
00182 {
00183 return -ENOTSUP;
00184 }
00185
00186 static void a3c90x_internal_ReadEepromContents(struct INF_3C90X *inf_3c90x)
00187 {
00188 int eeprom_size = (inf_3c90x->isBrev ? 0x20 : 0x17) * 2;
00189
00190 DBGP("a3c90x_internal_ReadEepromContents\n");
00191
00192 nvs_read(&inf_3c90x->nvs, 0, inf_3c90x->eeprom, eeprom_size);
00193 }
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204 static void a3c90x_reset(struct INF_3C90X *inf_3c90x)
00205 {
00206 DBGP("a3c90x_reset\n");
00207
00208 DBG("3c90x: Issuing RESET\n");
00209 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdGlobalReset, 0);
00210
00211
00212
00213
00214 a3c90x_internal_SetWindow(inf_3c90x, winAddressing2);
00215 outw(0, inf_3c90x->IOAddr + regStationMask_2_3w + 0);
00216 outw(0, inf_3c90x->IOAddr + regStationMask_2_3w + 2);
00217 outw(0, inf_3c90x->IOAddr + regStationMask_2_3w + 4);
00218
00219
00220 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdTxReset, 0);
00221
00222 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdTxEnable, 0);
00223
00224
00225
00226
00227
00228 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdRxReset,
00229 inf_3c90x->isBrev ? 0x04 : 0x00);
00230
00231 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdRxEnable, 0);
00232
00233 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr,
00234 cmdSetInterruptEnable, 0);
00235
00236 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr,
00237 cmdSetIndicationEnable,
00238 INT_TXCOMPLETE | INT_UPCOMPLETE);
00239
00240 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr,
00241 cmdAcknowledgeInterrupt, 0x661);
00242
00243 return;
00244 }
00245
00246
00247
00248
00249
00250
00251
00252
00253 static int a3c90x_setup_tx_ring(struct INF_3C90X *p)
00254 {
00255 DBGP("a3c90x_setup_tx_ring\n");
00256 p->tx_ring =
00257 malloc_dma(TX_RING_SIZE * sizeof(struct TXD), TX_RING_ALIGN);
00258
00259 if (!p->tx_ring) {
00260 DBG("Could not allocate TX-ring\n");
00261 return -ENOMEM;
00262 }
00263
00264 memset(p->tx_ring, 0, TX_RING_SIZE * sizeof(struct TXD));
00265 p->tx_cur = 0;
00266 p->tx_cnt = 0;
00267 p->tx_tail = 0;
00268
00269 return 0;
00270 }
00271
00272
00273
00274
00275
00276
00277
00278 static void a3c90x_process_tx_packets(struct net_device *netdev)
00279 {
00280 struct INF_3C90X *p = netdev_priv(netdev);
00281 unsigned int downlist_ptr;
00282
00283 DBGP("a3c90x_process_tx_packets\n");
00284
00285 DBG(" tx_cnt: %d\n", p->tx_cnt);
00286
00287 while (p->tx_tail != p->tx_cur) {
00288
00289 downlist_ptr = inl(p->IOAddr + regDnListPtr_l);
00290
00291 DBG(" downlist_ptr: %#08x\n", downlist_ptr);
00292 DBG(" tx_tail: %d tx_cur: %d\n", p->tx_tail, p->tx_cur);
00293
00294
00295 if(downlist_ptr == virt_to_bus(p->tx_ring + p->tx_tail))
00296 return;
00297
00298 netdev_tx_complete(netdev, p->tx_iobuf[p->tx_tail]);
00299
00300 DBG("transmitted packet\n");
00301 DBG(" size: %zd\n", iob_len(p->tx_iobuf[p->tx_tail]));
00302
00303 p->tx_tail = (p->tx_tail + 1) % TX_RING_SIZE;
00304 p->tx_cnt--;
00305 }
00306 }
00307
00308 static void a3c90x_free_tx_ring(struct INF_3C90X *p)
00309 {
00310 DBGP("a3c90x_free_tx_ring\n");
00311
00312 free_dma(p->tx_ring, TX_RING_SIZE * sizeof(struct TXD));
00313 p->tx_ring = NULL;
00314
00315 }
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325 static int a3c90x_transmit(struct net_device *netdev,
00326 struct io_buffer *iob)
00327 {
00328 struct INF_3C90X *inf_3c90x = netdev_priv(netdev);
00329 struct TXD *tx_cur_desc;
00330 struct TXD *tx_prev_desc;
00331
00332 unsigned int len;
00333 unsigned int downlist_ptr;
00334
00335 DBGP("a3c90x_transmit\n");
00336
00337 if (inf_3c90x->tx_cnt == TX_RING_SIZE) {
00338 DBG("TX-Ring overflow\n");
00339 return -ENOBUFS;
00340 }
00341
00342 inf_3c90x->tx_iobuf[inf_3c90x->tx_cur] = iob;
00343 tx_cur_desc = inf_3c90x->tx_ring + inf_3c90x->tx_cur;
00344
00345 tx_prev_desc = inf_3c90x->tx_ring +
00346 (((inf_3c90x->tx_cur + TX_RING_SIZE) - 1) % TX_RING_SIZE);
00347
00348 len = iob_len(iob);
00349
00350
00351 tx_cur_desc->DnNextPtr = 0;
00352
00353
00354
00355
00356
00357 tx_cur_desc->FrameStartHeader =
00358 fshTxIndicate | (inf_3c90x->isBrev ? 0x00 : len);
00359
00360 tx_cur_desc->DataAddr = virt_to_bus(iob->data);
00361 tx_cur_desc->DataLength = len | downLastFrag;
00362
00363
00364
00365
00366
00367
00368 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdStallCtl,
00369 dnStall);
00370
00371 tx_prev_desc->DnNextPtr = virt_to_bus(tx_cur_desc);
00372
00373 downlist_ptr = inl(inf_3c90x->IOAddr + regDnListPtr_l);
00374 if (downlist_ptr == 0) {
00375
00376 outl(virt_to_bus(tx_cur_desc),
00377 inf_3c90x->IOAddr + regDnListPtr_l);
00378 }
00379
00380
00381 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdStallCtl,
00382 dnUnStall);
00383
00384 inf_3c90x->tx_cur = (inf_3c90x->tx_cur + 1) % TX_RING_SIZE;
00385 inf_3c90x->tx_cnt++;
00386
00387 return 0;
00388 }
00389
00390
00391
00392
00393
00394
00395
00396
00397 static void a3c90x_prepare_rx_desc(struct INF_3C90X *p, unsigned int index)
00398 {
00399 DBGP("a3c90x_prepare_rx_desc\n");
00400 DBG("Populating rx_desc %d\n", index);
00401
00402
00403
00404
00405
00406
00407 a3c90x_internal_IssueCommand(p->IOAddr, cmdStallCtl, upStall);
00408
00409 p->rx_ring[index].DataAddr = virt_to_bus(p->rx_iobuf[index]->data);
00410 p->rx_ring[index].DataLength = RX_BUF_SIZE | upLastFrag;
00411 p->rx_ring[index].UpPktStatus = 0;
00412
00413
00414 a3c90x_internal_IssueCommand(p->IOAddr, cmdStallCtl, upUnStall);
00415 }
00416
00417
00418
00419
00420
00421
00422
00423
00424 static void a3c90x_refill_rx_ring(struct INF_3C90X *p)
00425 {
00426 int i;
00427 unsigned int status;
00428 struct RXD *rx_cur_desc;
00429
00430 DBGP("a3c90x_refill_rx_ring\n");
00431
00432 for (i = 0; i < RX_RING_SIZE; i++) {
00433 rx_cur_desc = p->rx_ring + i;
00434 status = rx_cur_desc->UpPktStatus;
00435
00436
00437 if (!(status & upComplete))
00438 continue;
00439
00440
00441 if (p->rx_iobuf[i] != NULL)
00442 continue;
00443
00444 p->rx_iobuf[i] = alloc_iob(RX_BUF_SIZE);
00445 if (p->rx_iobuf[i] == NULL) {
00446 DBG("alloc_iob() failed\n");
00447 break;
00448 }
00449
00450 a3c90x_prepare_rx_desc(p, i);
00451 }
00452 }
00453
00454
00455
00456
00457
00458
00459
00460
00461 static int a3c90x_setup_rx_ring(struct INF_3C90X *p)
00462 {
00463 int i;
00464
00465 DBGP("a3c90x_setup_rx_ring\n");
00466
00467 p->rx_ring =
00468 malloc_dma(RX_RING_SIZE * sizeof(struct RXD), RX_RING_ALIGN);
00469
00470 if (!p->rx_ring) {
00471 DBG("Could not allocate RX-ring\n");
00472 return -ENOMEM;
00473 }
00474
00475 p->rx_cur = 0;
00476
00477 for (i = 0; i < RX_RING_SIZE; i++) {
00478 p->rx_ring[i].UpNextPtr =
00479 virt_to_bus(p->rx_ring + (i + 1));
00480
00481
00482 p->rx_ring[i].UpPktStatus = upComplete;
00483 p->rx_iobuf[i] = NULL;
00484 }
00485
00486
00487 p->rx_ring[i - 1].UpNextPtr = virt_to_bus(p->rx_ring);
00488
00489 a3c90x_refill_rx_ring(p);
00490
00491 return 0;
00492 }
00493
00494 static void a3c90x_free_rx_ring(struct INF_3C90X *p)
00495 {
00496 DBGP("a3c90x_free_rx_ring\n");
00497
00498 free_dma(p->rx_ring, RX_RING_SIZE * sizeof(struct RXD));
00499 p->rx_ring = NULL;
00500 }
00501
00502 static void a3c90x_free_rx_iobuf(struct INF_3C90X *p)
00503 {
00504 int i;
00505
00506 DBGP("a3c90x_free_rx_iobuf\n");
00507
00508 for (i = 0; i < RX_RING_SIZE; i++) {
00509 free_iob(p->rx_iobuf[i]);
00510 p->rx_iobuf[i] = NULL;
00511 }
00512 }
00513
00514
00515
00516
00517
00518
00519
00520
00521 static void a3c90x_process_rx_packets(struct net_device *netdev)
00522 {
00523 int i;
00524 unsigned int rx_status;
00525 struct INF_3C90X *p = netdev_priv(netdev);
00526 struct RXD *rx_cur_desc;
00527
00528 DBGP("a3c90x_process_rx_packets\n");
00529
00530 for (i = 0; i < RX_RING_SIZE; i++) {
00531 rx_cur_desc = p->rx_ring + p->rx_cur;
00532 rx_status = rx_cur_desc->UpPktStatus;
00533
00534 if (!(rx_status & upComplete) && !(rx_status & upError))
00535 break;
00536
00537 if (p->rx_iobuf[p->rx_cur] == NULL)
00538 break;
00539
00540 if (rx_status & upError) {
00541 DBG("Corrupted packet received\n");
00542 netdev_rx_err(netdev, p->rx_iobuf[p->rx_cur],
00543 -EINVAL);
00544 } else {
00545
00546 int packet_len;
00547
00548 packet_len = rx_status & 0x1FFF;
00549 iob_put(p->rx_iobuf[p->rx_cur], packet_len);
00550
00551 DBG("received packet\n");
00552 DBG(" size: %d\n", packet_len);
00553
00554 netdev_rx(netdev, p->rx_iobuf[p->rx_cur]);
00555 }
00556
00557 p->rx_iobuf[p->rx_cur] = NULL;
00558 p->rx_cur = (p->rx_cur + 1) % RX_RING_SIZE;
00559 }
00560 a3c90x_refill_rx_ring(p);
00561
00562 }
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572 static void a3c90x_poll(struct net_device *netdev)
00573 {
00574 struct INF_3C90X *p = netdev_priv(netdev);
00575 uint16_t raw_status, int_status;
00576
00577 DBGP("a3c90x_poll\n");
00578
00579 raw_status = inw(p->IOAddr + regCommandIntStatus_w);
00580 int_status = (raw_status & 0x0FFF);
00581
00582 if ( int_status == 0 )
00583 return;
00584
00585 a3c90x_internal_IssueCommand(p->IOAddr, cmdAcknowledgeInterrupt,
00586 int_status);
00587
00588 if (int_status & INT_TXCOMPLETE)
00589 outb(0x00, p->IOAddr + regTxStatus_b);
00590
00591 DBG("poll: status = %#04x\n", raw_status);
00592
00593 a3c90x_process_tx_packets(netdev);
00594
00595 a3c90x_process_rx_packets(netdev);
00596 }
00597
00598
00599
00600 static void a3c90x_free_resources(struct INF_3C90X *p)
00601 {
00602 DBGP("a3c90x_free_resources\n");
00603
00604 a3c90x_free_tx_ring(p);
00605 a3c90x_free_rx_ring(p);
00606 a3c90x_free_rx_iobuf(p);
00607 }
00608
00609
00610
00611
00612
00613
00614
00615 static void a3c90x_remove(struct pci_device *pci)
00616 {
00617 struct net_device *netdev = pci_get_drvdata(pci);
00618 struct INF_3C90X *inf_3c90x = netdev_priv(netdev);
00619
00620 DBGP("a3c90x_remove\n");
00621
00622 a3c90x_reset(inf_3c90x);
00623
00624
00625 outw(cmdRxDisable, inf_3c90x->IOAddr + regCommandIntStatus_w);
00626 outw(cmdTxDisable, inf_3c90x->IOAddr + regCommandIntStatus_w);
00627
00628 unregister_netdev(netdev);
00629 netdev_nullify(netdev);
00630 netdev_put(netdev);
00631 }
00632
00633 static void a3c90x_irq(struct net_device *netdev, int enable)
00634 {
00635 struct INF_3C90X *p = netdev_priv(netdev);
00636
00637 DBGP("a3c90x_irq\n");
00638
00639 if (enable == 0) {
00640
00641 a3c90x_internal_IssueCommand(p->IOAddr,
00642 cmdSetInterruptEnable, 0);
00643 } else {
00644 a3c90x_internal_IssueCommand(p->IOAddr,
00645 cmdSetInterruptEnable,
00646 INT_TXCOMPLETE |
00647 INT_UPCOMPLETE);
00648 a3c90x_internal_IssueCommand(p->IOAddr,
00649 cmdAcknowledgeInterrupt,
00650 0x661);
00651 }
00652 }
00653
00654
00655
00656
00657
00658 static void a3c90x_hw_start(struct net_device *netdev)
00659 {
00660 int i, c;
00661 unsigned int cfg;
00662 unsigned int mopt;
00663 unsigned short linktype;
00664 struct INF_3C90X *inf_3c90x = netdev_priv(netdev);
00665
00666 DBGP("a3c90x_hw_start\n");
00667
00668
00669 if (inf_3c90x->is3c556) {
00670 unsigned int tmp;
00671 a3c90x_internal_SetWindow(inf_3c90x, winAddressing2);
00672 tmp = inw(inf_3c90x->IOAddr + regResetOptions_2_w);
00673 tmp |= 0x4000;
00674 outw(tmp, inf_3c90x->IOAddr + regResetOptions_2_w);
00675 }
00676
00677
00678 a3c90x_internal_SetWindow(inf_3c90x, winAddressing2);
00679 for (i = 0; i < ETH_ALEN; i++)
00680 outb(netdev->ll_addr[i],
00681 inf_3c90x->IOAddr + regStationAddress_2_3w + i);
00682 for (i = 0; i < ETH_ALEN; i++)
00683 outb(0, inf_3c90x->IOAddr + regStationMask_2_3w + i);
00684
00685
00686
00687
00688
00689
00690
00691 a3c90x_internal_SetWindow(inf_3c90x, winTxRxOptions3);
00692 mopt = inw(inf_3c90x->IOAddr + regResetMediaOptions_3_w);
00693
00694
00695 if (!inf_3c90x->isBrev) {
00696 mopt &= 0x7F;
00697 }
00698
00699 DBG("Connectors present: ");
00700 c = 0;
00701 linktype = 0x0008;
00702 if (mopt & 0x01) {
00703 DBG("%s100Base-T4", (c++) ? ", " : "");
00704 linktype = linkMII;
00705 }
00706 if (mopt & 0x04) {
00707 DBG("%s100Base-FX", (c++) ? ", " : "");
00708 linktype = link100BaseFX;
00709 }
00710 if (mopt & 0x10) {
00711 DBG("%s10Base-2", (c++) ? ", " : "");
00712 linktype = link10Base2;
00713 }
00714 if (mopt & 0x20) {
00715 DBG("%sAUI", (c++) ? ", " : "");
00716 linktype = linkAUI;
00717 }
00718 if (mopt & 0x40) {
00719 DBG("%sMII", (c++) ? ", " : "");
00720 linktype = linkMII;
00721 }
00722 if ((mopt & 0xA) == 0xA) {
00723 DBG("%s10Base-T / 100Base-TX", (c++) ? ", " : "");
00724 linktype = linkAutoneg;
00725 } else if ((mopt & 0xA) == 0x2) {
00726 DBG("%s100Base-TX", (c++) ? ", " : "");
00727 linktype = linkAutoneg;
00728 } else if ((mopt & 0xA) == 0x8) {
00729 DBG("%s10Base-T", (c++) ? ", " : "");
00730 linktype = linkAutoneg;
00731 }
00732 DBG(".\n");
00733
00734
00735
00736
00737 if (inf_3c90x->isBrev) {
00738 if ((inf_3c90x->eeprom[0x16] & 0xFF00) == XCVR_MAGIC) {
00739
00740 linktype = inf_3c90x->eeprom[0x16] & 0x000F;
00741 }
00742 } else {
00743
00744 if (linktype == linkExternalMII) {
00745 if (inf_3c90x->isBrev)
00746 DBG("WARNING: MII External MAC Mode only supported on B-revision " "cards!!!!\nFalling Back to MII Mode\n");
00747 linktype = linkMII;
00748 }
00749 }
00750
00751
00752 if (linktype == link10Base2) {
00753 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr,
00754 cmdEnableDcConverter, 0);
00755 }
00756
00757
00758 a3c90x_internal_SetWindow(inf_3c90x, winTxRxOptions3);
00759 cfg = inl(inf_3c90x->IOAddr + regInternalConfig_3_l);
00760 cfg &= ~(0xF << 20);
00761 cfg |= (linktype << 20);
00762
00763 DBG("Setting internal cfg register: 0x%08X (linktype: 0x%02X)\n",
00764 cfg, linktype);
00765
00766 outl(cfg, inf_3c90x->IOAddr + regInternalConfig_3_l);
00767
00768
00769 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdTxReset, 0x00);
00770
00771 if (!inf_3c90x->isBrev)
00772 outb(0x01, inf_3c90x->IOAddr + regTxFreeThresh_b);
00773
00774
00775 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdSetRxFilter,
00776 0x01 + 0x02 + 0x04);
00777
00778
00779
00780
00781
00782 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr,
00783 cmdSetInterruptEnable,
00784 INT_TXCOMPLETE | INT_UPCOMPLETE);
00785 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr,
00786 cmdSetIndicationEnable,
00787 INT_TXCOMPLETE | INT_UPCOMPLETE);
00788 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr,
00789 cmdAcknowledgeInterrupt, 0x661);
00790 }
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800 static int a3c90x_open(struct net_device *netdev)
00801 {
00802 int rc;
00803 struct INF_3C90X *inf_3c90x = netdev_priv(netdev);
00804
00805 DBGP("a3c90x_open\n");
00806
00807 a3c90x_hw_start(netdev);
00808
00809 rc = a3c90x_setup_tx_ring(inf_3c90x);
00810 if (rc != 0) {
00811 DBG("Error setting up TX Ring\n");
00812 goto error;
00813 }
00814
00815 rc = a3c90x_setup_rx_ring(inf_3c90x);
00816 if (rc != 0) {
00817 DBG("Error setting up RX Ring\n");
00818 goto error;
00819 }
00820
00821
00822 outl(virt_to_bus(inf_3c90x->rx_ring),
00823 inf_3c90x->IOAddr + regUpListPtr_l);
00824
00825
00826 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdTxEnable, 0);
00827 a3c90x_internal_IssueCommand(inf_3c90x->IOAddr, cmdRxEnable, 0);
00828
00829 return 0;
00830
00831 error:
00832 a3c90x_free_resources(inf_3c90x);
00833 a3c90x_reset(inf_3c90x);
00834 return rc;
00835 }
00836
00837
00838
00839
00840
00841
00842 static void a3c90x_close(struct net_device *netdev)
00843 {
00844 struct INF_3C90X *inf_3c90x = netdev_priv(netdev);
00845
00846 DBGP("a3c90x_close\n");
00847
00848 a3c90x_reset(inf_3c90x);
00849 outw(cmdRxDisable, inf_3c90x->IOAddr + regCommandIntStatus_w);
00850 outw(cmdTxDisable, inf_3c90x->IOAddr + regCommandIntStatus_w);
00851 a3c90x_free_resources(inf_3c90x);
00852 }
00853
00854 static struct net_device_operations a3c90x_operations = {
00855 .open = a3c90x_open,
00856 .close = a3c90x_close,
00857 .poll = a3c90x_poll,
00858 .transmit = a3c90x_transmit,
00859 .irq = a3c90x_irq,
00860 };
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873 static int a3c90x_probe(struct pci_device *pci,
00874 const struct pci_device_id *pci_id __unused)
00875 {
00876
00877 struct net_device *netdev;
00878 struct INF_3C90X *inf_3c90x;
00879 unsigned char *HWAddr;
00880 int rc;
00881
00882 DBGP("a3c90x_probe\n");
00883
00884 if (pci->ioaddr == 0)
00885 return -EINVAL;
00886
00887 netdev = alloc_etherdev(sizeof(*inf_3c90x));
00888 if (!netdev)
00889 return -ENOMEM;
00890
00891 netdev_init(netdev, &a3c90x_operations);
00892 pci_set_drvdata(pci, netdev);
00893 netdev->dev = &pci->dev;
00894
00895 inf_3c90x = netdev_priv(netdev);
00896 memset(inf_3c90x, 0, sizeof(*inf_3c90x));
00897
00898 adjust_pci_device(pci);
00899
00900 inf_3c90x->is3c556 = (pci->device == 0x6055);
00901 inf_3c90x->IOAddr = pci->ioaddr;
00902 inf_3c90x->CurrentWindow = winNone;
00903
00904 inf_3c90x->isBrev = 1;
00905 switch (pci->device) {
00906 case 0x9000:
00907 case 0x9001:
00908 case 0x9050:
00909 case 0x9051:
00910 inf_3c90x->isBrev = 0;
00911 break;
00912 }
00913
00914 DBG("[3c90x]: found NIC(0x%04X, 0x%04X), isBrev=%d, is3c556=%d\n",
00915 pci->vendor, pci->device, inf_3c90x->isBrev,
00916 inf_3c90x->is3c556);
00917
00918
00919 inf_3c90x->nvs.word_len_log2 = 1;
00920 inf_3c90x->nvs.size = (inf_3c90x->isBrev ? 0x20 : 0x17);
00921 inf_3c90x->nvs.block_size = 1;
00922 inf_3c90x->nvs.read = a3c90x_internal_ReadEeprom;
00923 inf_3c90x->nvs.write = a3c90x_internal_WriteEeprom;
00924
00925
00926 a3c90x_reset(inf_3c90x);
00927
00928
00929 a3c90x_internal_ReadEepromContents(inf_3c90x);
00930
00931 HWAddr = netdev->hw_addr;
00932
00933
00934 HWAddr[0] = inf_3c90x->eeprom[eepromHwAddrOffset + 0] >> 8;
00935 HWAddr[1] = inf_3c90x->eeprom[eepromHwAddrOffset + 0] & 0xFF;
00936 HWAddr[2] = inf_3c90x->eeprom[eepromHwAddrOffset + 1] >> 8;
00937 HWAddr[3] = inf_3c90x->eeprom[eepromHwAddrOffset + 1] & 0xFF;
00938 HWAddr[4] = inf_3c90x->eeprom[eepromHwAddrOffset + 2] >> 8;
00939 HWAddr[5] = inf_3c90x->eeprom[eepromHwAddrOffset + 2] & 0xFF;
00940
00941
00942 netdev_link_up(netdev);
00943
00944 if ((rc = register_netdev(netdev)) != 0) {
00945 DBG("3c90x: register_netdev() failed\n");
00946 netdev_put(netdev);
00947 return rc;
00948 }
00949
00950 return 0;
00951 }
00952
00953 static struct pci_device_id a3c90x_nics[] = {
00954
00955 PCI_ROM(0x10b7, 0x6055, "3c556", "3C556", 0),
00956 PCI_ROM(0x10b7, 0x9000, "3c905-tpo", "3Com900-TPO", 0),
00957 PCI_ROM(0x10b7, 0x9001, "3c905-t4", "3Com900-Combo", 0),
00958 PCI_ROM(0x10b7, 0x9050, "3c905-tpo100", "3Com905-TX", 0),
00959 PCI_ROM(0x10b7, 0x9051, "3c905-combo", "3Com905-T4", 0),
00960
00961 PCI_ROM(0x10b7, 0x9004, "3c905b-tpo", "3Com900B-TPO", 0),
00962 PCI_ROM(0x10b7, 0x9005, "3c905b-combo", "3Com900B-Combo", 0),
00963 PCI_ROM(0x10b7, 0x9006, "3c905b-tpb2", "3Com900B-2/T", 0),
00964 PCI_ROM(0x10b7, 0x900a, "3c905b-fl", "3Com900B-FL", 0),
00965 PCI_ROM(0x10b7, 0x9055, "3c905b-tpo100", "3Com905B-TX", 0),
00966 PCI_ROM(0x10b7, 0x9056, "3c905b-t4", "3Com905B-T4", 0),
00967 PCI_ROM(0x10b7, 0x9058, "3c905b-9058", "3Com905B-9058", 0),
00968 PCI_ROM(0x10b7, 0x905a, "3c905b-fx", "3Com905B-FL", 0),
00969
00970 PCI_ROM(0x10b7, 0x9200, "3c905c-tpo", "3Com905C-TXM", 0),
00971 PCI_ROM(0x10b7, 0x9202, "3c920b-emb-ati", "3c920B-EMB-WNM (ATI Radeon 9100 IGP)", 0),
00972 PCI_ROM(0x10b7, 0x9210, "3c920b-emb-wnm", "3Com20B-EMB WNM", 0),
00973 PCI_ROM(0x10b7, 0x9800, "3c980", "3Com980-Cyclone", 0),
00974 PCI_ROM(0x10b7, 0x9805, "3c9805", "3Com9805", 0),
00975 PCI_ROM(0x10b7, 0x7646, "3csoho100-tx", "3CSOHO100-TX", 0),
00976 PCI_ROM(0x10b7, 0x4500, "3c450", "3Com450 HomePNA Tornado", 0),
00977 PCI_ROM(0x10b7, 0x1201, "3c982a", "3Com982A", 0),
00978 PCI_ROM(0x10b7, 0x1202, "3c982b", "3Com982B", 0),
00979 };
00980
00981 struct pci_driver a3c90x_driver __pci_driver = {
00982 .ids = a3c90x_nics,
00983 .id_count = (sizeof(a3c90x_nics) / sizeof(a3c90x_nics[0])),
00984 .probe = a3c90x_probe,
00985 .remove = a3c90x_remove,
00986 };
00987
00988
00989
00990
00991
00992
00993
00994