cynix

x86 UNIX-like OS
git clone git://git.2f30.org/cynix
Log | Files | Refs | README | LICENSE

rtl8139.c (8301B)


      1 /*
      2  *  core/rtl8139.c
      3  *
      4  *  Copyright (C) 2010 stateless
      5  */
      6 
      7 #include <rtl8139.h>
      8 #include <pci.h>
      9 #include <x86.h>
     10 #include <idt.h>
     11 #include <heap.h>
     12 #include <rtc.h>
     13 #include <string.h>
     14 #include <errno.h>
     15 
     16 #define INTMASK (RTL_INT_PCIERR | RTL_INT_RX_ERR \
     17 		 | RTL_INT_RX_OK | RTL_INT_TX_ERR \
     18 		 | RTL_INT_TX_OK | RTL_INT_RXBUF_OVERFLOW)
     19 
     20 enum {
     21 	RTL_VENDOR_ID = 0x10ec,
     22 	RTL_DEVICE_ID = 0x8139,
     23 	RTL_RESET_TIMEOUT = 20 /* 200 ms */
     24 };
     25 
     26 /* NOTE: register naming comes from NetBSD-DC sources. */
     27 enum rtl_registers {
     28 	RTL_IDR0               = 0x00,            /* Mac address */
     29 	RTL_MAR0               = 0x08,            /* Multicast filter */
     30 	RTL_TXSTATUS0          = 0x10,            /* Transmit status (4 32bit regs) */
     31 	RTL_TXSTATUS1          = 0x14,            /* Transmit status (4 32bit regs) */
     32 	RTL_TXSTATUS2          = 0x18,            /* Transmit status (4 32bit regs) */
     33 	RTL_TXSTATUS3          = 0x1c,            /* Transmit status (4 32bit regs) */
     34 	RTL_TXADDR0            = 0x20,            /* Tx descriptors (also 4 32bit) */
     35 	RTL_TXADDR1            = 0x24,            /* Tx descriptors (also 4 32bit) */
     36 	RTL_TXADDR2            = 0x28,            /* Tx descriptors (also 4 32bit) */
     37 	RTL_TXADDR3            = 0x2c,            /* Tx descriptors (also 4 32bit) */
     38 	RTL_RXBUF              = 0x30,            /* Receive buffer start address */
     39 	RTL_RXEARLYCNT         = 0x34,            /* Early Rx byte count */
     40 	RTL_RXEARLYSTATUS      = 0x36,            /* Early Rx status */
     41 	RTL_CHIPCMD            = 0x37,            /* Command register */
     42 	RTL_RXBUFTAIL          = 0x38,            /* Current address of packet read (queue tail) */
     43 	RTL_RXBUFHEAD          = 0x3A,            /* Current buffer address (queue head) */
     44 	RTL_INTRMASK           = 0x3C,            /* Interrupt mask */
     45 	RTL_INTRSTATUS         = 0x3E,            /* Interrupt status */
     46 	RTL_TXCONFIG           = 0x40,            /* Tx config */
     47 	RTL_RXCONFIG           = 0x44,            /* Rx config */
     48 	RTL_TIMER              = 0x48,            /* A general purpose counter */
     49 	RTL_RXMISSED           = 0x4C,            /* 24 bits valid, write clears */
     50 	RTL_CFG9346            = 0x50,            /* 93C46 command register */
     51 	RTL_CONFIG0            = 0x51,            /* Configuration reg 0 */
     52 	RTL_CONFIG1            = 0x52,            /* Configuration reg 1 */
     53 	RTL_TIMERINT           = 0x54,            /* Timer interrupt register (32 bits) */
     54 	RTL_MEDIASTATUS        = 0x58,            /* Media status register */
     55 	RTL_CONFIG3            = 0x59,            /* Config register 3 */
     56 	RTL_CONFIG4            = 0x5A,            /* Config register 4 */
     57 	RTL_MULTIINTR          = 0x5C,            /* Multiple interrupt select */
     58 	RTL_MII_TSAD           = 0x60,            /* Transmit status of all descriptors (16 bits) */
     59 	RTL_MII_BMCR           = 0x62,            /* Basic Mode Control Register (16 bits) */
     60 	RTL_MII_BMSR           = 0x64,            /* Basic Mode Status Register (16 bits) */
     61 	RTL_AS_ADVERT          = 0x66,            /* Auto-negotiation advertisement reg (16 bits) */
     62 	RTL_AS_LPAR            = 0x68,            /* Auto-negotiation link partner reg (16 bits) */
     63 	RTL_AS_EXPANSION       = 0x6A             /* Auto-negotiation expansion reg (16 bits) */
     64 };
     65 
     66 enum rtl_command_bits {
     67 	RTL_CMD_RESET          = 0x10,
     68 	RTL_CMD_RX_ENABLE      = 0x08,
     69 	RTL_CMD_TX_ENABLE      = 0x04,
     70 	RTL_CMD_RX_BUF_EMPTY   = 0x01
     71 };
     72 
     73 enum rtl_int_status {
     74 	RTL_INT_PCIERR              = 0x8000,          /* PCI Bus error */
     75 	RTL_INT_TIMEOUT             = 0x4000,          /* Set when TCTR reaches TimerInt value */
     76 	RTL_INT_RXFIFO_OVERFLOW     = 0x0040,          /* Rx FIFO overflow */
     77 	RTL_INT_RXFIFO_UNDERRUN     = 0x0020,          /* Packet underrun / link change */
     78 	RTL_INT_RXBUF_OVERFLOW      = 0x0010,          /* Rx BUFFER overflow */
     79 	RTL_INT_TX_ERR              = 0x0008,
     80 	RTL_INT_TX_OK               = 0x0004,
     81 	RTL_INT_RX_ERR              = 0x0002,
     82 	RTL_INT_RX_OK               = 0x0001
     83 };
     84 
     85 enum rtl_tx_status {
     86 	RTL_TX_CARRIER_LOST         = 0x80000000,      /* Carrier sense lost */
     87 	RTL_TX_ABORTED              = 0x40000000,      /* Transmission aborted */
     88 	RTL_TX_OUT_OF_WINDOW        = 0x20000000,      /* Out of window collision */
     89 	RTL_TX_STATUS_OK            = 0x00008000,      /* Status ok: a good packet was transmitted */
     90 	RTL_TX_UNDERRUN             = 0x00004000,      /* Transmit FIFO underrun */
     91 	RTL_TX_HOST_OWNS            = 0x00002000,      /* Set to 1 when DMA operation is completed */
     92 	RTL_TX_SIZE_MASK            = 0x00001fff       /* Descriptor size mask */
     93 };
     94 
     95 enum rtl_rx_status {
     96 	RTL_RX_MULTICAST            = 0x00008000,      /* Multicast packet */
     97 	RTL_RX_PAM                  = 0x00004000,      /* Physical address matched */
     98 	RTL_RX_BROADCAST            = 0x00002000,      /* Broadcast address matched */
     99 	RTL_RX_BAD_SYMBOL           = 0x00000020,      /* Invalid symbol in 100TX packet */
    100 	RTL_RX_RUNT                 = 0x00000010,      /* Packet size is <64 bytes */
    101 	RTL_RX_TOO_LONG             = 0x00000008,      /* Packet size is >4K bytes */
    102 	RTL_RX_CRC_ERR              = 0x00000004,      /* CRC error */
    103 	RTL_RX_FRAME_ALIGN          = 0x00000002,      /* Frame alignment error */
    104 	RTL_RX_STATUS_OK            = 0x00000001       /* Status ok: a good packet was received */
    105 };
    106 
    107 struct rtl8139_t {
    108 	char rx_buffer[8192 + 16];
    109 	uint8_t mac_addr[6];
    110 	spinlock_t iolock;
    111 	uint32_t io_base;
    112 } *rtl = NULL;
    113 
    114 void
    115 rtl8139_int(__attribute__ ((unused)) struct trapframe_t *regs)
    116 {
    117 	panic("yoohoo!");
    118 }
    119 
    120 static void
    121 rtl_write8(uint16_t offset, uint8_t val)
    122 {
    123 	acquire(&rtl->iolock);
    124 	outb(rtl->io_base + offset, val);
    125 	release(&rtl->iolock);
    126 }
    127 
    128 static void
    129 rtl_write32(uint16_t offset, uint32_t val)
    130 {
    131 	acquire(&rtl->iolock);
    132 	outl(rtl->io_base + offset, val);
    133 	release(&rtl->iolock);
    134 }
    135 
    136 static void
    137 rtl_write16(uint16_t offset, uint16_t val)
    138 {
    139 	acquire(&rtl->iolock);
    140 	outw(rtl->io_base + offset, val);
    141 	release(&rtl->iolock);
    142 }
    143 
    144 static uint8_t
    145 rtl_read8(uint16_t offset)
    146 {
    147 	uint8_t r;
    148 
    149 	acquire(&rtl->iolock);
    150 	r = inb(rtl->io_base + offset);
    151 	release(&rtl->iolock);
    152 	return r;
    153 }
    154 
    155 static uint32_t
    156 rtl_read32(uint16_t offset)
    157 {
    158 	uint32_t r;
    159 
    160 	acquire(&rtl->iolock);
    161 	r = inl(rtl->io_base + offset);
    162 	release(&rtl->iolock);
    163 	return r;
    164 }
    165 
    166 int
    167 rtl8139_init(void)
    168 {
    169 	struct pci_dev_t *dev;
    170 	uint32_t i, timeout = 0;
    171 
    172 	/* enumerate the PCI bus looking for an rtl8139 */
    173 	dev = get_pci_dev(RTL_VENDOR_ID, RTL_DEVICE_ID);
    174 	if (!dev)
    175 		return -ENODEV;
    176 
    177 	rtl = kmalloc(sizeof(*rtl));
    178 	if (IS_ERR(rtl))
    179 		return PTR_ERR(rtl);
    180 
    181 	memset(rtl, 0, sizeof(*rtl));
    182 	initspinlock(&rtl->iolock);
    183 
    184 	/* grab the io port base for all subsequence i/o operations */
    185 	rtl->io_base = dev->cspace->type0.bar0 & 0xfffffffc;
    186 
    187 	/* reset the device */
    188 	rtl_write8(RTL_CHIPCMD, RTL_CMD_RESET);
    189 	do {
    190 		if (timeout++ == RTL_RESET_TIMEOUT)
    191 			goto err;
    192 		msleep(1); /* sleep for ~10ms */
    193 	} while (rtl_read8(RTL_CHIPCMD) & RTL_CMD_RESET);
    194 
    195 	register_isr_handler(0x20 + dev->cspace->type0.irq, rtl8139_int);
    196 
    197 	/* grab the mac-address */
    198 	for (i = 0; i < 6; ++i)
    199 		rtl->mac_addr[i] = rtl_read8(i);
    200 
    201 	/* put the device in config mode to enable writing to the config registers */
    202 	rtl_write8(RTL_CFG9346, 0xc0);
    203 	/* reset config 1 */
    204 	rtl_write8(RTL_CONFIG1, 0);
    205 	/* go back to normal mode */
    206 	rtl_write8(RTL_CFG9346, 0);
    207 
    208 	/* set the receive buffer address */
    209 	rtl_write32(RTL_RXBUF, (uint32_t)rtl->rx_buffer);
    210 	/* TODO: setup the tx descriptors */
    211 
    212 #if 0
    213 	/* accept
    214 	 *        physical address packets,
    215 	 *        physical match packets,
    216 	 *        multicast packets,
    217 	 *        and broadcast packets
    218 	 * enable wrap mode
    219 	 */
    220 	rtl_write32(RTL_RXCONFIG, 0xf | (1 << 7));
    221 	/* make sure IRQs will fire */
    222 	rtl_write32(RTL_INTRMASK, RTL_INT_TX_OK | RTL_INT_RX_OK);
    223 #else
    224 	rtl_write32(RTL_RXMISSED, 0);
    225 	rtl_write32(RTL_RXCONFIG, rtl_read32(RTL_RXCONFIG) | 0x0000000f);
    226 	rtl_write32(RTL_MAR0, 0);
    227 	rtl_write32(RTL_MAR0 + 4, 0);
    228 	rtl_write16(RTL_MULTIINTR, 0);
    229 	rtl_write16(RTL_INTRMASK, INTMASK);
    230 #endif
    231 
    232 	/* enable the receiver and the transmitter */
    233 	rtl_write32(RTL_CHIPCMD, RTL_CMD_RX_ENABLE | RTL_CMD_TX_ENABLE);
    234 	/* just to be on the safe side */
    235 	rtl_write8(RTL_CFG9346, 0);
    236 	return 0;
    237 err:
    238 	kfree(rtl);
    239 	return -EBUSY;
    240 }
    241 
    242 const uint8_t *
    243 get_mac_addr(void)
    244 {
    245 	if (!rtl)
    246 		return NULL;
    247 	return rtl->mac_addr;
    248 }
    249