DM9000是開發板經采用的網絡芯片,是一種高度集成而且功耗很低的高速網絡控制器,可以和CPU直連,支持10/100M以太網連接,芯片內部自帶16K SARM(3KB用來發送,13KB用來接收).
1.模塊初始化
static?struct?platform_driver?dm9000_driver?=?{??
.driver?=?{??
.name????=?"dm9000",??
.owner???=?THIS_MODULE,??
},??
.probe???=?dm9000_probe,??
.remove??=?__devexit_p(dm9000_drv_remove),??
.suspend?=?dm9000_drv_suspend,??
.resume??=?dm9000_drv_resume,??
};??
static?int?__init??
dm9000_init(void)??
{??
printk(KERN_INFO?"%s?Ethernet?Driver,?V%s\n",?CARDNAME,?DRV_VERSION);??
return?platform_driver_register(&dm9000_driver);??
}??
static struct platform_driver dm9000_driver = {.driver= {.name = "dm9000",.owner = THIS_MODULE,},.probe = dm9000_probe,.remove = __devexit_p(dm9000_drv_remove),.suspend = dm9000_drv_suspend,.resume = dm9000_drv_resume,};static int __initdm9000_init(void){printk(KERN_INFO "%s Ethernet Driver, V%s\n", CARDNAME, DRV_VERSION);return platform_driver_register(&dm9000_driver);}
模塊初始化完成了基于platfrom平臺的DM9000網卡驅動的注冊,當DM9000網卡找到其對應的能處理的platform設備后調用probe函數。
2.DM9000網卡初始化
在probe函數中完成了對DM9000網卡的初始化
DM9000的特性:DM9000地址信號和數據信號復用使用CMD引腳區分它們(CMD為低是讀寫DM900地址寄存器,CMD為高時讀寫DM9000數據寄存器),訪問DM9000內部寄存器時,先將CMD置低,寫DM900地址寄存器,然后將CMD置高,讀寫DM9000數據寄存器。
static?int?__devinit??
dm9000_probe(struct?platform_device?*pdev)??
{?????
struct?dm9000_plat_data?*pdata?=?pdev->dev.platform_data;??
struct?board_info?*db;??/*?Point?a?board?information?structure?*/??
struct?net_device?*ndev;??
const?unsigned?char?*mac_src;??
int?ret?=?0;??
int?iosize;??
int?i;??
u32?id_val;??
/*?Init?network?device?*/??
//申請net_device結構??
ndev?=?alloc_etherdev(sizeof(struct?board_info));??
if?(!ndev)?{??
dev_err(&pdev->dev,?"could?not?allocate?device.\n");??
return?-ENOMEM;??
}??
//將net_device的parent指針指向platform_device對象,表示該設備掛載platform設備上。??
SET_NETDEV_DEV(ndev,?&pdev->dev);???
dev_dbg(&pdev->dev,?"dm9000_probe()\n");??
/*?setup?board?info?structure?*/??
//獲取net_device私有數據結構指針??
db?=?netdev_priv(ndev);??
memset(db,?0,?sizeof(*db));??
//設置相關設備??
db->dev?=?&pdev->dev;??
db->ndevndev?=?ndev;??
spin_lock_init(&db->lock);??
mutex_init(&db->addr_lock);??
INIT_DELAYED_WORK(&db->phy_poll,?dm9000_poll_work);??
//獲取平臺設備資源。包括DM9000地址寄存器地址,DM9000數據寄存器地址,和DM900所占用的中斷號??
db->addr_res?=?platform_get_resource(pdev,?IORESOURCE_MEM,?0);??
db->data_res?=?platform_get_resource(pdev,?IORESOURCE_MEM,?1);??
db->irq_res??=?platform_get_resource(pdev,?IORESOURCE_IRQ,?0);??
if?(db->addr_res?==?NULL?||?db->data_res?==?NULL?||??
db->irq_res?==?NULL)?{??
dev_err(db->dev,?"insufficient?resources\n");??
ret?=?-ENOENT;??
goto?out;??
}??
//申請地址寄存器IO內存區域并映射??
iosize?=?res_size(db->addr_res);??
db->addr_req?=?request_mem_region(db->addr_res->start,?iosize,??
pdev->name);??
if?(db->addr_req?==?NULL)?{??
dev_err(db->dev,?"cannot?claim?address?reg?area\n");??
ret?=?-EIO;??
goto?out;??
}??
db->io_addr?=?ioremap(db->addr_res->start,?iosize);??
if?(db->io_addr?==?NULL)?{??
dev_err(db->dev,?"failed?to?ioremap?address?reg\n");??
ret?=?-EINVAL;??
goto?out;??
}??
//申請數據寄存器IO內存區域并映射??
iosize?=?res_size(db->data_res);??
db->data_req?=?request_mem_region(db->data_res->start,?iosize,??
pdev->name);??
if?(db->data_req?==?NULL)?{??
dev_err(db->dev,?"cannot?claim?data?reg?area\n");??
ret?=?-EIO;??
goto?out;??
}??
db->io_data?=?ioremap(db->data_res->start,?iosize);??
if?(db->io_data?==?NULL)?{??
dev_err(db->dev,?"failed?to?ioremap?data?reg\n");??
ret?=?-EINVAL;??
goto?out;??
}??
/*?fill?in?parameters?for?net-dev?structure?*/??
ndev->base_addr?=?(unsigned?long)db->io_addr;??
ndev->irq????=?db->irq_res->start;??
//設置數據位寬??
/*?ensure?at?least?we?have?a?default?set?of?IO?routines?*/??
dm9000_set_io(db,?iosize);??
/*?check?to?see?if?anything?is?being?over-ridden?*/??
if?(pdata?!=?NULL)?{??
/*?check?to?see?if?the?driver?wants?to?over-ride?the??
*?default?IO?width?*/??
if?(pdata->flags?&?DM9000_PLATF_8BITONLY)??
dm9000_set_io(db,?1);??
if?(pdata->flags?&?DM9000_PLATF_16BITONLY)??
dm9000_set_io(db,?2);??
if?(pdata->flags?&?DM9000_PLATF_32BITONLY)??
dm9000_set_io(db,?4);??
/*?check?to?see?if?there?are?any?IO?routine??
*?over-rides?*/??
if?(pdata->inblk?!=?NULL)??
db->inblk?=?pdata->inblk;??
if?(pdata->outblk?!=?NULL)??
db->outblk?=?pdata->outblk;??
if?(pdata->dumpblk?!=?NULL)??
db->dumpblk?=?pdata->dumpblk;??
db->flags?=?pdata->flags;??
}??
#ifdef?CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL??
db->flags?|=?DM9000_PLATF_SIMPLE_PHY;??
#endif??
//復位網卡芯片??
dm9000_reset(db);??
//讀取設備ID,判斷是否是驅動能夠處理的網卡芯片??
/*?try?multiple?times,?DM9000?sometimes?gets?the?read?wrong?*/??
for?(i?=?0;?i?8;?i++)?{??
id_val??=?ior(db,?DM9000_VIDL);??
id_val?|=?(u32)ior(db,?DM9000_VIDH)?<8;??
id_val?|=?(u32)ior(db,?DM9000_PIDL)?<16;??
id_val?|=?(u32)ior(db,?DM9000_PIDH)?<24;??
if?(id_val?==?DM9000_ID)??
break;??
dev_err(db->dev,?"read?wrong?id?0x%08x\n",?id_val);??
}??
if?(id_val?!=?DM9000_ID)?{??
dev_err(db->dev,?"wrong?id:?0x%08x\n",?id_val);??
ret?=?-ENODEV;??
goto?out;??
}??
/*?Identify?what?type?of?DM9000?we?are?working?on?*/??
id_val?=?ior(db,?DM9000_CHIPR);??
dev_dbg(db->dev,?"dm9000?revision?0x%02x\n",?id_val);??
switch?(id_val)?{??
case?CHIPR_DM9000A:??
db->type?=?TYPE_DM9000A;??
break;??
case?CHIPR_DM9000B:??
db->type?=?TYPE_DM9000B;??
break;??
default:??
dev_dbg(db->dev,?"ID?%02x?=>?defaulting?to?DM9000E\n",?id_val);??
db->type?=?TYPE_DM9000E;??
}??
/*?from?this?point?we?assume?that?we?have?found?a?DM9000?*/??
/*?driver?system?function?*/??
ether_setup(ndev);??
//設置網卡芯片的接口函數??
ndev->open????????=?&dm9000_open;??
ndev->hard_start_xmit????=?&dm9000_start_xmit;??
ndev->tx_timeout?????????=?&dm9000_timeout;??
ndev->watchdog_timeo?=?msecs_to_jiffies(watchdog);??
ndev->stop????????=?&dm9000_stop;??
ndev->set_multicast_list?=?&dm9000_hash_table;??
ndev->ethtool_ops?????=?&dm9000_ethtool_ops;??
ndev->do_ioctl????????=?&dm9000_ioctl;??
#ifdef?CONFIG_NET_POLL_CONTROLLER??
ndev->poll_controller?????=?&dm9000_poll_controller;??
#endif??
db->msg_enable???????=?NETIF_MSG_LINK;??
db->mii.phy_id_mask??=?0x1f;??
db->mii.reg_num_mask?=?0x1f;??
db->mii.force_media??=?0;??
db->mii.full_duplex??=?0;??
db->mii.dev???????=?ndev;??
db->mii.mdio_read????=?dm9000_phy_read;??
db->mii.mdio_write???=?dm9000_phy_write;??
mac_src?=?"eeprom";??
//從EEPROM中讀取MAC地址填充dev_addr??
/*?try?reading?the?node?address?from?the?attached?EEPROM?*/??
for?(i?=?0;?i?6;?i?+=?2)??
dm9000_read_eeprom(db,?i?/?2,?ndev->dev_addr+i);??
if?(!is_valid_ether_addr(ndev->dev_addr)?&&?pdata?!=?NULL)?{??
mac_src?=?"platform?data";??
memcpy(ndev->dev_addr,?pdata->dev_addr,?6);??
}??
if?(!is_valid_ether_addr(ndev->dev_addr))?{??
/*?try?reading?from?mac?*/??
mac_src?=?"chip";??
for?(i?=?0;?i?6;?i++)??
ndev->dev_addr[i]?=?ior(db,?i+DM9000_PAR);??
}??
if?(!is_valid_ether_addr(ndev->dev_addr))??
dev_warn(db->dev,?"%s:?Invalid?ethernet?MAC?address.?Please?"??
"set?using?ifconfig\n",?ndev->name);??
//設置平臺設備驅動的dev成員為ndev。??
platform_set_drvdata(pdev,?ndev);??
//注冊網絡設備驅動??
ret?=?register_netdev(ndev);??
if?(ret?==?0)??
printk(KERN_INFO?"%s:?dm9000%c?at?%p,%p?IRQ?%d?MAC:?%pM?(%s)\n",??
ndev->name,?dm9000_type_to_char(db->type),??
db->io_addr,?db->io_data,?ndev->irq,??
ndev->dev_addr,?mac_src);??
return?0;??
out:??
dev_err(db->dev,?"not?found?(%d).\n",?ret);??
dm9000_release_board(pdev,?db);??
free_netdev(ndev);??
return?ret;??
}??
static int __devinitdm9000_probe(struct platform_device *pdev){struct dm9000_plat_data *pdata = pdev->dev.platform_data;struct board_info *db;/* Point a board information structure */struct net_device *ndev;const unsigned char *mac_src;int ret = 0;int iosize;int i;u32 id_val;/* Init network device *///申請net_device結構ndev = alloc_etherdev(sizeof(struct board_info));if (!ndev) {dev_err(&pdev->dev, "could not allocate device.\n");return -ENOMEM;}//將net_device的parent指針指向platform_device對象,表示該設備掛載platform設備上。SET_NETDEV_DEV(ndev, &pdev->dev);dev_dbg(&pdev->dev, "dm9000_probe()\n");/* setup board info structure *///獲取net_device私有數據結構指針db = netdev_priv(ndev);memset(db, 0, sizeof(*db));//設置相關設備db->dev = &pdev->dev;db->ndev = ndev;spin_lock_init(&db->lock);mutex_init(&db->addr_lock);INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);//獲取平臺設備資源。包括DM9000地址寄存器地址,DM9000數據寄存器地址,和DM900所占用的中斷號db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);if (db->addr_res == NULL || db->data_res == NULL ||db->irq_res == NULL) {dev_err(db->dev, "insufficient resources\n");ret = -ENOENT;goto out;}//申請地址寄存器IO內存區域并映射iosize = res_size(db->addr_res);db->addr_req = request_mem_region(db->addr_res->start, iosize,pdev->name);if (db->addr_req == NULL) {dev_err(db->dev, "cannot claim address reg area\n");ret = -EIO;goto out;}db->io_addr = ioremap(db->addr_res->start, iosize);if (db->io_addr == NULL) {dev_err(db->dev, "failed to ioremap address reg\n");ret = -EINVAL;goto out;}//申請數據寄存器IO內存區域并映射iosize = res_size(db->data_res);db->data_req = request_mem_region(db->data_res->start, iosize,pdev->name);if (db->data_req == NULL) {dev_err(db->dev, "cannot claim data reg area\n");ret = -EIO;goto out;}db->io_data = ioremap(db->data_res->start, iosize);if (db->io_data == NULL) {dev_err(db->dev, "failed to ioremap data reg\n");ret = -EINVAL;goto out;}/* fill in parameters for net-dev structure */ndev->base_addr = (unsigned long)db->io_addr;ndev->irq= db->irq_res->start;//設置數據位寬/* ensure at least we have a default set of IO routines */dm9000_set_io(db, iosize);/* check to see if anything is being over-ridden */if (pdata != NULL) {/* check to see if the driver wants to over-ride the* default IO width */if (pdata->flags & DM9000_PLATF_8BITONLY)dm9000_set_io(db, 1);if (pdata->flags & DM9000_PLATF_16BITONLY)dm9000_set_io(db, 2);if (pdata->flags & DM9000_PLATF_32BITONLY)dm9000_set_io(db, 4);/* check to see if there are any IO routine* over-rides */if (pdata->inblk != NULL)db->inblk = pdata->inblk;if (pdata->outblk != NULL)db->outblk = pdata->outblk;if (pdata->dumpblk != NULL)db->dumpblk = pdata->dumpblk;db->flags = pdata->flags;}#ifdef CONFIG_DM9000_FORCE_SIMPLE_PHY_POLLdb->flags |= DM9000_PLATF_SIMPLE_PHY;#endif//復位網卡芯片dm9000_reset(db);//讀取設備ID,判斷是否是驅動能夠處理的網卡芯片/* try multiple times, DM9000 sometimes gets the read wrong */for (i = 0; i < 8; i++) {id_val = ior(db, DM9000_VIDL);id_val |= (u32)ior(db, DM9000_VIDH) << 8;id_val |= (u32)ior(db, DM9000_PIDL) << 16;id_val |= (u32)ior(db, DM9000_PIDH) << 24;if (id_val == DM9000_ID)break;dev_err(db->dev, "read wrong id 0x%08x\n", id_val);}if (id_val != DM9000_ID) {dev_err(db->dev, "wrong id: 0x%08x\n", id_val);ret = -ENODEV;goto out;}/* Identify what type of DM9000 we are working on */id_val = ior(db, DM9000_CHIPR);dev_dbg(db->dev, "dm9000 revision 0x%02x\n", id_val);switch (id_val) {case CHIPR_DM9000A:db->type = TYPE_DM9000A;break;case CHIPR_DM9000B:db->type = TYPE_DM9000B;break;default:dev_dbg(db->dev, "ID %02x => defaulting to DM9000E\n", id_val);db->type = TYPE_DM9000E;}/* from this point we assume that we have found a DM9000 *//* driver system function */ether_setup(ndev);//設置網卡芯片的接口函數ndev->open = &dm9000_open;ndev->hard_start_xmit = &dm9000_start_xmit;ndev->tx_timeout = &dm9000_timeout;ndev->watchdog_timeo = msecs_to_jiffies(watchdog);ndev->stop = &dm9000_stop;ndev->set_multicast_list = &dm9000_hash_table;ndev->ethtool_ops = &dm9000_ethtool_ops;ndev->do_ioctl = &dm9000_ioctl;#ifdef CONFIG_NET_POLL_CONTROLLERndev->poll_controller = &dm9000_poll_controller;#endifdb->msg_enable = NETIF_MSG_LINK;db->mii.phy_id_mask = 0x1f;db->mii.reg_num_mask = 0x1f;db->mii.force_media = 0;db->mii.full_duplex = 0;db->mii.dev = ndev;db->mii.mdio_read = dm9000_phy_read;db->mii.mdio_write = dm9000_phy_write;mac_src = "eeprom";//從EEPROM中讀取MAC地址填充dev_addr/* try reading the node address from the attached EEPROM */for (i = 0; i < 6; i += 2)dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i);if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) {mac_src = "platform data";memcpy(ndev->dev_addr, pdata->dev_addr, 6);}if (!is_valid_ether_addr(ndev->dev_addr)) {/* try reading from mac */mac_src = "chip";for (i = 0; i < 6; i++)ndev->dev_addr[i] = ior(db, i+DM9000_PAR);}if (!is_valid_ether_addr(ndev->dev_addr))dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please ""set using ifconfig\n", ndev->name);//設置平臺設備驅動的dev成員為ndev。platform_set_drvdata(pdev, ndev);//注冊網絡設備驅動ret = register_netdev(ndev);if (ret == 0)printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)\n",ndev->name, dm9000_type_to_char(db->type),db->io_addr, db->io_data, ndev->irq,ndev->dev_addr, mac_src);return 0;out:dev_err(db->dev, "not found (%d).\n", ret);dm9000_release_board(pdev, db);free_netdev(ndev);return ret;}
我們在來看看讀寫網卡寄存器所用的ior和iow
static?u8??
ior(board_info_t?*?db,?int?reg)??
{??
writeb(reg,?db->io_addr);??
return?readb(db->io_data);??
}??
static?void??
iow(board_info_t?*?db,?int?reg,?int?value)??
{??
writeb(reg,?db->io_addr);??
writeb(value,?db->io_data);??
}??
static u8ior(board_info_t * db, int reg){writeb(reg, db->io_addr);return readb(db->io_data);}static voidiow(board_info_t * db, int reg, int value){writeb(reg, db->io_addr);writeb(value, db->io_data);}
可以看得出是先將要訪問的寄存器地址寫入到地址寄存器,然后在將數據寫入到數據寄存器。地址。
3.打開網卡
在linux終端下使用ifconfig命令時調用net_device的open函數打開網卡設備
static?int??
dm9000_open(struct?net_device?*dev)??
{??
board_info_t?*db?=?netdev_priv(dev);??
unsigned?long?irqflags?=?db->irq_res->flags?&?IRQF_TRIGGER_MASK;??
if?(netif_msg_ifup(db))??
dev_dbg(db->dev,?"enabling?%s\n",?dev->name);??
/*?If?there?is?no?IRQ?type?specified,?default?to?something?that??
*?may?work,?and?tell?the?user?that?this?is?a?problem?*/??
if?(irqflags?==?IRQF_TRIGGER_NONE)??
dev_warn(db->dev,?"WARNING:?no?IRQ?resource?flags?set.\n");??
irqflags?|=?IRQF_SHARED;??
//申請中斷??
if?(request_irq(dev->irq,?&dm9000_interrupt,?irqflags,?dev->name,?dev))??
return?-EAGAIN;??
/*?Initialize?DM9000?board?*/??
//復位網卡芯片??
dm9000_reset(db);??
//初始化網卡(相關寄存器設置)??
dm9000_init_dm9000(dev);??
/*?Init?driver?variable?*/??
db->dbug_cnt?=?0;??
mii_check_media(&db->mii,?netif_msg_link(db),?1);??
//打開發送隊列??
netif_start_queue(dev);??
//調度發送隊列開始工作??
dm9000_schedule_poll(db);??
return?0;??
}???
static intdm9000_open(struct net_device *dev){board_info_t *db = netdev_priv(dev);unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;if (netif_msg_ifup(db))dev_dbg(db->dev, "enabling %s\n", dev->name);/* If there is no IRQ type specified, default to something that* may work, and tell the user that this is a problem */if (irqflags == IRQF_TRIGGER_NONE)dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");irqflags |= IRQF_SHARED;//申請中斷if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev))return -EAGAIN;/* Initialize DM9000 board *///復位網卡芯片dm9000_reset(db);//初始化網卡(相關寄存器設置)dm9000_init_dm9000(dev);/* Init driver variable */db->dbug_cnt = 0;mii_check_media(&db->mii, netif_msg_link(db), 1);//打開發送隊列netif_start_queue(dev);//調度發送隊列開始工作dm9000_schedule_poll(db);return 0;}
4.數據發送
下面說一下DM9000A中的存儲部分,DM9000A內部有一個4K Dword SRAM,其中3KB是作為發送,16KB作為接收,如下圖所示。其中0x0000~0x0BFF是傳說中的TX buffer(TX buffer中只能存放兩個包),0x0C00~0x3FFF是RX buffer。因此在寫內存操作時,當IMR的第7位被設置,如果到達了地址的結尾比如到了3KB,則回卷到0。相似的方式,在讀操作中,當IMR的第7位被設置如果到達了地址的結尾比如16K,則回卷到0x0C00。
DM9000的TX RAM可以同時放兩個包,可以第9行代碼中看出如果大于TXRAM中的包大于2則返回,DM9000會先發送第一個包,然后再發第二個包。
static?int??
dm9000_start_xmit(struct?sk_buff?*skb,?struct?net_device?*dev)??
{??
unsigned?long?flags;??
board_info_t?*db?=?netdev_priv(dev);??
dm9000_dbg(db,?3,?"%s:\n",?__func__);??
//如果TX?RAM中的包大于2個包則返回??
if?(db->tx_pkt_cnt?>?1)??
return?1;??
spin_lock_irqsave(&db->lock,?flags);??
*MWCMD是Memory?data?write?command?with?address?increment?Register(F8H)???
*將要訪問的TXRAM地址寫入地址寄存器。??
/*?Move?data?to?DM9000?TX?RAM?*/??
writeb(DM9000_MWCMD,?db->io_addr);??
//拷貝數據到TXRAM??
(db->outblk)(db->io_data,?skb->data,?skb->len);??
dev->stats.tx_bytes?+=?skb->len;??
db->tx_pkt_cnt++;//增加數據包計數,這個值會在發送完成中斷時進行自減??
如果是第一個包則直接發送??
/*?TX?control:?First?packet?immediately?send,?second?packet?queue?*/??
if?(db->tx_pkt_cnt?==?1)?{??
/*?Set?TX?length?to?DM9000?*/??
/*把數據的長度填到TXPLL(發送包長度低字節)和TXPLH(發送包長度高字節)中*/????
iow(db,?DM9000_TXPLL,?skb->len);????
iow(db,?DM9000_TXPLH,?skb->len?>>?8);????
/*置發送控制寄存器(TX?Control?Register)的發送請求位TXREQ(Auto?clears?after?sending?completely),這樣就可以發送出去了*/???
/*???
*記下此時的時間,這里起一個時間戳的作用,之后的超時會用到。如果當前的系統時間超過設備的trans_start時間???
*至少一個超時周期,網絡層將最終調用驅動程序的tx_timeout。那個這個"一個超時周期"又是什么呢?這個是我們在???
*probe函數中設置的,ndev->watchdog_timeo?=?msecs_to_jiffies(watchdog);???
*/??
dev->trans_start?=?jiffies;??/*?save?the?time?stamp?*/??
}?else?{??????????
//如果是第二個包,則暫時不發送,等待第一個包發送完成時tx_pkt_cnt減為1的時候再發送。??
/*?Second?packet?*/??
db->queue_pkt_len?=?skb->len;??
netif_stop_queue(dev);//停止發送隊列??
}??
spin_unlock_irqrestore(&db->lock,?flags);??
/*?free?this?SKB?*/??
dev_kfree_skb(skb);??
return?0;??
}??
static intdm9000_start_xmit(struct sk_buff *skb, struct net_device *dev){unsigned long flags;board_info_t *db = netdev_priv(dev);dm9000_dbg(db, 3, "%s:\n", __func__);//如果TX RAM中的包大于2個包則返回if (db->tx_pkt_cnt > 1)return 1;spin_lock_irqsave(&db->lock, flags);*MWCMD是Memory data write command with address increment Register(F8H)*將要訪問的TXRAM地址寫入地址寄存器。/* Move data to DM9000 TX RAM */writeb(DM9000_MWCMD, db->io_addr);//拷貝數據到TXRAM(db->outblk)(db->io_data, skb->data, skb->len);dev->stats.tx_bytes += skb->len;db->tx_pkt_cnt++;//增加數據包計數,這個值會在發送完成中斷時進行自減如果是第一個包則直接發送/* TX control: First packet immediately send, second packet queue */if (db->tx_pkt_cnt == 1) {/* Set TX length to DM9000 *//*把數據的長度填到TXPLL(發送包長度低字節)和TXPLH(發送包長度高字節)中*/iow(db, DM9000_TXPLL, skb->len);iow(db, DM9000_TXPLH, skb->len >> 8);/*置發送控制寄存器(TX Control Register)的發送請求位TXREQ(Auto clears after sending completely),這樣就可以發送出去了*//**記下此時的時間,這里起一個時間戳的作用,之后的超時會用到。如果當前的系統時間超過設備的trans_start時間*至少一個超時周期,網絡層將最終調用驅動程序的tx_timeout。那個這個"一個超時周期"又是什么呢?這個是我們在*probe函數中設置的,ndev->watchdog_timeo = msecs_to_jiffies(watchdog);*/dev->trans_start = jiffies;/* save the time stamp */} else {//如果是第二個包,則暫時不發送,等待第一個包發送完成時tx_pkt_cnt減為1的時候再發送。/* Second packet */db->queue_pkt_len = skb->len;netif_stop_queue(dev);//停止發送隊列}spin_unlock_irqrestore(&db->lock, flags);/* free this SKB */dev_kfree_skb(skb);return 0;}
4.中斷
static?irqreturn_t?dm9000_interrupt(intirq,?void?*dev_id)??
{??
structnet_device?*dev?=?dev_id;??
board_info_t*db?=?netdev_priv(dev);??
intint_status;??
unsignedlong?flags;??
u8reg_save;??
dm9000_dbg(db,3,?"entering?%s\n",?__func__);??
/*A?real?interrupt?coming?*/??
//禁止所用中斷??
/*holders?of?db->lock?must?always?block?IRQs?*/??
spin_lock_irqsave(&db->lock,flags);??
//保存寄存器地址??
/*Save?previous?register?address?*/??
reg_save=?readb(db->io_addr);??
//禁止DM9000的所有中斷??
/*Disable?all?interrupts?*/??
iow(db,DM9000_IMR,?IMR_PAR);??
/*Got?DM9000?interrupt?status?*/??
//獲取中斷狀態寄存器的值??
int_status=?ior(db,?DM9000_ISR);?/*?Got?ISR?*/??
iow(db,DM9000_ISR,?int_status);?/*?Clear?ISRstatus?*/??
if(netif_msg_intr(db))??
dev_dbg(db->dev,"interrupt?status?%02x\n",?int_status);??
/*Received?the?coming?packet?*/??
//如果是讀取中斷,則開始讀取??
if(int_status?&?ISR_PRS)??
dm9000_rx(dev);??
/*Trnasmit?Interrupt?check?*/??
//是發送完成中斷則處理發送完成后的事情??
if(int_status?&?ISR_PTS)??
dm9000_tx_done(dev,db);??
if(db->type?!=?TYPE_DM9000E)?{??
if(int_status?&?ISR_LNKCHNG)?{??
/*fire?a?link-change?request?*/??
schedule_delayed_work(&db->phy_poll,1);??
}??
}??
/*Re-enable?interrupt?mask?*/??
//重新打開DM9000的內部中斷??
iow(db,DM9000_IMR,?db->imr_all);??
/*Restore?previous?register?address?*/??
//恢復寄存器的值??
writeb(reg_save,db->io_addr);??
//重新允許所有中斷??
spin_unlock_irqrestore(&db->lock,flags);??
returnIRQ_HANDLED;??
}??
static irqreturn_t dm9000_interrupt(intirq, void *dev_id){structnet_device *dev = dev_id;board_info_t*db = netdev_priv(dev);intint_status;unsignedlong flags;u8reg_save;dm9000_dbg(db,3, "entering %s\n", __func__);/*A real interrupt coming *///禁止所用中斷/*holders of db->lock must always block IRQs */spin_lock_irqsave(&db->lock,flags);//保存寄存器地址/*Save previous register address */reg_save= readb(db->io_addr);//禁止DM9000的所有中斷/*Disable all interrupts */iow(db,DM9000_IMR, IMR_PAR);/*Got DM9000 interrupt status *///獲取中斷狀態寄存器的值int_status= ior(db, DM9000_ISR); /* Got ISR */iow(db,DM9000_ISR, int_status); /* Clear ISRstatus */if(netif_msg_intr(db))dev_dbg(db->dev,"interrupt status %02x\n", int_status);/*Received the coming packet *///如果是讀取中斷,則開始讀取if(int_status & ISR_PRS)dm9000_rx(dev);/*Trnasmit Interrupt check *///是發送完成中斷則處理發送完成后的事情if(int_status & ISR_PTS)dm9000_tx_done(dev,db);if(db->type != TYPE_DM9000E) {if(int_status & ISR_LNKCHNG) {/*fire a link-change request */schedule_delayed_work(&db->phy_poll,1);}}/*Re-enable interrupt mask *///重新打開DM9000的內部中斷iow(db,DM9000_IMR, db->imr_all);/*Restore previous register address *///恢復寄存器的值writeb(reg_save,db->io_addr);//重新允許所有中斷spin_unlock_irqrestore(&db->lock,flags);returnIRQ_HANDLED;}
5.接收數據
static?void??
dm9000_rx(struct?net_device?*dev)??
{??
board_info_t?*db?=?netdev_priv(dev);??
struct?dm9000_rxhdr?rxhdr;??
struct?sk_buff?*skb;??
u8?rxbyte,?*rdptr;??
bool?GoodPacket;??
int?RxLen;??
/*?Check?packet?ready?or?not?*/??
do?{??
ior(db,?DM9000_MRCMDX);?/*?Dummy?read?*/??
//獲取接收數據的長度??
/*?Get?most?updated?data?*/??
rxbyte?=?readb(db->io_data);??
//檢查設備接收狀態??
/*?Status?check:?this?byte?must?be?0?or?1?*/??
if?(rxbyte?>?DM9000_PKT_RDY)?{??
dev_warn(db->dev,?"status?check?fail:?%d\n",?rxbyte);??
iow(db,?DM9000_RCR,?0x00);??/*?Stop?Device?*/??
iow(db,?DM9000_ISR,?IMR_PAR);???/*?Stop?INT?request?*/??
return;??
}??
if?(rxbyte?!=?DM9000_PKT_RDY)??
return;??
/*?A?packet?ready?now??&?Get?status/length?*/??
GoodPacket?=?true;??
writeb(DM9000_MRCMD,?db->io_addr);??
(db->inblk)(db->io_data,?&rxhdr,?sizeof(rxhdr));??
RxLen?=?le16_to_cpu(rxhdr.RxLen);??
if?(netif_msg_rx_status(db))??
dev_dbg(db->dev,?"RX:?status?%02x,?length?%04x\n",??
rxhdr.RxStatus,?RxLen);??
/*?Packet?Status?check?*/??
if?(RxLen?0x40)?{??
GoodPacket?=?false;??
if?(netif_msg_rx_err(db))??
dev_dbg(db->dev,?"RX:?Bad?Packet?(runt)\n");??
}??
if?(RxLen?>?DM9000_PKT_MAX)?{??
dev_dbg(db->dev,?"RST:?RX?Len:%x\n",?RxLen);??
}??
/*?rxhdr.RxStatus?is?identical?to?RSR?register.?*/??
if?(rxhdr.RxStatus?&?(RSR_FOE?|?RSR_CE?|?RSR_AE?|??
RSR_PLE?|?RSR_RWTO?|??
RSR_LCS?|?RSR_RF))?{??
GoodPacket?=?false;??
if?(rxhdr.RxStatus?&?RSR_FOE)?{??
if?(netif_msg_rx_err(db))??
dev_dbg(db->dev,?"fifo?error\n");??
dev->stats.rx_fifo_errors++;??
}??
if?(rxhdr.RxStatus?&?RSR_CE)?{??
if?(netif_msg_rx_err(db))??
dev_dbg(db->dev,?"crc?error\n");??
dev->stats.rx_crc_errors++;??
}??
if?(rxhdr.RxStatus?&?RSR_RF)?{??
if?(netif_msg_rx_err(db))??
dev_dbg(db->dev,?"length?error\n");??
dev->stats.rx_length_errors++;??
}??
}??
/*?Move?data?from?DM9000?*/??
//如果接收正確,開始接收??
if?(GoodPacket??
&&?((skb?=?dev_alloc_skb(RxLen?+?4))?!=?NULL))?{??
skb_reserve(skb,?2);??
rdptr?=?(u8?*)?skb_put(skb,?RxLen?-?4);//獲取skb的數據指針??
/*?Read?received?packet?from?RX?SRAM?*/??
(db->inblk)(db->io_data,?rdptr,?RxLen);//讀取數據??
dev->stats.rx_bytes?+=?RxLen;??
/*?Pass?to?upper?layer?*/??
skb->protocol?=?eth_type_trans(skb,?dev);??
netif_rx(skb);//將接收到的skb交給協議層??
dev->stats.rx_packets++;??
}?else?{??
/*?need?to?dump?the?packet's?data?*/??
(db->dumpblk)(db->io_data,?RxLen);??
}??
}?while?(rxbyte?==?DM9000_PKT_RDY);??
}??
static voiddm9000_rx(struct net_device *dev){board_info_t *db = netdev_priv(dev);struct dm9000_rxhdr rxhdr;struct sk_buff *skb;u8 rxbyte, *rdptr;bool GoodPacket;int RxLen;/* Check packet ready or not */do {ior(db, DM9000_MRCMDX);/* Dummy read *///獲取接收數據的長度/* Get most updated data */rxbyte = readb(db->io_data);//檢查設備接收狀態/* Status check: this byte must be 0 or 1 */if (rxbyte > DM9000_PKT_RDY) {dev_warn(db->dev, "status check fail: %d\n", rxbyte);iow(db, DM9000_RCR, 0x00);/* Stop Device */iow(db, DM9000_ISR, IMR_PAR);/* Stop INT request */return;}if (rxbyte != DM9000_PKT_RDY)return;/* A packet ready now & Get status/length */GoodPacket = true;writeb(DM9000_MRCMD, db->io_addr);(db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));RxLen = le16_to_cpu(rxhdr.RxLen);if (netif_msg_rx_status(db))dev_dbg(db->dev, "RX: status %02x, length %04x\n",rxhdr.RxStatus, RxLen);/* Packet Status check */if (RxLen < 0x40) {GoodPacket = false;if (netif_msg_rx_err(db))dev_dbg(db->dev, "RX: Bad Packet (runt)\n");}if (RxLen > DM9000_PKT_MAX) {dev_dbg(db->dev, "RST: RX Len:%x\n", RxLen);}/* rxhdr.RxStatus is identical to RSR register. */if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE |RSR_PLE | RSR_RWTO |RSR_LCS | RSR_RF)) {GoodPacket = false;if (rxhdr.RxStatus & RSR_FOE) {if (netif_msg_rx_err(db))dev_dbg(db->dev, "fifo error\n");dev->stats.rx_fifo_errors++;}if (rxhdr.RxStatus & RSR_CE) {if (netif_msg_rx_err(db))dev_dbg(db->dev, "crc error\n");dev->stats.rx_crc_errors++;}if (rxhdr.RxStatus & RSR_RF) {if (netif_msg_rx_err(db))dev_dbg(db->dev, "length error\n");dev->stats.rx_length_errors++;}}/* Move data from DM9000 *///如果接收正確,開始接收if (GoodPacket&& ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) {skb_reserve(skb, 2);rdptr = (u8 *) skb_put(skb, RxLen - 4);//獲取skb的數據指針/* Read received packet from RX SRAM */(db->inblk)(db->io_data, rdptr, RxLen);//讀取數據dev->stats.rx_bytes += RxLen;/* Pass to upper layer */skb->protocol = eth_type_trans(skb, dev);netif_rx(skb);//將接收到的skb交給協議層dev->stats.rx_packets++;} else {/* need to dump the packet's data */(db->dumpblk)(db->io_data, RxLen);}} while (rxbyte == DM9000_PKT_RDY);}
6.發送完成
static?void?dm9000_tx_done(struct?net_device?*dev,?board_info_t?*db)??
{??
int?tx_status?=?ior(db,?DM9000_NSR);????/*?Got?TX?status?*/??
if?(tx_status?&?(NSR_TX2END?|?NSR_TX1END))?{??
/*?One?packet?sent?complete?*/??
//將數據包計數減1??
db->tx_pkt_cnt--;??
dev->stats.tx_packets++;??
if?(netif_msg_tx_done(db))??
dev_dbg(db->dev,?"tx?done,?NSR?%02x\n",?tx_status);??
/*?Queue?packet?check?&?send?*/??
//如果數據包數量依然大于0,說明是TX?RAM中的第二個包,再次啟動發送,將TX?RAM中第二個包發送出去??
if?(db->tx_pkt_cnt?>?0)?{??
/*把數據的長度填到TXPLL(發送包長度低字節)和TXPLH(發送包長度高字節)中*/????
iow(db,?DM9000_TXPLL,?skb->len);????
iow(db,?DM9000_TXPLH,?skb->len?>>?8);????
/*置發送控制寄存器(TX?Control?Register)的發送請求位TXREQ(Auto?clears?after?sending?completely),這樣就可以發送出去了*/???
dev->trans_start?=?jiffies;??
}??
netif_wake_queue(dev);//喚醒發送隊列??
}??
}??
static void dm9000_tx_done(struct net_device *dev, board_info_t *db){int tx_status = ior(db, DM9000_NSR);/* Got TX status */if (tx_status & (NSR_TX2END | NSR_TX1END)) {/* One packet sent complete *///將數據包計數減1db->tx_pkt_cnt--;dev->stats.tx_packets++;if (netif_msg_tx_done(db))dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status);/* Queue packet check & send *///如果數據包數量依然大于0,說明是TX RAM中的第二個包,再次啟動發送,將TX RAM中第二個包發送出去if (db->tx_pkt_cnt > 0) {/*把數據的長度填到TXPLL(發送包長度低字節)和TXPLH(發送包長度高字節)中*/iow(db, DM9000_TXPLL, skb->len);iow(db, DM9000_TXPLH, skb->len >> 8);/*置發送控制寄存器(TX Control Register)的發送請求位TXREQ(Auto clears after sending completely),這樣就可以發送出去了*/dev->trans_start = jiffies;}netif_wake_queue(dev);//喚醒發送隊列}}
7.超時處理
static?void?dm9000_timeout(struct?net_device?*dev)??
{??
board_info_t?*db?=?netdev_priv(dev);??
u8?reg_save;??
unsigned?long?flags;??
/*?Save?previous?register?address?*/??
reg_save?=?readb(db->io_addr);??
spin_lock_irqsave(&db->lock,?flags);??
//停止發送隊列并復位DM9000網卡??
netif_stop_queue(dev);??
dm9000_reset(db);??
dm9000_init_dm9000(dev);??
/*?We?can?accept?TX?packets?again?*/??
//重新發送??
dev->trans_start?=?jiffies;??
netif_wake_queue(dev);??
/*?Restore?previous?register?address?*/??
writeb(reg_save,?db->io_addr);??
spin_unlock_irqrestore(&db->lock,?flags);??
}??
static void dm9000_timeout(struct net_device *dev){board_info_t *db = netdev_priv(dev);u8 reg_save;unsigned long flags;/* Save previous register address */reg_save = readb(db->io_addr);spin_lock_irqsave(&db->lock, flags);//停止發送隊列并復位DM9000網卡netif_stop_queue(dev);dm9000_reset(db);dm9000_init_dm9000(dev);/* We can accept TX packets again *///重新發送dev->trans_start = jiffies;netif_wake_queue(dev);/* Restore previous register address */writeb(reg_save, db->io_addr);spin_unlock_irqrestore(&db->lock, flags);} ?
評論
查看更多