123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889 |
- /*
- * Copyright (c) 2006-2021, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2021-08-16 JasonHu first version
- */
- #include <board.h>
- #include <rtthread.h>
- #include <rtdevice.h>
- #include <rthw.h>
- #include <netif/ethernetif.h>
- #include <pci.h>
- #include <mmu.h>
- #define DBG_LVL DBG_INFO
- #define DBG_TAG "RTL8139"
- #include <rtdbg.h>
- #include "drv_rtl8139.h"
- #define DEV_NAME "e0"
- #define GET_RTL8139(eth) (struct eth_device_rtl8139 *)(eth)
- struct eth_device_rtl8139
- {
- /* inherit from Ethernet device */
- struct eth_device parent;
- /* interface address info. */
- rt_uint8_t dev_addr[ETH_ALEN]; /* MAC address */
- rt_pci_device_t *pci_dev; /* pci device info */
- rt_uint32_t iobase; /* io port base */
- rt_uint32_t irqno; /* irq number */
- card_chip_t chipset;
- rt_spinlock_t lock; /* lock for rx packet */
- rt_uint8_t *rx_buffer;
- rt_uint8_t *rx_ring;
- rt_uint8_t current_rx; /* CAPR, Current Address of Packet Read */
- rt_uint32_t rx_flags;
- rt_ubase_t rx_ring_dma; /* dma phy addr */
- rt_uint32_t rx_config; /* receive config */
- struct rtl8139_status rx_status;
- rt_uint8_t *tx_buffers;
- rt_uint8_t *tx_buffer[NUM_TX_DESC]; /* tx buffer pointer array */
- rt_uint32_t current_tx;
- rt_uint32_t dirty_tx;
- rt_size_t tx_free_counts;
- rt_uint32_t tx_flags;
- rt_ubase_t tx_buffer_dma; /* dma phy addr */
- struct rtl8139_status tx_status;
- struct net_device_status stats; /* device stats */
- struct rtl_extra_status xstats; /* extra status */
- rt_uint32_t dev_flags; /* flags of net device */
- rt_mq_t rx_mqueue; /* msg queue for rx */
- rt_uint8_t linked; /* eth device linked */
- };
- static struct eth_device_rtl8139 eth_dev;
- static rt_uint8_t rx_cache_send_buf[RX_MSG_SIZE] = {0}; /* buf for rx packet, put size and data into mq */
- static rt_uint8_t rx_cache_recv_buf[RX_MSG_SIZE] = {0}; /* buf for rx packet, get size and data from mq */
- static rt_uint8_t tx_cache_pbuf[TX_CACHE_BUF_SIZE] = {0}; /* buf for tx packet, get data from pbuf payload */
- static int rtl8139_next_desc(int current_desc)
- {
- return (current_desc == NUM_TX_DESC - 1) ? 0 : (current_desc + 1);
- }
- int rtl8139_transmit(struct eth_device_rtl8139 *dev, rt_uint8_t *buf, rt_size_t len)
- {
- rt_uint32_t entry;
- rt_uint32_t length = len;
- entry = dev->current_tx;
- rt_base_t level = rt_hw_interrupt_disable();
- if (dev->tx_free_counts > 0)
- {
- if (length < TX_BUF_SIZE)
- {
- if (length < ETH_ZLEN)
- {
- rt_memset(dev->tx_buffer[entry], 0, ETH_ZLEN); /* pad zero */
- }
- rt_memcpy(dev->tx_buffer[entry], buf, length);
- }
- else
- {
- /* drop packet */
- dev->stats.tx_dropped++;
- dbg_log(DBG_WARNING, "dropped a packed!\n");
- rt_hw_interrupt_enable(level);
- return 0;
- }
- /*
- * Writing to tx_status triggers a DMA transfer of the data
- * copied to dev->tx_buffer[entry] above. Use a memory barrier
- * to make sure that the device sees the updated data.
- */
- rt_hw_dsb();
- outl(dev->iobase + TX_STATUS0 + (entry * 4), dev->tx_flags | ETH_MAX(length, (rt_uint32_t )ETH_ZLEN));
- inl(dev->iobase + TX_STATUS0 + (entry * 4)); // flush
- dev->current_tx = rtl8139_next_desc(dev->current_tx);
- --dev->tx_free_counts;
- } else {
- LOG_E("Stop Tx packet!\n");
- rt_hw_interrupt_enable(level);
- return -1;
- }
- rt_hw_interrupt_enable(level);
- return 0;
- }
- /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
- static void rtl8139_init_ring(struct eth_device_rtl8139 *dev)
- {
- int i;
- dev->current_rx = 0;
- dev->current_tx = 0;
- dev->dirty_tx = 0;
- /* set free counts */
- dev->tx_free_counts = NUM_TX_DESC;
- for (i = 0; i < NUM_TX_DESC; i++)
- {
- dev->tx_buffer[i] = (unsigned char *)&dev->tx_buffers[i * TX_BUF_SIZE];
- }
- }
- static void rtl8139_chip_reset(struct eth_device_rtl8139 *dev)
- {
- /* software reset, to clear the RX and TX buffers and set everything back to defaults. */
- outb(dev->iobase + CHIP_CMD, CMD_RESET);
- /* wait reset done */
- for (;;)
- {
- rt_hw_dmb();
- if ((inb(dev->iobase + CHIP_CMD) & CMD_RESET) == 0)
- {
- break;
- }
- rt_hw_cpu_pause();
- }
- }
- static void rtl8139_set_rx_mode(struct eth_device_rtl8139 *dev)
- {
- rt_base_t level = rt_hw_interrupt_disable();
- int rx_mode = ACCEPT_BROADCAST | ACCEPT_MY_PHYS | ACCEPT_MULTICAST;
- rx_mode |= (ACCEPT_ERR | ACCEPT_RUNT);
- rt_uint32_t tmp;
- tmp = rtl8139_rx_config | rx_mode;
- if (dev->rx_config != tmp)
- {
- outl(dev->iobase + RX_CONFIG, tmp);
- /* flush */
- inl(dev->iobase + RX_CONFIG);
- dev->rx_config = tmp;
- }
- /* filter packet */
- rt_uint32_t mac_filter[2];
- mac_filter[0] = mac_filter[1] = 0;
- outl(dev->iobase + MAR0 + 0, mac_filter[0]);
- inl(dev->iobase + MAR0 + 0);
- outl(dev->iobase + MAR0 + 4, mac_filter[1]);
- inl(dev->iobase + MAR0 + 4);
- rt_hw_interrupt_enable(level);
- }
- static void rtl8139_hardware_start(struct eth_device_rtl8139 *dev)
- {
- /* Bring old chips out of low-power mode. */
- if (rtl_chip_info[dev->chipset].flags & HAS_HLT_CLK)
- {
- outb(dev->iobase + HLT_CTL, 'R');
- }
- rtl8139_chip_reset(dev);
- /* unlock Config[01234] and BMCR register writes */
- outb(dev->iobase + CFG9346, CFG9346_UNLOCK);
- inb(dev->iobase + CFG9346); // flush
- /* Restore our rtl8139a of the MAC address. */
- outl(dev->iobase + MAC0, *(rt_uint32_t *)(dev->dev_addr + 0));
- inl(dev->iobase + MAC0);
- outw(dev->iobase + MAC0 + 4, *(uint16_t *)(dev->dev_addr + 4));
- inw(dev->iobase + MAC0 + 4);
- dev->current_rx = 0;
- /* init Rx ring buffer DMA address */
- outl(dev->iobase + RX_BUF, dev->rx_ring_dma);
- inl(dev->iobase + RX_BUF);
- /* Must enable Tx/Rx before setting transfer thresholds! */
- outb(dev->iobase + CHIP_CMD, CMD_RX_ENABLE | CMD_TX_ENABLE);
- /* set receive config */
- dev->rx_config = rtl8139_rx_config | ACCEPT_BROADCAST | ACCEPT_MY_PHYS;
- outl(dev->iobase + RX_CONFIG, dev->rx_config);
- outl(dev->iobase + TX_CONFIG, rtl8139_tx_config);
- if (dev->chipset >= CH_8139B)
- {
- /* Disable magic packet scanning, which is enabled
- * when PM is enabled in Config1. It can be reenabled
- * via ETHTOOL_SWOL if desired.
- * clear MAGIC bit
- */
- outb(dev->iobase + CONFIG3, inb(dev->iobase + CONFIG3) & ~CFG3_MAGIC);
- }
- /* Lock Config[01234] and BMCR register writes */
- outb(dev->iobase + CFG9346, CFG9346_LOCK);
- /* init Tx buffer DMA addresses */
- int i;
- for (i = 0; i < NUM_TX_DESC; i++)
- {
- outl(dev->iobase + TX_ADDR0 + (i * 4), dev->tx_buffer_dma + (dev->tx_buffer[i] - dev->tx_buffers));
- /* flush */
- inl(dev->iobase + TX_ADDR0 + (i * 4));
- }
- outl(dev->iobase + RX_MISSED, 0);
- rtl8139_set_rx_mode(dev);
- /* no early-rx intr */
- outw(dev->iobase + MULTI_INTR, inw(dev->iobase + MULTI_INTR) & MULTI_INTR_CLEAR);
- /* make sure tx & rx enabled */
- uint8_t tmp = inb(dev->iobase + CHIP_CMD);
- if (!(tmp & CMD_RX_ENABLE) || !(tmp & CMD_TX_ENABLE))
- {
- outb(dev->iobase + CHIP_CMD, CMD_RX_ENABLE | CMD_TX_ENABLE);
- }
- /* enable 8139 intr mask */
- outw(dev->iobase + INTR_MASK, rtl8139_intr_mask);
- }
- static int rtl8139_tx_interrupt(struct eth_device_rtl8139 *dev)
- {
- while (dev->tx_free_counts < NUM_TX_DESC)
- {
- int entry = dev->dirty_tx;
- int tx_status;
- /* read tx status */
- tx_status = inl(dev->iobase + TX_STATUS0 + (entry * 4));
- /* no tx intr, exit */
- if (!(tx_status & (TX_STAT_OK | TX_UNDERRUN | TX_ABORTED)))
- {
- dbg_log(DBG_ERROR, "tx status not we want!\n");
- break;
- }
- /* NOTE: TxCarrierLost is always asserted at 100mbps. */
- if (tx_status & (TX_OUT_OF_WINDOW | TX_ABORTED))
- {
- dbg_log(DBG_ERROR, "Transmit error, Tx status %x\n", tx_status);
- dev->stats.tx_errors++;
- if (tx_status & TX_ABORTED)
- {
- dev->stats.tx_aborted_errors++;
- /* clear abort bit */
- outl(dev->iobase + TX_CONFIG, TX_CLEAR_ABT);
- /* set intr tx error */
- outw(dev->iobase + INTR_STATUS, TX_ERR);
- rt_hw_dsb();
- }
- if (tx_status & TX_CARRIER_LOST)
- {
- dev->stats.tx_carrier_errors++;
- }
- if (tx_status & TX_OUT_OF_WINDOW)
- {
- dev->stats.tx_window_errors++;
- }
- }
- else
- {
- if (tx_status & TX_UNDERRUN)
- {
- /* Add 64 to the Tx FIFO threshold. */
- if (dev->tx_flags < 0x00300000) {
- dev->tx_flags += 0x00020000;
- }
- dev->stats.tx_fifo_errors++;
- }
- dev->stats.collisions += (tx_status >> 24) & 15;
- dev->tx_status.packets++;
- dev->tx_status.bytes += tx_status & 0x7ff;
- }
- dev->dirty_tx = rtl8139_next_desc(dev->dirty_tx);
- if (dev->tx_free_counts == 0)
- {
- rt_hw_dmb();
- }
- dev->tx_free_counts++;
- }
- return 0;
- }
- static void rtl8139_other_interrupt(struct eth_device_rtl8139 *dev, int status, int link_changed)
- {
- /* Update the error count. */
- dev->stats.rx_missed_errors += inl(dev->iobase + RX_MISSED);
- outl(dev->iobase + RX_MISSED, 0);
- if ((status & RX_UNDERRUN) && link_changed && (dev->dev_flags & HAS_LNK_CHNG))
- {
- dev->linked = RT_FALSE; /* dev not linked */
- status &= ~RX_UNDERRUN;
- }
- if (status & (RX_UNDERRUN | RX_ERR))
- {
- dev->stats.rx_errors++;
- }
- if (status & PCS_TIMEOUT)
- {
- dev->stats.rx_length_errors++;
- }
- if (status & RX_UNDERRUN)
- {
- dev->stats.rx_fifo_errors++;
- }
- if (status & PCI_ERR) /* error on pci */
- {
- rt_uint32_t pci_cmd_status;
- pci_cmd_status = rt_pci_device_read(dev->pci_dev, PCI_STATUS_COMMAND);
- rt_pci_device_write(dev->pci_dev, PCI_STATUS_COMMAND, pci_cmd_status);
- dbg_log(DBG_ERROR, "PCI Bus error %x\n", pci_cmd_status >> 16);
- }
- }
- static void rtl8139_rx_error(rt_uint32_t rx_status, struct eth_device_rtl8139 *dev)
- {
- rt_uint8_t tmp;
- dev->stats.rx_errors++;
- /* rx error */
- if (!(rx_status & RX_STATUS_OK))
- {
- /* frame error */
- if (rx_status & (RX_BAD_SYMBOL | RX_BAD_Align))
- {
- dev->stats.rx_frame_errors++;
- }
- /* long */
- if (rx_status & (RX_RUNT | RX_TOO_LONG))
- {
- dev->stats.rx_length_errors++;
- }
- /* CRC check */
- if (rx_status & RX_CRC_ERR)
- {
- dev->stats.rx_crc_errors++;
- }
- }
- else
- {
- /* receive ok, but lost */
- dev->xstats.rx_lost_in_ring++;
- }
- /* reset receive */
- tmp = inb(dev->iobase + CHIP_CMD);
- outb(dev->iobase + CHIP_CMD, tmp & ~CMD_RX_ENABLE);
- outb(dev->iobase + CHIP_CMD, tmp);
- outl(dev->iobase + RX_CONFIG, dev->rx_config);
- dev->current_rx = 0;
- }
- static void rtl8139_isr_ack(struct eth_device_rtl8139 *dev)
- {
- rt_uint16_t status;
- status = inw(dev->iobase + INTR_STATUS) & RX_ACK_BITS;
- /* Clear out errors and receive interrupts */
- if (status != 0)
- {
- if (status & (RX_FIFO_OVER | RX_OVERFLOW))
- {
- dev->stats.rx_errors++;
- if (status & RX_FIFO_OVER)
- {
- dev->stats.rx_fifo_errors++;
- }
- }
- /* write rx ack */
- outw(dev->iobase + INTR_STATUS, RX_ACK_BITS);
- inw(dev->iobase + INTR_STATUS); // for flush
- }
- }
- static int rtl8139_rx_interrupt(struct eth_device_rtl8139 *dev)
- {
- int received = 0;
- rt_uint8_t *rx_ring = dev->rx_ring;
- rt_uint32_t current_rx = dev->current_rx;
- rt_uint32_t rx_size = 0;
- while (!(inb(dev->iobase + CHIP_CMD) & RX_BUFFER_EMPTY))
- {
- rt_uint32_t ring_offset = current_rx % RX_BUF_LEN;
- rt_uint32_t rx_status;
- rt_size_t pkt_size;
- rt_hw_dmb();
- /* read size+status of next frame from DMA ring buffer */
- rx_status = *(rt_uint32_t *)(rx_ring + ring_offset);
- /* size on high 16 bit */
- rx_size = rx_status >> 16;
- if (!(dev->dev_flags & DEV_FLAGS_RXFCS)) {
- pkt_size = rx_size - 4;
- } else {
- pkt_size = rx_size;
- }
- /* Packet copy from FIFO still in progress.
- * Theoretically, this should never happen
- * since early_rx is disabled.
- */
- if (rx_size == 0xfff0)
- {
- dbg_log(DBG_WARNING, "rx fifo copy in progress\n");
- dev->xstats.early_rx++;
- break;
- }
- /* If Rx err or invalid rx_size/rx_status received
- * (which happens if we get lost in the ring),
- * Rx process gets reset, so we abort any further
- * Rx processing.
- */
- if ((rx_size > (MAX_ETH_FRAME_SIZE + 4) || (rx_size < 8) || (!(rx_status & RX_STATUS_OK))))
- {
- if ((dev->dev_flags & DEV_FLAGS_RXALL) && (rx_size <= (MAX_ETH_FRAME_SIZE + 4)) &&
- (rx_size >= 8) && (!(rx_status & RX_STATUS_OK)))
- {
- dev->stats.rx_errors++;
- if (rx_status & RX_CRC_ERR)
- {
- dev->stats.rx_crc_errors++;
- goto keep_pkt;
- }
- if (rx_status & RX_RUNT)
- {
- dev->stats.rx_length_errors++;
- goto keep_pkt;
- }
- }
- /* rx error handle */
- rtl8139_rx_error(rx_status, dev);
- received = -1;
- goto out;
- }
- keep_pkt:
- /* merge size and data into receive pkg */
- rt_memcpy(rx_cache_send_buf, &pkt_size, 4);
- rt_memcpy(&rx_cache_send_buf[4], &rx_ring[ring_offset + 4], pkt_size);
- rt_mq_send_interrupt(dev->rx_mqueue, rx_cache_send_buf, pkt_size + 4);
- eth_device_ready(&dev->parent); /* notify eth thread to read packet */
- dev->rx_status.packets++;
- dev->rx_status.bytes += pkt_size;
- received++;
- /* 4:for header length(length include 4 bytes CRC)
- * 3:for dword alignment
- */
- current_rx = (current_rx + rx_size + 4 + 3) & ~3;
- outw(dev->iobase + RX_BUF_PTR, (rt_uint16_t)(current_rx - 16));
- rtl8139_isr_ack(dev);
- }
- if (!received || rx_size == 0xfff0)
- {
- rtl8139_isr_ack(dev);
- }
- dev->current_rx = current_rx;
- out:
- return received;
- }
- static void rt_hw_rtl8139_isr(int vector, void *param)
- {
- struct eth_device_rtl8139 *dev = GET_RTL8139(param);
- rt_uint16_t status, ackstat;
- int link_changed = 0; /* avoid bogus "uninit" warning */
- rt_spin_lock(&dev->lock);
- status = inw(dev->iobase + INTR_STATUS);
- outw(dev->iobase + INTR_STATUS, status);
- if ((status & rtl8139_intr_mask) == 0)
- {
- dbg_log(DBG_LOG, "no interrupt occured on me!\n");
- rt_spin_unlock(&dev->lock);
- return;
- }
- /* check netif state whether running. */
- if (!dev->linked)
- {
- /* clear intr mask, don't receive intr forever */
- outw(dev->iobase + INTR_MASK, 0);
- goto out;
- }
- /* Acknowledge all of the current interrupt sources ASAP, but
- an first get an additional status bit from CSCR. */
- if (status & RX_UNDERRUN)
- {
- link_changed = inw(dev->iobase + CSCR) & CSCR_LINK_CHANGE;
- }
- ackstat = status & ~(RX_ACK_BITS | TX_ERR);
- if (ackstat)
- {
- outw(dev->iobase + INTR_STATUS, ackstat);
- }
- if (status & RX_ACK_BITS)
- {
- rtl8139_rx_interrupt(dev);
- }
- /* Check uncommon events with one test. */
- if (status & (PCI_ERR | PCS_TIMEOUT | RX_UNDERRUN | RX_ERR))
- {
- rtl8139_other_interrupt(dev, status, link_changed);
- }
- /* handle receive */
- if (status & (TX_OK | TX_ERR))
- {
- rtl8139_tx_interrupt(dev);
- if (status & TX_ERR)
- outw(dev->iobase + INTR_STATUS, TX_ERR);
- }
- out:
- rt_spin_unlock(&dev->lock);
- }
- static rt_err_t rtl8139_init(rt_device_t device)
- {
- struct eth_device_rtl8139 *dev = GET_RTL8139(device);
- /* alloc transmit buffer */
- dev->tx_buffers = (rt_uint8_t *) rt_malloc(TX_BUF_TOTAL_LEN);
- if (dev->tx_buffers == RT_NULL)
- {
- LOG_E("alloc memory for rtl8139 tx buffer failed!\n");
- return -1;
- }
- /* alloc receive buffer */
- dev->rx_ring = (rt_uint8_t *) rt_malloc(RX_BUF_TOTAL_LEN);
- if (dev->rx_ring == RT_NULL) {
- LOG_E("alloc memory for rtl8139 rx buffer failed!\n");
- rt_free(dev->tx_buffers);
- return -1;
- }
- /* create msg queue for eth rx */
- dev->rx_mqueue = rt_mq_create("rx_mqueue", RX_MSG_SIZE, RX_MSG_CNT, 0);
- if (dev->rx_mqueue == RT_NULL)
- {
- LOG_E("crete msg queue for rx buffer failed!\n");
- rt_free(dev->tx_buffers);
- rt_free(dev->rx_ring);
- return -1;
- }
- dev->tx_buffer_dma = (rt_ubase_t)rt_hw_vir2phy(dev->tx_buffers);
- dev->rx_ring_dma = (rt_ubase_t)rt_hw_vir2phy(dev->rx_ring);
- dev->tx_flags = (TX_FIFO_THRESH << 11) & 0x003f0000;
- /* init tx and rx ring */
- rtl8139_init_ring(dev);
- rtl8139_hardware_start(dev);
- dev->dev_flags = DEV_FLAGS_RXALL;
- dev->linked = RT_TRUE;
- eth_device_linkchange(&dev->parent, RT_TRUE);
- if (rt_hw_interrupt_install(dev->irqno, rt_hw_rtl8139_isr, (void *) dev, "rtl8139") < 0)
- {
- LOG_E("install IRQ failed!\n");
- rt_free(dev->tx_buffers);
- rt_free(dev->rx_ring);
- rt_mq_delete(dev->rx_mqueue);
- return RT_ERROR;
- }
- rt_hw_interrupt_umask(dev->irqno);
- dbg_log(DBG_INFO, "ethernet card init done.\n");
- return RT_EOK;
- }
- #ifdef RT_USING_DEVICE_OPS
- const static struct rt_device_ops rtl8139_ops =
- {
- rtl8139_init,
- RT_NULL,
- RT_NULL,
- RT_NULL,
- RT_NULL,
- rtl8139_control
- };
- #endif
- static int rtl8139_get_pci(struct eth_device_rtl8139 *dev)
- {
- /* get pci device */
- rt_pci_device_t *pci_dev = rt_pci_device_get(RTL8139_VENDOR_ID, RTL8139_DEVICE_ID);
- if (pci_dev == RT_NULL)
- {
- LOG_E("device not find on pci device.\n");
- return -1;
- }
- dev->pci_dev = pci_dev;
- dbg_log(DBG_LOG, "find device, vendor id: 0x%x, device id: 0x%x\n",
- pci_dev->vendor_id, pci_dev->device_id);
- /* enable bus mastering */
- rt_pci_enable_bus_mastering(pci_dev);
- /* get io port address */
- dev->iobase = rt_pci_device_get_io_addr(pci_dev);
- if (dev->iobase == 0)
- {
- LOG_E("invalid pci device io address.\n");
- return -1;
- }
- dbg_log(DBG_LOG, "io base address: 0x%x\n", dev->iobase);
- /* get irq */
- dev->irqno = rt_pci_device_get_irq_line(pci_dev);
- if (dev->irqno == 0xff)
- {
- LOG_E("invalid irqno.\n");
- return -1;
- }
- dbg_log(DBG_LOG, "irqno %d\n", dev->irqno);
- return 0;
- }
- static int rtl8139_init_board(struct eth_device_rtl8139 *dev)
- {
- /* check for missing/broken hardware */
- if (inl(dev->iobase + TX_CONFIG) == 0xFFFFFFFF)
- {
- dbg_log(DBG_ERROR, "chip not responding, ignoring board.\n");
- return -1;
- }
- rt_uint32_t version = inl(dev->iobase + TX_CONFIG) & HW_REVID_MASK;
- int i;
- for (i = 0; i < CHIP_INFO_NR; i++)
- {
- if (version == rtl_chip_info[i].version) {
- dev->chipset = i;
- goto chip_match;
- }
- }
- /* if unknown chip, assume array element #0, original RTL-8139 in this case */
- i = 0;
- dbg_log(DBG_LOG, "unknown chip version, assuming RTL-8139\n");
- dbg_log(DBG_LOG, "TxConfig = 0x%x\n", inl(dev->iobase + TX_CONFIG));
- dev->chipset = 0;
- chip_match:
- dbg_log(DBG_LOG, "chipset id (%x) == index %d, '%s'\n",
- version, i, rtl_chip_info[i].name);
- /* start netcard */
- if (dev->chipset >= CH_8139B)
- {
- dbg_log(DBG_WARNING, "PCI PM wakeup, not support now!\n");
- }
- else
- {
- rt_uint8_t tmp = inb(dev->iobase + CONFIG1);
- tmp &= ~(CFG1_SLEEP | CFG1_PWRDN);
- outb(dev->iobase + CONFIG1, tmp);
- }
- /* reset chip */
- rtl8139_chip_reset(dev);
- return 0;
- }
- static int rtl8139_init_hw(struct eth_device_rtl8139 *dev)
- {
- rt_pci_device_t *pci_dev = dev->pci_dev;
- /* check version */
- if (pci_dev->vendor_id == RTL8139_VENDOR_ID && pci_dev->device_id == RTL8139_DEVICE_ID &&
- pci_dev->revision_id >= 0x20)
- {
- dbg_log(DBG_LOG, "This (id %04x:%04x rev %02x) is an enhanced 8139C+ chip, use 8139cp\n",
- pci_dev->vendor_id, pci_dev->device_id, pci_dev->revision_id);
- }
- if (rtl8139_init_board(dev) < 0)
- {
- return -1;
- }
- /* get MAC from pci config */
- int i;
- for (i = 0; i < ETH_ALEN; i++) {
- dev->dev_addr[i] = inb(dev->iobase + MAC0 + i);
- }
- dbg_log(DBG_INFO, "MAC addr: %x:%x:%x:%x:%x:%x\n", dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
- rt_spin_lock_init(&dev->lock);
- /* Put the chip into low-power mode. */
- if (rtl_chip_info[dev->chipset].flags & HAS_HLT_CLK)
- {
- outb(dev->iobase + HLT_CTL, 'H'); /* 'R' would leave the clock running. */
- }
- return 0;
- }
- static rt_err_t rtl8139_tx(rt_device_t device, struct pbuf *p)
- {
- rt_err_t err = RT_EOK;
- /* copy data from pbuf to tx cache */
- pbuf_copy_partial(p, (void *)&tx_cache_pbuf[0], p->tot_len, 0);
- if (rtl8139_transmit(GET_RTL8139(device), tx_cache_pbuf, p->tot_len) < 0)
- {
- err = RT_ERROR;
- }
- return err;
- }
- static struct pbuf *rtl8139_rx(rt_device_t device)
- {
- struct eth_device_rtl8139 *dev = GET_RTL8139(device);
- int recv_len = 0;
- struct pbuf *pbuf = RT_NULL;
- rt_err_t err;
- /* get data from rx queue. */
- err = rt_mq_recv_interruptible(dev->rx_mqueue, rx_cache_recv_buf, RX_MSG_SIZE, 0);
- if (err != RT_EOK)
- {
- goto end;
- }
- /* get recv len from rx cache, 0~3: recv len, 3-n: frame data */
- recv_len = *(int *)rx_cache_recv_buf;
- if (recv_len > 0)
- {
- pbuf = pbuf_alloc(PBUF_LINK, recv_len, PBUF_RAM);
- rt_memcpy(pbuf->payload, (char *)rx_cache_recv_buf + 4, recv_len);
- }
- end:
- return pbuf;
- }
- static rt_err_t rtl8139_control(rt_device_t device, int cmd, void *args)
- {
- struct eth_device_rtl8139 *dev = GET_RTL8139(device);
- switch(cmd)
- {
- case NIOCTL_GADDR:
- /* get MAC address */
- if(args)
- {
- rt_memcpy(args, dev->dev_addr, ETH_ALEN);
- }
- else
- {
- return -RT_ERROR;
- }
- break;
- default :
- break;
- }
- return RT_EOK;
- }
- static int rt_hw_rtl8139_init(void)
- {
- rt_memset(ð_dev, 0x0, sizeof(eth_dev));
- if (rtl8139_get_pci(ð_dev) < 0)
- {
- return -1;
- }
- if (rtl8139_init_hw(ð_dev) < 0)
- {
- return -1;
- }
- /* set device opts */
- #ifdef RT_USING_DEVICE_OPS
- eth_dev.parent.parent.ops = &rtl8139_ops;
- #else
- eth_dev.parent.parent.init = rtl8139_init;
- eth_dev.parent.parent.open = RT_NULL;
- eth_dev.parent.parent.close = RT_NULL;
- eth_dev.parent.parent.read = RT_NULL;
- eth_dev.parent.parent.write = RT_NULL;
- eth_dev.parent.parent.control = rtl8139_control;
- #endif
- eth_dev.parent.parent.user_data = RT_NULL;
- eth_dev.parent.eth_rx = rtl8139_rx;
- eth_dev.parent.eth_tx = rtl8139_tx;
- /* register ETH device */
- if (eth_device_init(&(eth_dev.parent), DEV_NAME) != RT_EOK)
- {
- return -1;
- }
- return 0;
- }
- INIT_DEVICE_EXPORT(rt_hw_rtl8139_init);
|