Back to home page

Quest Cross Reference

 
 

    


Warning, cross-references for /kernel/drivers/net/e1000.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 /* Intel e1000 NIC driver */
0019 
0020 #include "drivers/pci/pci.h"
0021 #include "drivers/net/ethernet.h"
0022 #include "arch/i386.h"
0023 #include "arch/i386-percpu.h"
0024 #include "util/printf.h"
0025 #include "smp/smp.h"
0026 #include "smp/apic.h"
0027 #include "mem/physical.h"
0028 #include "mem/virtual.h"
0029 #include "kernel.h"
0030 #include "sched/vcpu.h"
0031 
0032 #define EEPROM_MICROWIRE
0033 //#define DEBUG_E1000
0034 //#define LOOPBACK_MODE
0035 
0036 typedef struct {
0037   uint16 word_size, delay_usec, address_bits, opcode_bits;
0038   bool need_acquire;
0039 } nvm_info_t;
0040 
0041 nvm_info_t i82543_nvm = {
0042   .word_size = 64, .delay_usec = 50, .address_bits = 6, .opcode_bits = 3,
0043   .need_acquire = FALSE
0044 };
0045 
0046 nvm_info_t *nvm = &i82543_nvm;
0047 
0048 #ifdef DEBUG_E1000
0049 #define DLOG(fmt,...) DLOG_PREFIX("e1000",fmt,##__VA_ARGS__)
0050 #else
0051 #define DLOG(fmt,...) ;
0052 #endif
0053 
0054 #define RDESC_COUNT 8           /* must be multiple of 8 */
0055 #define RDESC_COUNT_MOD_MASK (RDESC_COUNT - 1)
0056 #define RBUF_SIZE   2048        /* configured in RCTL.BSIZE */
0057 #define RBUF_SIZE_MASK 0        /* 0 = 2048 bytes */
0058 
0059 #define TDESC_COUNT 8           /* must be multiple of 8 */
0060 #define TDESC_COUNT_MOD_MASK (RDESC_COUNT - 1)
0061 #define TBUF_SIZE   2048        /* configured in TCTL.BSIZE */
0062 #define TBUF_SIZE_MASK 0        /* 0 = 2048 bytes */
0063 #define TCTL_CT_MASK   0x100
0064 #define TCTL_COLD_MASK 0x40000
0065 #define TIPG_MASK (10 | (10 << 10) | (10 << 20))
0066 
0067 /* List of compatible cards (ended by { 0xFFFF, 0xFFFF }) */
0068 static struct { uint16 vendor, device; } compatible_ids[] = {
0069   { 0x8086, 0x1004 },
0070   { 0x8086, 0x1008 },
0071   { 0x8086, 0x100E },
0072   { 0xFFFF, 0xFFFF }
0073 };
0074 
0075 static uint8 hwaddr[ETH_ADDR_LEN];
0076 static uint device_index, mem_addr, irq_line, irq_pin, e1000_phys;
0077 static volatile uint32 *mmio_base;
0078 #define E1000_MMIO_PAGES 0x10
0079 
0080 /* ************************************************** */
0081 
0082 /* registers */
0083 
0084 #define REG(x) (mmio_base[x])
0085 
0086 #define CTRL   (REG (0x00))     /* Control */
0087 #define CTRL_FD   (0x1)         /* Full-Duplex */
0088 #define CTRL_LRST (0x8)         /* Link Reset */
0089 #define CTRL_ASDE (0x20)        /* Auto-Speed Detection */
0090 #define CTRL_SLU (0x40)         /* Set Link Up */
0091 #define CTRL_ILOS (0x80)        /* Invert Loss-of-Signal */
0092 #define CTRL_SPDSEL (0x300)     /* Speed Selector bits */
0093 #define CTRL_SPD1000 (0x200)    /* Set 1000Mbit */
0094 #define CTRL_FRCSPD (0x800)     /* Force Speed */
0095 #define CTRL_FRCDPLX (0x1000)   /* Force Duplex */
0096 #define CTRL_RST (1<<26)        /* Reset */
0097 #define CTRL_RFCE (1<<27)       /* RX Flow Control Enable */
0098 #define CTRL_TFCE (1<<28)       /* TX Flow Control Enable */
0099 #define CTRL_PHYRST (1<<31)     /* PHY Reset */
0100 #define STATUS (REG (0x02))     /* Device Status */
0101 #define STATUS_FD (0x1)         /* Full-Duplex indicator */
0102 #define EECD   (REG (0x04))     /* EEPROM Control/Data */
0103 #define EECD_SK (0x1)           /* Clock Input */
0104 #define EECD_CS (0x2)           /* Chip Select */
0105 #define EECD_DI (0x4)           /* Data Input */
0106 #define EECD_DO (0x8)           /* Data Output */
0107 #define EECD_REQ (0x40)         /* Request Access */
0108 #define EECD_GNT (0x80)         /* Access Granted */
0109 #define EERD   (REG (0x05))     /* EEPROM Read */
0110 #define CTRLEXT (REG (0x06))    /* Extended Control */
0111 #define CTRLEXT_EERST (1<<13)   /* EEPROM Reset */
0112 #define MDIC   (REG (0x08))     /* MDI Control */
0113 #define ICR    (REG (0x30))     /* Interrupt Cause Read */
0114 #define ICR_RXT (0x80)          /* RX Timer Int. */
0115 #define ICR_RXO (0x40)          /* RX Overrun Int. */
0116 #define ICR_TXQE (0x02)         /* TX Queue Empty Int. */
0117 #define IMS    (REG (0x34))     /* Interrupt Mask Set */
0118 #define IMS_RXT (0x80)          /* RX Timer Int. */
0119 #define IMS_RXO (0x40)          /* RX Overrun Int. */
0120 #define IMS_TXQE (0x02)         /* TX Queue Empty Int. */
0121 #define RCTL   (REG (0x40))     /* Receive Control */
0122 #define RCTL_EN (0x02)          /* RX Enable */
0123 #define RCTL_BAM (1<<15)        /* Accept Broadcast packets */
0124 #define RCTL_BSIZE (0x30000)    /* Buffer size */
0125 #define RCTL_BSEX (1<<25)       /* "Extension" (x16) of size */
0126 #define TXCW   (REG (0x5E))     /* TX Config Word */
0127 #define TXCW_ANE (1<<31)        /* Auto-Negotiate Enable */
0128 #define TCTL   (REG (0x100))    /* Transmit Control */
0129 #define TCTL_EN (0x02)          /* TX Enable */
0130 #define TCTL_PSP (0x08)         /* TX Pad Short Packets */
0131 #define TCTL_CT (0xFF0)         /* TX Collision Threshold */
0132 #define TCTL_COLD (0x3FF000)    /* TX Collision Distance */
0133 #define TIPG   (REG (0x104))    /* TX Inter Packet Gap */
0134 #define RDBAL  (REG (0xA00))    /* RX Desc. Base Address Low */
0135 #define RDBAH  (REG (0xA01))    /* RX Desc. Base Address High */
0136 #define RDLEN  (REG (0xA02))    /* RX Desc. Length */
0137 #define RDH    (REG (0xA04))    /* RX Desc Head */
0138 #define RDT    (REG (0xA06))    /* RX Desc Tail */
0139 #define TDBAL  (REG (0xE00))    /* TX Desc. Base Address Low */
0140 #define TDBAH  (REG (0xE01))    /* TX Desc. Base Address High */
0141 #define TDLEN  (REG (0xE02))    /* TX Desc. Length */
0142 #define TDH    (REG (0xE04))    /* TX Desc Head */
0143 #define TDT    (REG (0xE06))    /* TX Desc Tail */
0144 #define RAL    (REG (0x1500))   /* RX HW Address Low */
0145 #define RAH    (REG (0x1501))   /* RX HW Address High */
0146 #define TPT    (REG (0x1035))   /* Total Packets Transmitted */
0147 
0148 #define WRITE_FLUSH (void) STATUS
0149 
0150 /* ************************************************** */
0151 
0152 /* Receive descriptor (16-bytes) describes a buffer in memory */
0153 struct e1000_rdesc {
0154   uint64 address;
0155   uint16 length;
0156   uint16 checksum;
0157   uint8  status;
0158   uint8  errors;
0159   uint16 special;
0160 } PACKED;
0161 #define RDESC_STATUS_DD  0x01    /* indicates hardware done with descriptor */
0162 #define RDESC_STATUS_EOP 0x02    /* indicates end of packet */
0163 
0164 /* ************************************************** */
0165 
0166 /* Transmit descriptor (16-bytes) describes a buffer in memory */
0167 struct e1000_tdesc {
0168   uint64 address;
0169   uint16 length;
0170   uint8  cso;                   /* checksum offset */
0171   uint8  cmd;                   /* command */
0172   uint8  sta:4;                 /* status */
0173   uint8  rsv:4;                 /* reserved */
0174   uint8  css;                   /* checksum start */
0175   uint16 special;
0176 } PACKED;
0177 #define TDESC_STA_DD   0x01 /* indicates hardware done with descriptor */
0178 #define TDESC_CMD_EOP  0x01 /* indicates end of packet */
0179 #define TDESC_CMD_IFCS 0x02 /* insert frame checksum (FCS) */
0180 #define TDESC_CMD_RS   0x08 /* requests status report */
0181 
0182 /* ************************************************** */
0183 
0184 static struct e1000_interface {
0185   struct e1000_rdesc rdescs[RDESC_COUNT] ALIGNED(0x10);
0186   struct e1000_tdesc tdescs[TDESC_COUNT] ALIGNED(0x10);
0187   uint8 rbufs[RDESC_COUNT][RBUF_SIZE];
0188   uint8 tbufs[TDESC_COUNT][TBUF_SIZE];
0189   uint  rx_idx;                 /* current RX descriptor */
0190   uint  tx_cnt;                 /* number of pending TX descriptors */
0191 } *e1000;
0192 
0193 /* Virtual-to-Physical */
0194 #define V2P(ty,p) ((ty)((((uint) (p)) - ((uint) e1000))+e1000_phys))
0195 /* Physical-to-Virtual */
0196 #define P2V(ty,p) ((ty)((((uint) (p)) - e1000_phys)+((uint) e1000)))
0197 
0198 static ethernet_device e1000_ethdev;
0199 static pci_device e1000_pci_device;
0200 
0201 /* ************************************************** */
0202 
0203 extern bool
0204 e1000_get_hwaddr (uint8 a[ETH_ADDR_LEN])
0205 {
0206   int i;
0207   for (i=0; i<ETH_ADDR_LEN; i++)
0208     a[i] = hwaddr[i];
0209   return TRUE;
0210 }
0211 
0212 extern sint
0213 e1000_transmit (uint8* buffer, sint len)
0214 {
0215   struct e1000_tdesc *td;
0216   uint32 tdt = TDT;
0217   DLOG ("TX: (%p, %d) TDH=%d TDT=%d", buffer, len, TDH, tdt);
0218   DLOG ("TX:   %.02X %.02X %.02X %.02X %.02X %.02X %.02X %.02X",
0219         buffer[0], buffer[1], buffer[2], buffer[3],
0220         buffer[4], buffer[5], buffer[6], buffer[7]);
0221   DLOG ("TX:   %.02X %.02X %.02X %.02X %.02X %.02X %.02X %.02X",
0222         buffer[8], buffer[9], buffer[10], buffer[11],
0223         buffer[12], buffer[13], buffer[14], buffer[15]);
0224 
0225   if (len > TBUF_SIZE)
0226     return 0;
0227 
0228   if (e1000->tx_cnt >= TDESC_COUNT - 1) /* overrun */
0229     return 0;
0230 
0231   /* set up the first available descriptor */
0232   memcpy (e1000->tbufs[tdt], buffer, len);
0233   e1000->tdescs[tdt].length = len;
0234   e1000->tdescs[tdt].cmd = TDESC_CMD_IFCS | TDESC_CMD_RS | TDESC_CMD_EOP;
0235   td = &e1000->tdescs[tdt];
0236 
0237   /* advance the TDT, notifying hardware */
0238   tdt++;
0239   if (tdt >= TDESC_COUNT)
0240     tdt = 0;
0241   TDT = tdt;
0242 
0243   e1000->tx_cnt++;
0244 
0245   return len;
0246 }
0247 
0248 u32 e1000_packet_count = 0;
0249 u64 e1000_packet_bytes = 0;
0250 
0251 extern void
0252 e1000_rx_poll (void)
0253 {
0254   uint32 entry, rdt;
0255   uint8 *ptr;
0256 
0257   DLOG ("RX: %d %d %d %d %d %d %d %d",
0258         e1000->rdescs[0].status & RDESC_STATUS_DD,
0259         e1000->rdescs[1].status & RDESC_STATUS_DD,
0260         e1000->rdescs[2].status & RDESC_STATUS_DD,
0261         e1000->rdescs[3].status & RDESC_STATUS_DD,
0262         e1000->rdescs[4].status & RDESC_STATUS_DD,
0263         e1000->rdescs[5].status & RDESC_STATUS_DD,
0264         e1000->rdescs[6].status & RDESC_STATUS_DD,
0265         e1000->rdescs[7].status & RDESC_STATUS_DD);
0266 
0267   entry = e1000->rx_idx & RDESC_COUNT_MOD_MASK;
0268   while (e1000->rdescs[entry].status & RDESC_STATUS_DD) {
0269     if (e1000->rdescs[entry].status & RDESC_STATUS_EOP) {
0270       uint16 len;
0271       /* full packet */
0272       ptr = e1000->rbufs[entry];
0273       len = e1000->rdescs[entry].length;
0274       DLOG ("RX: full packet@%p len=%d", ptr, len);
0275       e1000_packet_count++;
0276       e1000_packet_bytes += len;
0277       if (e1000_ethdev.recv_func)
0278         e1000_ethdev.recv_func (&e1000_ethdev, ptr, len);
0279       else                      /* drop it */
0280         DLOG ("recv_func is null");
0281     } else {
0282       /* error */
0283       DLOG ("RX: error. status=%p", e1000->rdescs[entry].status);
0284     }
0285 
0286     /* clear status */
0287     e1000->rdescs[entry].status = 0;
0288 
0289     /* advance "tail" to notify hardware */
0290     rdt = RDT;
0291     rdt++;
0292     if (rdt >= RDESC_COUNT)
0293       rdt = 0;
0294     RDT = rdt;
0295 
0296     /* check next entry */
0297     entry = (++e1000->rx_idx) & RDESC_COUNT_MOD_MASK;
0298   }
0299 }
0300 
0301 static void
0302 handle_tx (uint32 icr)
0303 {
0304   uint i;
0305   DLOG ("TX: tx_cnt=%d", e1000->tx_cnt);
0306 
0307   /* find descriptors that have completed */
0308   for (i=0; i<TDESC_COUNT; i++) {
0309     if (e1000->tdescs[i].cmd && (e1000->tdescs[i].sta & TDESC_STA_DD)) {
0310       e1000->tdescs[i].cmd = 0;
0311       e1000->tdescs[i].sta = 0;
0312       e1000->tx_cnt--;
0313     }
0314   }
0315 }
0316 
0317 extern void
0318 e1000_poll (void)
0319 {
0320   e1000_rx_poll ();
0321   handle_tx (ICR_TXQE);
0322 }
0323 
0324 #ifdef E1000_DEBUG
0325 static uint16
0326 mdi_read (uint8 phy_reg)
0327 {
0328   uint32 mdic =
0329     ((phy_reg & 0x1F) << 16) |
0330     (1 << 21) |                 /* PHYADD=1 */
0331     (1 << 27);                  /* OP=READ */
0332   DLOG ("mdi_read sending %p", mdic);
0333   MDIC = mdic;
0334   while (!((mdic=MDIC) & 0x50000000LL))
0335     asm volatile ("pause");
0336   DLOG ("mdi_read MDIC=%p", mdic);
0337   if (mdic & 0x40000000LL)
0338     /* error */
0339     return 0;
0340   else
0341     return mdic & 0xFFFF;
0342 }
0343 
0344 static bool
0345 mdi_write (uint8 phy_reg, uint16 val)
0346 {
0347   uint32 mdic =
0348     ((phy_reg & 0x1F) << 16) |
0349     (1 << 21) |                 /* PHYADD=1 */
0350     (1 << 26) |                 /* OP=WRITE */
0351     (val & 0xFFFF);
0352   DLOG ("mdi_write sending %p", mdic);
0353   MDIC = mdic;
0354   while (!((mdic=MDIC) & 0x50000000LL))
0355     asm volatile ("pause");
0356   DLOG ("mdi_write MDIC=%p", mdic);
0357   if (mdic & 0x40000000LL)
0358     /* error */
0359     return FALSE;
0360   else
0361     return TRUE;
0362 }
0363 #endif
0364 
0365 static uint32 e1000_bh_stack[1024] ALIGNED (0x1000);
0366 static task_id e1000_bh_id = 0;
0367 static void
0368 e1000_bh_thread (void)
0369 {
0370   for (;;) {
0371     /* ICR is cleared upon read; this implicitly acknowledges the
0372      * interrupt. */
0373     uint32 icr = ICR;
0374     DLOG ("IRQ: ICR=%p CTRL=%p CTRLE=%p STA=%p", icr, CTRL, CTRLEXT, STATUS);
0375     //DLOG ("PHY_CTL=0x%.04X", mdi_read (0));
0376     //DLOG ("PHY_STA=0x%.04X", mdi_read (1));
0377     //DLOG ("PHY_GCON=0x%.04X", mdi_read (9));
0378     //DLOG ("PHY_GSTA=0x%.04X", mdi_read (10));
0379     DLOG ("TPT=%p", TPT);
0380 
0381     if (icr & ICR_RXT)            /* RX */
0382       e1000_rx_poll ();
0383     if (icr & ICR_TXQE)           /* TX queue empty */
0384       handle_tx (icr);
0385 
0386 #if 0
0387     unlock_kernel ();
0388     sti ();
0389     tsc_delay_usec (3000);
0390     cli ();
0391     lock_kernel ();
0392 #endif
0393 
0394     iovcpu_job_completion ();
0395   }
0396 }
0397 
0398 extern DEF_PER_CPU (vcpu *, vcpu_current);
0399 static uint32
0400 e1000_irq_handler (uint8 vec)
0401 {
0402   if (e1000_bh_id) {
0403     extern vcpu *vcpu_lookup (int);
0404     /* hack: use VCPU2's period */
0405     iovcpu_job_wakeup (e1000_bh_id, vcpu_lookup (2)->T);
0406   }
0407 
0408   return 0;
0409 }
0410 
0411 #define udelay tsc_delay_usec
0412 
0413 static bool
0414 eeprom_acquire (void)
0415 {
0416   uint32 eecd = EECD;
0417   uint32 timeout = 1000;
0418 
0419   DLOG ("eeprom_acquire EECD=%p", eecd);
0420   EECD = eecd | EECD_REQ;
0421   for (; timeout > 0; timeout--) {
0422     eecd = EECD;
0423     if (eecd & EECD_GNT)
0424       break;
0425     udelay (5);
0426   }
0427 
0428   if (timeout == 0) {
0429     DLOG ("unable to acquire EEPROM");
0430     eecd &= ~EECD_REQ;
0431     EECD = eecd;
0432     return FALSE;
0433   }
0434   return TRUE;
0435 }
0436 
0437 static void
0438 eeprom_release (void)
0439 {
0440   uint32 eecd = EECD;
0441 
0442   eecd &= ~EECD_REQ;
0443   EECD = eecd;
0444 }
0445 
0446 static void
0447 eeprom_raise_clock (uint32 *eecd)
0448 {
0449   *eecd = *eecd | EECD_SK;
0450   EECD = *eecd;
0451   WRITE_FLUSH;
0452   udelay(nvm->delay_usec);
0453 }
0454 
0455 static void
0456 eeprom_lower_clock (uint32 *eecd)
0457 {
0458   *eecd = *eecd & ~EECD_SK;
0459   EECD = *eecd;
0460   WRITE_FLUSH;
0461   udelay(nvm->delay_usec);
0462 }
0463 
0464 static void
0465 eeprom_send_bits (uint16 data, uint16 count)
0466 {
0467   uint32 eecd = EECD, mask;
0468 
0469   mask = 1 << (count - 1);
0470 
0471   /* clear data-out */
0472   eecd &= ~EECD_DO;
0473 
0474   do {
0475     /* send 1 or 0 based on current bit */
0476     if (data & mask)
0477       eecd |= EECD_DI;
0478     else
0479       eecd &= ~EECD_DI;
0480 
0481     /* write and flush it */
0482     EECD = eecd;
0483     WRITE_FLUSH;
0484 
0485     udelay (nvm->delay_usec);
0486 
0487     eeprom_raise_clock (&eecd);
0488     eeprom_lower_clock (&eecd);
0489 
0490     mask >>= 1;
0491   } while (mask);
0492 
0493   eecd &= ~EECD_DI;
0494   EECD = eecd;
0495 }
0496 
0497 static uint16
0498 eeprom_recv_bits (uint16 count)
0499 {
0500   uint32 eecd, i;
0501   uint16 data;
0502 
0503   eecd = EECD;
0504   eecd &= ~(EECD_DO | EECD_DI);
0505   data = 0;
0506 
0507   for (i=0; i<count; i++) {
0508     data <<= 1;
0509     eeprom_raise_clock (&eecd);
0510     eecd = EECD;
0511 
0512     eecd &= ~EECD_DI;           /* we are required to clear DI */
0513 
0514     if (eecd & EECD_DO)         /* read a bit */
0515       data |= 1;
0516 
0517     eeprom_lower_clock (&eecd);
0518   }
0519 
0520   return data;
0521 }
0522 
0523 static void
0524 eeprom_standby (void)
0525 {
0526   uint32 eecd = EECD;
0527 
0528   eecd &= ~(EECD_CS | EECD_SK);
0529   EECD = eecd;
0530   WRITE_FLUSH;
0531   udelay (nvm->delay_usec);
0532 
0533   eeprom_raise_clock (&eecd);
0534 
0535   eecd |= EECD_CS;
0536   EECD = eecd;
0537   WRITE_FLUSH;
0538   udelay (nvm->delay_usec);
0539 
0540   eeprom_lower_clock (&eecd);
0541 }
0542 
0543 static uint16
0544 eeprom_read (uint32 address)
0545 {
0546   uint32 eecd;
0547   uint16 data;
0548 
0549   /* Gain control of EEPROM */
0550   if (nvm->need_acquire && !eeprom_acquire ())
0551     return 0;
0552 
0553   eecd = EECD;
0554 
0555   DLOG ("eeprom_read EECD=%p", eecd);
0556 
0557   /* Make EEPROM ready */
0558 
0559   /* Clear SK and DI */
0560   eecd &= ~(EECD_DI | EECD_SK);
0561   EECD = eecd;
0562   udelay (1);
0563   /* Set CS */
0564   eecd |= EECD_CS;
0565   EECD = eecd;
0566   udelay (1);
0567 
0568   /* Start Read */
0569 
0570 #define NVM_READ_OPCODE 6
0571   eeprom_send_bits (NVM_READ_OPCODE, nvm->opcode_bits);
0572   eeprom_send_bits (address, nvm->address_bits);
0573 
0574   data = eeprom_recv_bits (16);
0575 
0576   DLOG ("eeprom said 0x%.04X", data);
0577 
0578   eeprom_standby ();
0579 
0580   /* Release control back to hardware */
0581 
0582   if (nvm->need_acquire)
0583     eeprom_release ();
0584 
0585   return data;
0586 }
0587 
0588 #ifdef LOOPBACK_MODE
0589 static void
0590 set_loopback_mode (void)
0591 {
0592   uint32 ctrl;
0593   /* p390 8254x_SDM */
0594   mdi_write (16, 0x0808);
0595   mdi_write (0, 0x9140);
0596   mdi_write (0, 0x8140);
0597   mdi_write (0, 0x4140);
0598   ctrl = CTRL;
0599   ctrl &= ~CTRL_SPDSEL;
0600   ctrl |= CTRL_FRCSPD | CTRL_FRCDPLX | CTRL_SPD1000 | CTRL_FD;
0601   if (!(STATUS & STATUS_FD))
0602     ctrl |= CTRL_ILOS | CTRL_SLU;
0603   CTRL = ctrl;
0604 }
0605 #endif
0606 
0607 static void
0608 reset (void)
0609 {
0610   uint i;
0611 
0612 #if 0
0613   /* PHY reset (before sw rst) */
0614   DLOG ("PHY PCTRL=0x%.4X", mdi_read (0));
0615   mdi_write (0, 0x9200);
0616   tsc_delay_usec (1000);
0617   DLOG ("PHY PCTRL=0x%.4X", mdi_read (0));
0618 #else
0619   /* PHY reset via CTRL */
0620   CTRL |= CTRL_PHYRST;
0621   udelay (3);
0622   CTRL &= ~CTRL_PHYRST;
0623 #endif
0624 
0625   udelay (5000);
0626 
0627   /* reset */
0628   CTRL |= CTRL_RST;             /* self-clearing */
0629   while (CTRL & CTRL_RST) tsc_delay_usec (1);
0630 
0631   /* EEPROM reset */
0632   CTRLEXT |= CTRLEXT_EERST;
0633   WRITE_FLUSH;
0634   udelay (2000);
0635 
0636   /* set hardware address */
0637   RAL =
0638     (hwaddr[0] << 0x00) |
0639     (hwaddr[1] << 0x08) |
0640     (hwaddr[2] << 0x10) |
0641     (hwaddr[3] << 0x18);
0642   RAH = 0x80000000L     |       /* Address Valid */
0643     (hwaddr[4] << 0x00) |
0644     (hwaddr[5] << 0x08);
0645 
0646   DLOG ("RAL=%p RAH=%p", RAL, RAH);
0647 
0648   /* set rx buffer size code */
0649   RCTL &= ~RCTL_BSIZE;
0650   RCTL |= RBUF_SIZE_MASK;
0651   RCTL &= ~RCTL_BSEX;
0652 
0653   /* set up rdesc addresses */
0654   for (i=0; i<RDESC_COUNT; i++) {
0655     e1000->rdescs[i].address = V2P (uint64, e1000->rbufs[i]);
0656     e1000->rdescs[i].status = 0;
0657   }
0658 
0659   /* program the rdesc base address and length */
0660   RDBAL = V2P (uint32, e1000->rdescs);
0661   RDBAH = 0;
0662   RDLEN = RDESC_COUNT * sizeof (struct e1000_rdesc);
0663 
0664   /* set head, tail of rx ring buffer */
0665   RDH = 0;
0666   RDT = RDESC_COUNT - 1;
0667 
0668   e1000->rx_idx = 0;
0669 
0670   DLOG ("RDBAL=%p RDLEN=%p RDH=%d RDT=%d",
0671         V2P (uint32, e1000->rdescs), RDESC_COUNT * sizeof (struct e1000_rdesc),
0672         RDH, RDT);
0673 
0674   /* set up tdesc addresses */
0675   for (i=0; i<TDESC_COUNT; i++) {
0676     e1000->tdescs[i].address = V2P (uint64, e1000->tbufs[i]);
0677     e1000->tdescs[i].sta = 0;
0678   }
0679 
0680   /* program the tdesc base address and length */
0681   TDBAL = V2P (uint32, e1000->tdescs);
0682   TDBAH = 0;
0683   TDLEN = TDESC_COUNT * sizeof (struct e1000_tdesc);
0684 
0685   /* set head, tail of rx ring buffer */
0686   TDH = 0;
0687   TDT = 0;
0688 
0689   e1000->tx_cnt = 0;
0690 
0691   DLOG ("TDBAL=%p TDLEN=%p TDH=%d TDT=%d",
0692         V2P (uint32, e1000->tdescs), TDESC_COUNT * sizeof (struct e1000_tdesc),
0693         TDH, TDT);
0694 
0695   /* setup RX interrupts */
0696   IMS |= IMS_RXT;
0697 
0698   /* setup TX interrupts */
0699   IMS |= IMS_TXQE;
0700 
0701   /* enable RX operation and broadcast reception */
0702   RCTL |= (RCTL_EN | RCTL_BAM);
0703 
0704   /* enable TX operation */
0705   TCTL |= (TCTL_EN | TCTL_PSP | TCTL_COLD_MASK);
0706   TIPG = TIPG_MASK;
0707 
0708   while (! (TCTL & TCTL_EN)) asm volatile ("pause");
0709 
0710 #ifndef LOOPBACK_MODE
0711   /* disable LRST and begin auto-negotiation */
0712   CTRL &= ~CTRL_LRST;
0713 
0714   tsc_delay_usec (10000);
0715 
0716   /* "software must set link up" in internal [G]MII mode
0717    * p166 8245x_SDM */
0718 
0719   /* p375 "ASDE should be set with SLU" */
0720   CTRL |= CTRL_SLU | CTRL_ASDE;
0721 #else
0722   set_loopback_mode ();
0723 #endif
0724 
0725 
0726   //DLOG ("PHY_CTL=0x%.04X", mdi_read (0));
0727   //DLOG ("PHY_STA=0x%.04X", mdi_read (1));
0728   //DLOG ("PHY_GCON=0x%.04X", mdi_read (9));
0729   //DLOG ("PHY_GSTA=0x%.04X", mdi_read (10));
0730 
0731 
0732   (void) TPT;                   /* clear TPT statistic */
0733 }
0734 
0735 extern bool
0736 e1000_init (void)
0737 {
0738   uint i, frame_count;
0739   pci_irq_t irq;
0740 
0741   if (mp_ISA_PC) {
0742     DLOG ("Requires PCI support");
0743     goto abort;
0744   }
0745 
0746   for (i=0; compatible_ids[i].vendor != 0xFFFF; i++)
0747     if (pci_find_device (compatible_ids[i].vendor, compatible_ids[i].device,
0748                          0xFF, 0xFF, 0, &device_index))
0749       break;
0750     else
0751       device_index = ~0;
0752 
0753   if (device_index == (uint)(~0)) {
0754     DLOG ("Unable to detect compatible device.");
0755     goto abort;
0756   }
0757 
0758   DLOG ("Found device_index=%d", device_index);
0759 
0760   if (!pci_get_device (device_index, &e1000_pci_device)) {
0761     DLOG ("Unable to get PCI device from PCI subsystem");
0762     return FALSE;
0763   }
0764 
0765   if (!pci_decode_bar (device_index, 0, &mem_addr, NULL, NULL)) {
0766     DLOG ("Invalid PCI configuration or BAR0 not found");
0767     goto abort;
0768   }
0769 
0770   DLOG ("Using PCI bus=%x dev=%x func=%x",
0771         e1000_pci_device.bus,
0772         e1000_pci_device.slot,
0773         e1000_pci_device.func);
0774 
0775   if (mem_addr == 0) {
0776     DLOG ("Unable to detect memory mapped IO region");
0777     goto abort;
0778   }
0779 
0780   /* Map some virtual pages to the memory-mapped I/O region */
0781   mmio_base = map_contiguous_virtual_pages (mem_addr | 3, E1000_MMIO_PAGES);
0782 
0783   if (mmio_base == NULL) {
0784     DLOG ("Unable to map page to phys=%p", mem_addr);
0785     goto abort;
0786   }
0787 
0788   DLOG ("Using memory mapped IO at phys=%p virt=%p", mem_addr, mmio_base);
0789 
0790 
0791   /* I need contiguous physical and virtual memory for DMA memory */
0792   frame_count = sizeof (struct e1000_interface) >> 12;
0793   if (sizeof (struct e1000_interface) & 0xFFF)
0794     frame_count++;              /* round up */
0795 
0796   /* Obtain contiguous physical frames. */
0797   e1000_phys = alloc_phys_frames (frame_count);
0798 
0799   if (e1000_phys == -1) {
0800     DLOG ("Unable to allocate physical memory");
0801     goto abort_mmap;
0802   }
0803 
0804   /* Map contiguous virtual pages to contiguous physical frames. */
0805   e1000 = (struct e1000_interface *)
0806     map_contiguous_virtual_pages (e1000_phys | 3, frame_count);
0807 
0808   if (e1000 == NULL) {
0809     DLOG ("Unable to allocate virtual memory");
0810     goto abort_phys;
0811   }
0812 
0813   /* zero the acquired memory */
0814   memset (e1000, 0, sizeof (struct e1000_interface));
0815 
0816   DLOG ("DMA region at virt=%p phys=%p count=%d", e1000, e1000_phys, frame_count);
0817 
0818   if (!pci_get_interrupt (device_index, &irq_line, &irq_pin)) {
0819     DLOG ("Unable to get IRQ");
0820     goto abort_virt;
0821   }
0822 
0823   if (pci_irq_find (e1000_pci_device.bus, e1000_pci_device.slot,
0824                     irq_pin, &irq)) {
0825     /* use PCI routing table */
0826     DLOG ("Found PCI routing entry irq.gsi=0x%x", irq.gsi);
0827     if (!pci_irq_map_handler (&irq, e1000_irq_handler, 0x01,
0828                               IOAPIC_DESTINATION_LOGICAL,
0829                               IOAPIC_DELIVERY_FIXED))
0830       goto abort_virt;
0831     irq_line = irq.gsi;
0832   }
0833 
0834   DLOG ("Using IRQ line=%.02X pin=%X", irq_line, irq_pin);
0835 
0836 #ifdef EEPROM_MICROWIRE
0837   *((uint16 *) &hwaddr[0]) = eeprom_read (0);
0838   *((uint16 *) &hwaddr[2]) = eeprom_read (1);
0839   *((uint16 *) &hwaddr[4]) = eeprom_read (2);
0840 
0841   DLOG ("ICW1=0x%.04X", eeprom_read (0xA));
0842 #else
0843   /* read hardware individual address from EEPROM */
0844   EERD = 0x0001;                /* EERD.START=0 EERD.ADDR=0 */
0845   while (!(EERD & 0x10))
0846     asm volatile ("pause"); /* wait for EERD.DONE */
0847   hwaddr[0] = (EERD >> 16) & 0xFF;
0848   hwaddr[1] = (EERD >> 24) & 0xFF;
0849   EERD = 0x0101;                /* EERD.START=0 EERD.ADDR=1 */
0850   while (!(EERD & 0x10))
0851     asm volatile ("pause"); /* wait for EERD.DONE */
0852   hwaddr[2] = (EERD >> 16) & 0xFF;
0853   hwaddr[3] = (EERD >> 24) & 0xFF;
0854   EERD = 0x0201;                /* EERD.START=0 EERD.ADDR=2 */
0855   while (!(EERD & 0x10))
0856     asm volatile ("pause"); /* wait for EERD.DONE */
0857   hwaddr[4] = (EERD >> 16) & 0xFF;
0858   hwaddr[5] = (EERD >> 24) & 0xFF;
0859 #endif
0860 
0861   DLOG ("hwaddr=%.02x:%.02x:%.02x:%.02x:%.02x:%.02x",
0862         hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
0863 
0864   reset ();
0865 
0866   /* Register network device with net subsystem */
0867   e1000_ethdev.recv_func = NULL;
0868   e1000_ethdev.send_func = e1000_transmit;
0869   e1000_ethdev.get_hwaddr_func = e1000_get_hwaddr;
0870   e1000_ethdev.poll_func = e1000_poll;
0871 
0872   if (!net_register_device (&e1000_ethdev)) {
0873     DLOG ("registration failed");
0874     goto abort_virt;
0875   }
0876 
0877   e1000_bh_id = create_kernel_thread_args ((u32) e1000_bh_thread,
0878                                            (u32) &e1000_bh_stack[1023],
0879                                            FALSE, 0);
0880   set_iovcpu (e1000_bh_id, IOVCPU_CLASS_NET);
0881 
0882   return TRUE;
0883 
0884  abort_virt:
0885   unmap_virtual_pages (e1000, frame_count);
0886  abort_phys:
0887   free_phys_frames (e1000_phys, frame_count);
0888  abort_mmap:
0889   unmap_virtual_pages ((void *)mmio_base, E1000_MMIO_PAGES);
0890  abort:
0891   return FALSE;
0892 }
0893 
0894 #include "module/header.h"
0895 
0896 static const struct module_ops mod_ops = {
0897   .init = e1000_init
0898 };
0899 
0900 DEF_MODULE (net___e1000, "e1000 network driver", &mod_ops, {"net___ethernet", "pci"});
0901 
0902 /*
0903  * Local Variables:
0904  * indent-tabs-mode: nil
0905  * mode: C
0906  * c-file-style: "gnu"
0907  * c-basic-offset: 2
0908  * End:
0909  */
0910 
0911 /* vi: set et sw=2 sts=2: */