|
ǰÑÔ 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 µÄ´¦Àí£¬ÕâЩ¾ÍÁô¸ø´ó¼Ò×ÔÐÐÑо¿ÁË¡£Èç¹ûÓÐÈËÓÐÐËȤ½«ÕâЩϸ½Ú²¹ÉÏ£¬ÎÒºÜÀÖÒ⽫ËüÃǼÓÈëÎÄÕÂÖ®ÖС£
|