Back to home page

Quest Cross Reference

 
 

    


Warning, cross-references for /kernel/drivers/net/pcnet.c need to be fixed.

0001 /*                    The Quest Operating System
0002  *  Copyright (C) 2005-2010  Richard West, Boston University
0003  *
0004  *  This program is free software: you can redistribute it and/or modify
0005  *  it under the terms of the GNU General Public License as published by
0006  *  the Free Software Foundation, either version 3 of the License, or
0007  *  (at your option) any later version.
0008  *
0009  *  This program is distributed in the hope that it will be useful,
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012  *  GNU General Public License for more details.
0013  *
0014  *  You should have received a copy of the GNU General Public License
0015  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
0016  */
0017 
0018 /* AMD 79C90 PCnet32/LANCE NIC driver */
0019 
0020 #include "drivers/pci/pci.h"
0021 #include "drivers/net/pcnet.h"
0022 #include "arch/i386.h"
0023 #include "util/printf.h"
0024 #include "smp/smp.h"
0025 #include "smp/apic.h"
0026 #include "mem/physical.h"
0027 #include "mem/virtual.h"
0028 #include "kernel.h"
0029 
0030 #define DEBUG_PCNET
0031 
0032 #ifdef DEBUG_PCNET
0033 #define DLOG(fmt,...) DLOG_PREFIX("PCnet",fmt,##__VA_ARGS__)
0034 #else
0035 #define DLOG(fmt,...) ;
0036 #endif
0037 
0038 /* ************************************************** */
0039 
0040 /* Basic constants */
0041 
0042 #define NUM_RX_BUFFERS_LOG2 2 /* 4 Rx buffers */
0043 
0044 #define RX_RING_SIZE (1 << NUM_RX_BUFFERS_LOG2)
0045 #define RX_RING_MOD_MASK (RX_RING_SIZE - 1)
0046 #define RX_RING_LEN_BITS ((NUM_RX_BUFFERS_LOG2) << 29)
0047 #define RX_RING_BUF_SIZE MAX_FRAME_SIZE   /* multiple of 16 */
0048 #define TX_RING_BUF_SIZE MAX_FRAME_SIZE   /* multiple of 16 */
0049 
0050 #define PCNET_VECTOR 0x4B
0051 
0052 /* CSR4: features */
0053 /* 0x915: bits 0 (JABM), 2 (TXSTRTM), 4 (RCVCCOM), 8 (MFCOM), 11 (APAD_XMIT) set */
0054 #define CSR4_FEATURES 0x915
0055 
0056 /* ************************************************** */
0057 
0058 /* PCnet data structures shared by hardware */
0059 
0060 /* using data structure mode ssize=1 (see datasheet) */
0061 
0062 struct pcnet_init_block {
0063   /* hardware-specific layout */
0064   uint16 mode;
0065   uint8  _reserved1:4;
0066   uint8  rlen:4;
0067   uint8  _reserved2:4;
0068   uint8  tlen:4;
0069   uint8  phys_addr[ETH_ADDR_LEN];
0070   uint16 _reserved3;
0071   uint32 filter[2];
0072   uint32 rx_ring;
0073   uint32 tx_ring;
0074 } PACKED;
0075 
0076 struct pcnet_rx_head {
0077   /* hardware-specific layout */
0078   union {
0079     uint32 raw;
0080     uint32 rbadr;          /* recv buf addr */
0081   } rmd0;
0082   union {
0083     uint32 raw;
0084     struct {
0085       sint16 buf_length; /* 2s complement */
0086       uint16 _reserved:4;
0087       uint16 bam:1;        /* Broadcast Address Match */
0088       uint16 lafm:1;       /* Logical Address Filter Match */
0089       uint16 pam:1;        /* Physical Address Match */
0090       uint16 bpe:1;        /* Bus Parity Error */
0091       uint16 enp:1;        /* End of Packet */
0092       uint16 stp:1;        /* Start of Packet */
0093       uint16 buff:1;       /* Buffer error (does not own next buffer)  */
0094       uint16 crc:1;        /* CRC error */
0095       uint16 oflo:1;       /* Overflow error */
0096       uint16 fram:1;       /* Framing error */
0097       uint16 err:1;        /* Any error set */
0098       uint16 own:1;        /* OWN bit (1=hw, 0=driver) */
0099     };
0100   } rmd1;
0101   union {
0102     uint32 raw;
0103     struct {
0104       uint16 msg_length;
0105       uint8 rpc;
0106       uint8 rcc;
0107     };
0108   } rmd2;
0109   uint32 _reserved;
0110 } PACKED;
0111 
0112 struct pcnet_tx_head {
0113   /* hardware-specific layout */
0114   union {
0115     uint32 raw;
0116     uint32 tbadr;          /* trans buf addr */
0117   } rmd0;
0118   union {
0119     uint32 raw;
0120     struct {
0121       sint16 buf_length; /* 2s complement */
0122       uint16 _reserved:7;
0123       uint16 bpe:1;
0124       uint16 enp:1;
0125       uint16 stp:1;
0126       /* bpe, enp, stp, def, one, more, add, err */
0127       uint16 flags:5;
0128       uint16 own:1;         /* OWN bit */
0129     };
0130   } rmd1;
0131   union {
0132     uint32 raw;            /* misc flags */
0133   } rmd2;
0134   uint32 _reserved;
0135 } PACKED;
0136 
0137 struct pcnet_interface {
0138   struct pcnet_rx_head rx_ring[RX_RING_SIZE];
0139   struct pcnet_tx_head tx_ring;
0140   struct pcnet_init_block init_block;
0141   uint8 rbuf[RX_RING_SIZE][RX_RING_BUF_SIZE] ALIGNED(16);
0142   uint8 tbuf[TX_RING_BUF_SIZE] ALIGNED(16);
0143   sint32 rx_idx;
0144 } PACKED;
0145 
0146 /* ************************************************** */
0147 
0148 /* List of compatible cards (ended by { 0xFFFF, 0xFFFF }) */
0149 static struct { uint16 vendor, device; } compatible_ids[] = {
0150   { 0x1022, 0x2000 },
0151   { 0xFFFF, 0xFFFF }
0152 };
0153 
0154 /* ************************************************** */
0155 
0156 static uint device_index, io_base, irq_line, irq_pin, version;
0157 
0158 static struct pcnet_interface* card;
0159 static uint card_phys, frame_count;
0160 
0161 /* Virtual-to-Physical */
0162 #define V2P(ty,p) ((ty)((((uint) (p)) - ((uint) card))+card_phys))
0163 /* Physical-to-Virtual */
0164 #define P2V(ty,p) ((ty)((((uint) (p)) - card_phys)+((uint) card)))
0165 
0166 static uint8 eth_addr[ETH_ADDR_LEN];
0167 
0168 /* ************************************************** */
0169 
0170 /* IO ports */
0171 
0172 #define ETH   (io_base+0x00)
0173 #define DATA  (io_base+0x10)
0174 #define ADDR  (io_base+0x12)
0175 #define RESET (io_base+0x14)
0176 #define BUS   (io_base+0x16)
0177 
0178 /* ************************************************** */
0179 
0180 static bool
0181 probe (void)
0182 {
0183   uint i;
0184 
0185   /* assume io_base set */
0186   outw (inw (RESET), RESET);
0187 
0188   /* expect set CSR0 bit 4 (STOPped) */
0189   outw (0, ADDR); (void) inw (ADDR);
0190   if (inw (DATA) != 4) {
0191     DLOG ("expected STOP bit set");
0192     return FALSE;
0193   }
0194 
0195   /* check BCR20 for 32-bit support */
0196   outw (20, ADDR); (void) inw (ADDR);
0197   outw (inw (BUS) | 0x102, BUS); /* set our style */
0198   outw (20, ADDR); (void) inw (ADDR);
0199   if ((inw (BUS) & 0x1FF) != 0x102) {
0200     DLOG ("SSIZE!=1 and SWSTYLE!=2 (BCR20=%p)", inw (BUS));
0201     return FALSE;
0202   }
0203 
0204   /* get version (CSR88, CSR89) */
0205   outw (88, ADDR);
0206   if (inw (ADDR) != 88) {
0207     DLOG ("Unsupported (ancient) chip");
0208     return FALSE;
0209   } else {
0210     version = inw (DATA);
0211     outw (89, ADDR); (void) inw (ADDR);
0212     version |= inw (DATA) << 16;
0213 
0214     if ((version & 0xfff) != 3) {
0215       DLOG ("malformed version %p", version);
0216       return FALSE;
0217     }
0218 
0219     version >>= 12;
0220     if (version != 0x2621) {
0221       DLOG ("version=%p is not supported", version);
0222       return FALSE;
0223     }
0224   }
0225 
0226   /* set CSR4 (features) */
0227   outw (4, ADDR); (void) inw (ADDR);
0228   outw (CSR4_FEATURES, DATA);
0229 
0230   /* CSR0 */
0231   outw (0, ADDR); (void) inw (ADDR);
0232 
0233   /* Get ethernet hardware address */
0234   for (i=0; i< ETH_ADDR_LEN; i++)
0235     eth_addr[i] = inb (ETH+i);
0236 
0237   /* enable auto-select of media (BCR2 bit 1: ASEL) */
0238   outw (2, ADDR); (void) inw (ADDR);
0239   outw (inw (BUS) | 2, BUS);
0240 
0241   DLOG ("version=%p eth_addr=%.02x:%.02x:%.02x:%.02x:%.02x:%.02x",
0242         version,
0243         eth_addr[0], eth_addr[1], eth_addr[2],
0244         eth_addr[3], eth_addr[4], eth_addr[5]);
0245 
0246   return TRUE;
0247 }
0248 
0249 static void
0250 reset (void)
0251 {
0252   uint i, phys_init;
0253 
0254   (void) inw (RESET);           /* read is sufficient to reset */
0255 
0256   /* enable auto-select of media (BCR2 bit 1: ASEL) */
0257   outw (2, ADDR); (void) inw (ADDR);
0258   outw (inw (BUS) | 2, BUS);
0259 
0260   /* setup station hardware address */
0261   for (i=0; i<ETH_ADDR_LEN; i++)
0262     card->init_block.phys_addr[i] = eth_addr[i];
0263 
0264   /* preset rx ring headers */
0265   for (i=0; i<RX_RING_SIZE; i++) {
0266     card->rx_ring[i].rmd1.buf_length = -RX_RING_BUF_SIZE;
0267     card->rx_ring[i].rmd0.rbadr = V2P (uint32, card->rbuf[i]);
0268     card->rx_ring[i].rmd1.own = 1;
0269   }
0270   card->tx_ring.rmd1.buf_length = -TX_RING_BUF_SIZE;
0271   card->tx_ring.rmd0.tbadr = V2P (uint32, card->tbuf);
0272 
0273   card->rx_idx = 0;
0274   card->init_block.mode = 0;      /* enable Rx and Tx */
0275   card->init_block.filter[0] = card->init_block.filter[1] = 0;
0276 
0277   /* multiple Rx buffers and one Tx buffer */
0278   card->init_block.rx_ring = V2P (uint32, card->rx_ring);
0279   card->init_block.tx_ring = V2P (uint32, &card->tx_ring);
0280   card->init_block.rlen = NUM_RX_BUFFERS_LOG2;
0281   card->init_block.tlen = 0;
0282 
0283   phys_init = V2P (uint, &card->init_block);
0284 
0285   DLOG ("phys_init=%p rx_ring=%p tx_ring=%p rbuf[0]=%p tbuf=%p",
0286         phys_init, card->init_block.rx_ring, card->init_block.tx_ring,
0287         V2P (uint, card->rbuf[0]), V2P (uint, card->tbuf));
0288 
0289   outw (0, ADDR); (void) inw (ADDR);
0290   outw (4, DATA);               /* STOP */
0291 
0292   /* tell card where init block is found (physically) */
0293 
0294   /* CSR1=low 16-bits */
0295   outw (1, ADDR); (void) inw (ADDR);
0296   outw ((uint16) phys_init, DATA);
0297 
0298   /* CSR2=high 16-bits */
0299   outw (2, ADDR); (void) inw (ADDR);
0300   outw ((uint16) (phys_init >> 16), DATA);
0301 
0302   /* CSR4 (features) */
0303   outw (4, ADDR); (void) inw (ADDR);
0304   outw (CSR4_FEATURES, DATA);
0305 
0306   outw (0, ADDR); (void) inw (ADDR);
0307   outw (1, DATA);               /* INIT */
0308 
0309   /* check for IDON (init done) */
0310   for (i=10000; i > 0; i--)
0311     if (inw (DATA) & 0x100)
0312       break;
0313   if (i <= 0)
0314     DLOG ("reset: INIT timed out");
0315 
0316   outw (0x142, DATA);            /* assert START + clear IDON + set IENA
0317                                   * (interrupt enable) */
0318 
0319   DLOG ("reset: complete.  CSR0=%p", inw (DATA));
0320 }
0321 
0322 extern sint
0323 pcnet_transmit (uint8* buf, sint len)
0324 {
0325   DLOG ("pcnet_transmit (%p, %d)", buf, len);
0326   if (card->tx_ring.rmd1.own != 0) {
0327     /* we don't control the transmit buffer at the moment */
0328     return 0;
0329   } else if (len > MAX_FRAME_SIZE) {
0330     /* too big */
0331     return -1;
0332   } else {
0333     /* copy into transmission buffer */
0334     memcpy (card->tbuf, buf, len);
0335     /* set tbuf length */
0336     card->tx_ring.rmd1.buf_length = -len;
0337     /* clear misc. info */
0338     card->tx_ring.rmd2.raw = 0;
0339     /* this is a single packet, start and end */
0340     card->tx_ring.rmd1.stp = card->tx_ring.rmd1.enp = 1;
0341     /* pass ownership to NIC */
0342     card->tx_ring.rmd1.own = 1;
0343     /* trigger a send poll */
0344     outw (0, ADDR); (void) inw (ADDR);
0345     outw (0x48, DATA);
0346   }
0347   return len;
0348 }
0349 
0350 static void
0351 pcnet_drop_packet (uint8* packet, uint len)
0352 {
0353   DLOG ("dropping packet (%p, %d)", packet, len);
0354 }
0355 
0356 static ethernet_device pcnet_ethdev;
0357 
0358 static void
0359 pcnet_poll (void)
0360 {
0361   uint32 entry;
0362   uint32* ptr;
0363 
0364   entry = card->rx_idx & RX_RING_MOD_MASK;
0365 
0366   while (card->rx_ring[entry].rmd1.own == 0) {
0367     if (card->rx_ring[entry].rmd1.enp == 1 &&
0368         card->rx_ring[entry].rmd1.stp == 1) {
0369       /* full packet awaits */
0370       ptr = P2V (uint32*, card->rx_ring[entry].rmd0.rbadr);
0371 
0372       DLOG ("  recv entry=%d rmd1=%p msglen=%x",
0373             entry, card->rx_ring[entry].rmd1.raw,
0374             card->rx_ring[entry].rmd2.msg_length);
0375       DLOG ("    %.08X %.08X %.08X %.08X",
0376             ptr[0], ptr[1], ptr[2], ptr[3]);
0377 
0378       /* do something with packet */
0379       if (pcnet_ethdev.recv_func)
0380         pcnet_ethdev.recv_func (&pcnet_ethdev, (uint8*)ptr, 
0381                                 card->rx_ring[entry].rmd2.msg_length);
0382       else
0383         pcnet_drop_packet ((uint8*)ptr, card->rx_ring[entry].rmd2.msg_length);
0384     } else {
0385       /* not a full packet -- error */
0386       DLOG ("  recv error not full packet entry=%d rmd1=%p",
0387             entry, card->rx_ring[entry].rmd1.raw);
0388     }
0389 
0390     /* clear errors */
0391     card->rx_ring[entry].rmd1.raw &= 0x030fffff;
0392     /* clear msg_length */
0393     card->rx_ring[entry].rmd2.raw = 0;
0394     /* set length */
0395     card->rx_ring[entry].rmd1.buf_length = -RX_RING_BUF_SIZE;
0396     /* set OWN */
0397     card->rx_ring[entry].rmd1.own = 1;
0398 
0399     /* check next entry */
0400     entry = (++card->rx_idx) & RX_RING_MOD_MASK;
0401   }
0402 }
0403 
0404 static void
0405 handle_rint (void)
0406 {
0407   DLOG ("IRQ: RINT rx_ring=%.01x %p %.01x %p %.01x %p %.01x %p",
0408         card->rx_ring[0].rmd1.own, card->rx_ring[0].rmd0.rbadr,
0409         card->rx_ring[1].rmd1.own, card->rx_ring[1].rmd0.rbadr,
0410         card->rx_ring[2].rmd1.own, card->rx_ring[2].rmd0.rbadr,
0411         card->rx_ring[3].rmd1.own, card->rx_ring[3].rmd0.rbadr);
0412 
0413   pcnet_poll ();
0414 }
0415 
0416 static void
0417 handle_tint (void)
0418 {
0419   DLOG ("IRQ: TINT tx_ring=%.01x %p",
0420         card->tx_ring.rmd1.own, card->tx_ring.rmd0.tbadr);
0421 }
0422 
0423 static uint32
0424 pcnet_irq_handler (uint8 vec)
0425 {
0426   uint16 csr0;
0427   lock_kernel ();
0428 
0429   outw (0, ADDR); (void) inw (ADDR);
0430   csr0 = inw (DATA);
0431 
0432   DLOG ("IRQ: vec=%.02X csr0=%.04X", vec, csr0);
0433 
0434   /* acknowledge interrupt sources */
0435   outw (csr0 & ~0x004f, DATA);
0436 
0437   if (csr0 & 0x8000) {          /* ERR */
0438     if (csr0 & 0x1000)          /* MISS */
0439       DLOG ("IRQ: missed packet");
0440     if (csr0 & 0x2000)          /* CERR */
0441       DLOG ("IRQ: collision detected");
0442   }
0443 
0444   if (csr0 & 0x400)             /* RINT */
0445     handle_rint ();
0446   if (csr0 & 0x200)             /* TINT */
0447     handle_tint ();
0448 
0449   /* ack anything further and set IENA */
0450   outw (0, ADDR); (void) inw (ADDR);
0451   outw (0x7940, DATA);
0452 
0453   DLOG ("IRQ: finished. csr0=%.04X", inw (DATA));
0454 
0455   unlock_kernel ();
0456   return 0;
0457 }
0458 
0459 extern bool
0460 pcnet_get_hwaddr (uint8 addr[ETH_ADDR_LEN])
0461 {
0462   uint i;
0463   for (i=0;i<ETH_ADDR_LEN;i++)
0464     addr[i] = eth_addr[i];
0465   return TRUE;
0466 }
0467 
0468 extern bool
0469 pcnet_init (void)
0470 {
0471   uint i;
0472 
0473   if (mp_ISA_PC) {
0474     DLOG ("Cannot operate without PCI support");
0475     goto abort;
0476   }
0477 
0478   for (i=0; compatible_ids[i].vendor != 0xFFFF; i++)
0479     if (pci_find_device (compatible_ids[i].vendor, compatible_ids[i].device,
0480                          0xFF, 0xFF, 0, &device_index))
0481       break;
0482     else
0483       device_index = ~0;
0484 
0485   if (device_index == (uint)(~0)) {
0486     DLOG ("Unable to detect compatible device.");
0487     goto abort;
0488   }
0489 
0490   DLOG ("Found device_index=%d sizeof (pcnet_interface)=%d",
0491         device_index, sizeof (struct pcnet_interface));
0492 
0493   if (!pci_decode_bar (device_index, 0, NULL, &io_base, NULL)) {
0494     DLOG ("Invalid PCI configuration or BAR0 not found");
0495     goto abort;
0496   }
0497 
0498   if (io_base == 0) {
0499     DLOG ("Memory-mapped I/O not implemented");
0500     goto abort;
0501   }
0502 
0503   DLOG ("Using io_base=%.04X", io_base);
0504 
0505   if (!pci_get_interrupt (device_index, &irq_line, &irq_pin)) {
0506     DLOG ("Unable to get IRQ");
0507     goto abort;
0508   }
0509 
0510   DLOG ("Using IRQ line=%.02X pin=%X", irq_line, irq_pin);
0511 
0512   /* I need contiguous physical and virtual memory here */
0513   frame_count = sizeof (struct pcnet_interface) >> 12;
0514   if (sizeof (struct pcnet_interface) & 0xFFF)
0515     frame_count++;              /* round up */
0516 
0517   /* Obtain contiguous physical frames. */
0518   card_phys = alloc_phys_frames (frame_count);
0519 
0520   if (card_phys == -1) {
0521     DLOG ("Unable to allocate physical memory");
0522     goto abort;
0523   }
0524 
0525   /* Map contiguous virtual pages to contiguous physical frames. */
0526   card = (struct pcnet_interface *)
0527     map_contiguous_virtual_pages (card_phys | 3, frame_count);
0528 
0529   if (card == NULL) {
0530     DLOG ("Unable to allocate virtual memory");
0531     goto abort_phys;
0532   }
0533 
0534   /* zero the acquired memory */
0535   memset (card, 0, sizeof (struct pcnet_interface));
0536 
0537   DLOG ("DMA region at virt=%p phys=%p count=%d", card, card_phys, frame_count);
0538 
0539   if (!probe ()) {
0540     DLOG ("probe failed");
0541     goto abort_virt;
0542   }
0543 
0544   /* Map IRQ to handler */
0545   pci_irq_t irq;
0546   pci_device pdev;
0547   if (!pci_get_device (device_index, &pdev)) {
0548     DLOG ("pci_get_device");
0549     goto abort_virt;
0550   }
0551 
0552   if (pci_irq_find (pdev.bus, pdev.slot, irq_pin, &irq)) {
0553     /* use PCI routing table */
0554     DLOG ("Found PCI routing entry irq.gsi=0x%x", irq.gsi);
0555     if (!pci_irq_map_handler (&irq, pcnet_irq_handler, 0x01,
0556                               IOAPIC_DESTINATION_LOGICAL,
0557                               IOAPIC_DELIVERY_FIXED)) {
0558       DLOG ("Failed to map IRQ");
0559       goto abort_virt;
0560     }
0561     irq_line = irq.gsi;
0562   } else {
0563     DLOG ("Unable to find PCI routing entry");
0564     goto abort_virt;
0565   }
0566 
0567   reset ();
0568 
0569   /* Register network device with net subsystem */
0570   pcnet_ethdev.recv_func = NULL;
0571   pcnet_ethdev.send_func = pcnet_transmit;
0572   pcnet_ethdev.get_hwaddr_func = pcnet_get_hwaddr;
0573   pcnet_ethdev.poll_func = pcnet_poll;
0574 
0575   if (!net_register_device (&pcnet_ethdev)) {
0576     DLOG ("registration failed");
0577     goto abort_virt;
0578   }
0579 
0580   return TRUE;
0581  abort_virt:
0582   unmap_virtual_pages (card, frame_count);
0583  abort_phys:
0584   free_phys_frames (card_phys, frame_count);
0585  abort:
0586   return FALSE;
0587 }
0588 
0589 /* ************************************************** */
0590 
0591 #include "module/header.h"
0592 
0593 static const struct module_ops mod_ops = {
0594   .init = pcnet_init
0595 };
0596 
0597 DEF_MODULE (net___pcnet, "pcnet network driver", &mod_ops, {"net___ethernet", "pci"});
0598 
0599 /* 
0600  * Local Variables:
0601  * indent-tabs-mode: nil
0602  * mode: C
0603  * c-file-style: "gnu"
0604  * c-basic-offset: 2
0605  * End: 
0606  */
0607 
0608 /* vi: set et sw=2 sts=2: */