LinuxÒÁµéÔ°Ê×Ò³

¿ØÖÆÃæ°å ×ÔÓÉÐÂÎÅ ×ÔÓÉÈí¼þ ×ÔÓÉÎĵµ ×ÔÓÉÂÛ̳ ×ÔÓÉÉÌ³Ç ÁªÏµÎÒÃÇ
ÎÒµÄÊÕ²Ø ÍÆ¼öÎÄÕ »áÔ±µÇ½ ×îºó¸üР¸ß¼¶ËÑË÷ Í˳öµÇ½
ÐÂÎŶ¯Ì¬
ÐÂÊÖÈëÃÅ
¼¼ÊõÇ°ÑØ
ϵͳ¹ÜÀí
ÍøÂç¹ÜÀí
ʹÓþ­Ñé
±à³Ì¿ª·¢
ϵͳ°²È«
½â¾ö·½°¸
Ó²¼þÏà¹Ø
Unix¼Ò×å
Êý¾Ý¿âÀà
¹ÛµãÆÀÂÛ
ÈËÎï½éÉÜ



Linuxeden.com-- Linuxeden ÐÂÎÅ Îĵµ ×ÊÁÏ ½Ì³Ì LinuxÒÁµéÔ° / Ó²¼þÏà¹Ø / RTL8139 Çý¶¯³ÌÐò½âÎö
RTL8139 Çý¶¯³ÌÐò½âÎö¡¡¡¡ÕÒlinux¹¤×÷,ÕÐlinuxÈ˲Å,µ½LinuxedenÈË²ÅÆµµÀ
2001-09-02    otto       µã»÷: 16055


ǰÑÔ
RTL8139 ¿ÉÄÜÊÇĿǰ×îÊÜ»¶Ó­µÄÍøÂ翨£¬ËüµÄ¼Û¸ñ±ãÒË£¬¹¦ÄÜÉÏÒ²»¹ÄܽÓÊÜ¡£ËäÈ»ÔÚЧÄÜÉÏÓÐʱ»áÂÔ²»¼°Intel µÄ eepro100£¬µ«ÒòΪ¼Û¸ñʵÔÚÌ«±ãÒËÁË£¬ËùÒÔоƬÉϵÄÒ»µãСÎÊÌâͨ³£Ò²½ÓºöÂÔ²»¼Æ¡£

·Ï»°ÉÙ»°£¬ÂíÉÏÀ´ËµÃ÷ 8139too Õâ¸öÇý¶¯³ÌÐò¡£8139 ËäÈ»¼Û¸ñ²»¸ß£¬µ«¸ÃÓеŦÄÜÒ»µãÒ²²»È±¡£ËüÄÚ½¨ÁË·ûºÏ MII ¹æ¸ñµÄ tranceiver£¬¿ÉÒÔ×Ô¶¯ÅжÏÁ¬½ÓµÄÍøÂçÊÇÄÇÒ»ÖÖÐÍ̬¡£ËüÒ²¿ÉÒÔʹÓà DMA Ö±½ÓʹÓÃλÓÚÖ÷¼ÇÒäÌåµÄ»ºÇøÀ´´æÍøÂçÉϽÓÊյķâ°ü£¬Í¬ÑùµÄ£¬´ý´«Ë͵ķâ°üÒ²¿ÉÀûÓà DMA ´«Ë͵½ÍøÂ翨ÉÏ¡£ËùÒÔËäÈ»ÔÚ 8139 оƬÉÏÖ»ÓÐ 2K µÄ½ÓÊÕ»º³åÇøºÍ 2K µÄ´«ËÍ»º³åÇø£¬ÆäЧÄÜÈÔÊ®·Ö²»´í¡£

³ýÁË realtek ±¾ÉíÍ⣬Óв»Éٵij§ÉÌҲʹÓÃÏàͬµÄÄÚºËÉú²úÁËºÍ 8139 ÏàÈݵÄÍøÂçоƬ£¬°üÀ¨ÁË

SMC 1211
MPX 5030
DELTA 8139
ADDTRON 8139
DFE 538
¿ÉÄÜ»¹Óиü¶à¡£
Çý¶¯³ÌÐò³õʼ»¯
¾ÍÏñÆäËüµÄÇý¶¯³ÌÐòÒ»Ñù£¬Çý¶¯³ÌÐòÔÚʹÓà insmod ÔØÈëʱ£¬µÚÒ»¸ö³õºô½ÐµÄº¯ÊýÊÇ init_module£¬ÔÚʹÓà rmmod ÒÆ³ýʱ£¬cleanuo_module »á±»ºô½Ð¡£ÔÚ init_module ÖУ¬ÎÒÃÇ×¢²áÁËÒ»¸ö PCI Çý¶¯³ÌÐò
static struct pci_driver rtl8139_pci_driver = {
name: MODNAME,
id_table: rtl8139_pci_tbl,
probe: rtl8139_init_one,
remove: rtl8139_remove_one,
suspend: rtl8139_suspend,
resume: rtl8139_resume,
};


static int __init rtl8139_init_module (void)
{
return pci_module_init (&rtl8139_pci_driver);
}

Õâ¸ö½á¹¹ºÍÉϴνéÉÜµÄ sis900 Æäʵ²î±ð²»´ó¡£rtl8139_init_one ÓÃÀ´³õʼ»¯Ò»¸ö 8139 оƬ¡£PCI Çý¶¯³ÌÐò×î´óµÄºÃ´¦ÊÇ PCI BUS ÌṩÁË×é̬¿Õ¼ä (configuration space) À´´æ·ÅÇý¶¯³ÌÐòËùÐèµÄ IO λַ¼°ÖжϺÅÂëµÈ×ÊÁÏ£¬ÎÒÃDz»±ØÔÙÏñ ISA Çý¶¯³ÌÐòÒ»ÑùÐèÒªÖ¸¶¨ÕâЩ×ÊÔ´¡£

rtl8139_init_one »áºô½Ð rtl8139_init_board À´³õʼ»¯Ð¾Æ¬£¬»ù±¾ÉÏ 8139 Õâ¸öоƬËãÊÇÒ»¸öºÜÈÝÒ×ʹÓõÄоƬ£¬»ù±¾µÄ PCI ³õʼ»¯ºó¾Í¿ÉÒÔÖ±½ÓʹÓÃÁË¡£ËùÒÔ rtl8139_init_one ºÍ rtl8139_init_board Æäʵ¶à°ëÊÇÔÚ×öһЩ´íÎó¼ì²éµÄ¶¯×÷£¬²¢ÓÉ PCI ±í¸ñÖÐËùµÃÉÔºó»áÓõĵ½µÄ×ÊÔ´¡£

ÎÒ´Ó rtl8139_init_board ÖÐÈ¡³öһЩ±È½ÏÖØÒªµÄƬ¶Ï¼ÓÒÔ˵Ã÷£¬ÆäËüµÄ²¿·ÝÇë×ÔÐвο¼Ô´´úÂë¡£
......
// ÓÉ PCI ×ÓϵͳÖжÁ³öËùÐèµÄ×ÊÔ´
mmio_start = pci_resource_start (pdev, 1);
mmio_end = pci_resource_end (pdev, 1);
mmio_flags = pci_resource_flags (pdev, 1);
mmio_len = pci_resource_len (pdev, 1);
......
......
// ½«ÕâЩ×ÊÔ´±£ÁôÏÂÀ´
rc = pci_request_regions (pdev, "8139too");
pci_set_master (pdev);
......
// ½« IO λַ¶ÔÓ³µ½¼ÇÒäÌå
ioaddr = ioremap (mmio_start, mmio_len);
dev->base_addr = (long) ioaddr;
tp->mmio_addr = ioaddr;
......
// ÖØÉèоƬ
RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdReset);

/* Check that the chip has finished the reset. */
for (i = 1000; i > 0; i--) {
barrier();
udelay (10);
if ((RTL_R8 (ChipCmd) & CmdReset) == 0)
break;
}
// ÅжÏоƬȷµÄ°æ±¾
......

ÔÚ rtl8139_init_one ÖÐ×îÖØÒªµÄÊÇÏÂÃæÕâÒ»¶Î
dev->open = rtl8139_open;
dev->hard_start_xmit = rtl8139_start_xmit;
dev->stop = rtl8139_close;
dev->get_stats = rtl8139_get_stats;
dev->set_multicast_list = rtl8139_set_rx_mode;
dev->do_ioctl = mii_ioctl;
dev->tx_timeout = rtl8139_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;

dev->irq = pdev->irq;

»ù±¾ÉϺÍÉϴνéÉܵĺ¯Êý»ù±¾ÉÏÏàͬ£¬Ôڴ˲»ÔÙÖØ¸´¡£ÉÏÃæ±È½ÏÌØ±ðµÄ¿ÉÄÜÖ»ÓÐ ioremap Õâ¸öº¯Êý£¬ËüµÄÓÃ;Êǽ« mmio_start ¿ªÊ¼ mmio_len ³¤¶ÈµÄ IO Ó³Éäµ½¼ÇÒäÌåÖУ¬Ö®ºóÎÒÃǾͿÉÒÔÖ±½ÓʹÓú¯ÊýµÄ´«»ØÖµÀ´×ö IO µÄ¶¯×÷ÁË¡£

Ò»°ã¶øÑÔ£¬mmio_start µÄÖµÊÇÒ»¸öλÓÚ CPU ¶¨Ö·¿Õ¼äÖеÄʵÌåλַ£¬ÔÚÒ»°ãµÄ¼Ü¹¹Ï£¬Ó²¼þµÄÉè¼ÆÕ߻ᱣÁôÒ»¿é¼ÇÒäÌåλÖøø¼ÇÒäÌåÓ³Éä×°Öà (memory-mapped device) ʹÓá£ÕâЩװÖÃÔÊÐí CPU ÓüÇÒäÌåµ÷Óõķ½Ê½È¡ÓÃÆäÉϵÄÔÝ´æÆ÷£¬ÔÚÓÐЩ²»Ö§Ô® IO µ÷Óõļܹ¹ÖУ¬ÕâЩΨһȡµÃ×°ÖÃÔÝ´æÆ÷µÄ·½·¨¡£

¾Ù¸öÀý˵£¬Èç¹ûÄãÒªµ÷ÓÃµÚ 100 ºÅÔÝ´æÆ÷£¬Äã¿ÉÒÔʹÓÃ
unsigned int *ap = (unsigned int *) mmio_start + 0x100;
printf("register 0x100 = %x\n", *ap);

½ÓÏÂÀ´ÎÒÃÇÒ»Ò»½âÊÍÕâЩº¯Êý¡£



¿ªÊ¼×°ÖÃ-- rtl8139_open
Õâ¸öº¯Êý»áÔÚÄãʹÓà ifconfig ʱ³õºô½Ð£¬ÔÚÕâ¸öº¯ÊýÖУ¬Äã±ØÐë×öÏÂÁеÄÊÂ

×¢²áÖжϺ¯Êý rtl8139_interrupt
·ÖÅä²¢³õʼ»¯ 8139 ËùÐèµÄ½ÓÊÕÓë´«ËÍ»º³åÇø¡£
²úÉúÒ»¸ö kernel thread ¸ºÔð²é¿´ÍøÂçÁ¬ÏßµÄ״̬
±È½ÏÌØ±ðµÄÊǵÚÈý¸ö¶¯×÷£¬


rtl8139_start_xmit
Õâ¸öº¯Êý»áÔÚ´«ËÍÒ»¸ö·â°üʱ³õºô½Ð£¬
static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
{
entry = tp->cur_tx % NUM_TX_DESC;


8139 Ö§Ô®Ëĸö´«ËÍ»º³åÇø£¬Äã±ØÐëÌô³öÏÂÒ»¸öÒªÓõĻº³åÇø¡£½ÓÏÂÀ´£¬Äã±ØÐë°Ñ»º³åÇø¼ÇÒäÌåµÄʵÌå±íÖ· (physical address) É趨µ½ 8139 µÄÔÝ´æÆ÷ÖС£
tp->tx_info[entry].skb = skb;
if ((long) skb->data & 3) { /* Must use alignment buffer. */
/* tp->tx_info[entry].mapping = 0; */
memcpy (tp->tx_buf[entry], skb->data, skb->len);
RTL_W32 (TxAddr0 + (entry * 4),
tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs));
} else {
tp->tx_info[entry].mapping =
pci_map_single (tp->pci_dev, skb->data, skb->len,
PCI_DMA_TODEVICE);
RTL_W32 (TxAddr0 + (entry * 4), tp->tx_info[entry].mapping);
}

ÉÏÃæµÄ³ÌÐòÂëСÐĵĴ¦ÀíµÄ alignment µÄÎÊÌ⣬ 8139 ÒªÇ󻺳åÇøµÄ±íÖ·±ØÐë¶ÔÆë 32 λԪ¡£Ò²¾ÍÊÇ˵λַ±ØÐëÄܱ» 4 ³ý¾¡¡£Èç¹û²»Ðеϰ£¬ÎÒÃDZØÐëÁíÍâ°²ÅÅÒ»¸ö±íÖ·¶ÔÆë 32 λԪµÄ»º³åÇø£¬°Ñ×ÊÁÏ¿½±´µ½ÄÇÀïÈ¥£¬È»ºó½«Õâ¸öлº³åÇøµÄʵÌå±íÖ·´æ·Åµ½ÔÝ´æÆ÷ÖÐÈ¥¡£


RTL_W32 (TxStatus0 + (entry * sizeof (u32)),
tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));

ÕâÒ»¶Î³ÌÐòÓÃÀ´É趨·â°üµÄ³¤¶È£¬Ò»¸öÕýÈ·µÄ ethernet ·â°ü±ØÐëÖÁÉÙÓÐ 64 λԪ×鳤¡£²»Ðҵģ¬8139 ²»¹ÜÕâ¼þÊ£¬ÄãÉ趨¶à³¤Ëü¾ÍËͶàÉÙ¡£ÉÏÃæÕâÒ»ÐгÌÐò¾ÍÔÚÈ·¶¨·â°üµÄ³¤¶ÈÖÁÉÙÓÐ ETH_ZLEN¡£


dev->trans_start = jiffies;
spin_lock_irq (&tp->lock);

tp->cur_tx++;
if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx)
netif_stop_queue (dev);

spin_unlock_irq (&tp->lock);
return 0;
}

ÕâÒÔǰ½âÊ͹ýµ½£¬µ±»º³åÇøÓÃÍêʱ±ØÐë֪ͨÉϲ㲻ҪÔÙËÍ·â°üÏÂÀ´ÁË¡£



rtl8139_set_rx_mode
Õâ¸öº¯ÊýÓÃÀ´É趨½ÓÊÕµÄģʽ£¬8139 ÌṩÁË 64 ×é MAC λַ filter¡£Ö»ÓзûºÏÕâЩ filter µÄλַоƬ²Å»áÓÃÖжÏ֪ͨ CPU ǰÀ´´¦Àí£¬Ò»°ã״̬Ï£¬ÎÒÃÇÖ»½ÓÊÕºÍ 8139 ±¾Éí MAC Ïà·ûµÄ·â°ü¡£Ö»ÓÐÔÚÏñ tcpdump Ö®ÀàµÄ³ÌÐòÖвŻáÏëÒª½ÓÊÕÆäËüµÄ·â°ü¡£

rtl8139_interrupt
ÔÚÖжϺ¯ÊýÖУ¬ÎÒÃDZØÐ뽫״̬Âë¶ÁÈ룬Ȼºó¸ù¾Ý״̬ÂëµÄָʾ×ö²»Í¬µÄÊ¡£ÎÒÃÇÒª´¦ÀíµÄ×´¿öÓÐ

·¢Éú´íÎ󣬿ÉÄÜÊǽÓÊÕ»º³åÇøÂúÁË£¬´«ËÍ·¢Éú´íÎó£¬bus ·¢Éú´íÎ󣬽ÓÊÕ·¢Éú´íÎ󡣸ù¾Ý²»Í¬µÄ×´¿ö£¬±ØÐë×ö²»Í¬µÄ´¦Àí¡£Èç¹û´«ËÍ´íÎó£¬ÔòÔÙËÍÒ»´Î¡£Èç¹û½ÓÊÕ´íÎó£¬ÄÇ¿ÉÄÜÖ»ºÃµÈ´ýÉϲãЭ¶¨·¢ÏÖ²¢ÖØËÍ·â°ü¡£Èç¹ûÊÇ PVCI BUS ´íÎó£¬Ôò¿ÉÄÜÒªÖØÖà BUS¡£
½ÓÊÕµ½·â°ü£¬ºô½Ð rtl8139_rx_interrupt
´«ËÍÍêÒ»¸ö·â°ü£¬ºô½Ð rtl8139_tx_interrupt
µ±½ÓÊÕµ½Ò»¸ö·â°üʱ£¬ÎÒÃDZØÐë֪ͨÉϲãЭ¶¨Ç°¼ì´¦Àí
skb = dev_alloc_skb (pkt_size + 2);
if (skb) {
skb->dev = dev;
skb_reserve (skb, 2); /* 16 byte align the IP fields. */

eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0);
skb_put (skb, pkt_size);

skb->protocol = eth_type_trans (skb, dev);
netif_rx (skb);
dev->last_rx = jiffies;
tp->stats.rx_bytes += pkt_size;
tp->stats.rx_packets++;
} else {

Õâ¶Î³ÌÐòÊǷdz£µäÐ͵ĽÓÊÕ·â°ü³ÌÐò£¬ÏÈʹÓà dev_alloc_skb ·ÖÅäÒ»¶Î×ã¹»´óСµÄ»º³åÇø¡£skb_put»áµ÷Õû»º³åÇøµÄ´óС£¬¹Ø¼øÔÚʹÓà netif_rx ֪ͨÉϲãЭ¶¨ÓÐеķâ°ü´«Èë¡£ÔÚÉÔºó»áÓÉ BH_NET Õâ¸ö bottom half ´¦ÀíÕâ¸ö·â°ü¡£
µ±Ò»¸ö·â°ü´«ËÍÍê³Éºó£¬ÎÒÃDZØÐ뽫»º³åÇøÊÍ·Å¡£Õâ¼þ¹¤×÷ÔÚ rtl8139_tx_interrupt Öб»Íê³É£¬´ËʱÎÒÃDZØÐëºô½ÐÉϲãЭ¶¨±íʾ¿ÉÒÔ´«ËÍеķâ°üÁË¡£Õâ¼þÊÂÓÉÏÂÁÐÔÚ rtl8139_tx_interrupt ×îºóÃæµÄ³ÌÐòÍê³É
if (tp->dirty_tx != dirty_tx) {
tp->dirty_tx = dirty_tx;
if (netif_queue_stopped (dev))
netif_wake_queue (dev);
}

ÎÒÃÇСÐĵıÜÃâºô½ÐÌ«¶à´Î netif_wake_queue£¬Ö»ÓÐÔÚ×°Öüº¾­ÒòΪ»º³åÇøÂúÁËÇÒÓÐеķâ°üÒª´«ËÍʱ²ÅÈ¥ºô½Ð netif_wake_queue¡£


½áÓï
ÆäʵÎÒ»¹Óкܶàϸ½Ú»¹Ã»ÓнâÊÍ£¬Èç MII µÄ´¦Àí£¬´íÎóµÄ´¦ÀíºÍ eeprom µÄ´¦Àí£¬ÕâЩ¾ÍÁô¸ø´ó¼Ò×ÔÐÐÑо¿ÁË¡£Èç¹ûÓÐÈËÓÐÐËȤ½«ÕâЩϸ½Ú²¹ÉÏ£¬ÎÒºÜÀÖÒ⽫ËüÃǼÓÈëÎÄÕÂÖ®ÖС£

ÔðÈα༭: otto
·¢±íÆÀÂÛ ²é¿´ÆÀÂÛ ¼ÓÈëÊÕ²Ø Email¸øÅóÓÑ ´òÓ¡±¾ÎÄ
Èç¹ûÄãÏë¶Ô¸ÃÎÄÕÂÆÀ·Ö, ÇëÏȵǽ, Èç¹ûÄãÈÔδע²á,Çëµã»÷×¢²áÁ´½Ó×¢²á³ÉΪ±¾Õ¾»áÔ±.
ƽ¾ùµÃ·Ö 0, ¹² 0 ÈËÆÀ·Ö
1 2 3 4 5 6 7 8 9 10
Copyright © 2002 -2003 Linuxeden.com-- Linuxeden ÐÂÎÅ Îĵµ ×ÊÁÏ ½Ì³Ì LinuxÒÁµéÔ°
All rights reserved.