Path of driver engineers for Linux devices-Analysis of dm9000 NIC Driver

Source: Internet
Author: User

Path of driver engineers for Linux devices-Analysis of dm9000 NIC Driver

K-style

Reprinted please indicate from Hengyang Normal College 08 electric 2 k-style http://blog.csdn.net/ayangke,QQ:843308498 mailbox: yangkeemail@qq.com

Dm9000 is a network chip used in the Development Board. It is a highly integrated and low-power high-speed network controller that can be directly connected to the CPU and supports 10/100 M Ethernet connections, the chip comes with 16 k sarm (3 kb for sending and 13 KB for receiving ).

1. module initialization

 

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);}

The module initializes the registration of the dm9000 NIC Driver Based on the platfrom platform. When the dm9000 Nic finds its compatible platform device, it calls the probe function.

 

2. initialize the dm9000 Nic

 

Initialize the dm9000 Nic In the probe function

Dm9000 features: dm9000 address signal and data signal multiplexing use cmd pins to distinguish them (when CMD is low, dm900 address register is read/write, when CMD is high, dm9000 data register is read/write ), when accessing the internal register of dm9000, set cmd to low, write the dm900 address register, and then set cmd to high to read and write the dm9000 data register.

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 * // apply for the net_device structure ndev = alloc_etherdev (sizeof (struct board_info); if (! Ndev) {dev_err (& pdev-> dev, "cocould not allocate device. \ n "); return-ENOMEM;} // point the parent pointer of net_device to the platform_device object, indicating that the device is mounted to the platform device. SET_NETDEV_DEV (ndev, & pdev-> dev); dev_dbg (& pdev-> dev, "dm9000_probe () \ n "); /* setup board info structure * // obtain the private data structure pointer of net_device db = netdev_priv (ndev); memset (db, 0, sizeof (* db )); // set the relevant device 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); // obtain platform device resources. Including the DM9000 Address Register address, DM9000 data register address, and the interrupt number db occupied by DM900-> 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;} // apply for the address register IO memory region and map it to 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;} // apply for the IO memory region of the data register and map it to 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) d B-> io_addr; ndev-> irq = db-> irq_res-> start; // set the data Bit Width/* 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 // reset the NIC chip dm9000_reset (db); // read the device ID to determine whether the NIC chip can be processed by the driver/* 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_v Al | = (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 ); // set the interface function ndev-> open = & dm9000_open; ndev-> hard_start_xmit = & dm9000_start_xmit; ndev-> tx_timeout = & dm9000_timeout; ndev-> watchdog_timeo = watchdog; ndev-> stop = & dm9000_stop; ndev-> set_multicast_list = & dm9000_hash_table; ndev-> ethtool_ops = & dm90 00_ethtool_ops; ndev-> do_ioctl = & dm9000_ioctl; # ifdef restart-> poll_controller = & Environment; # 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"; // read MAC address from EEPROM fill d Ev_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); // set the dev Member of the platform device driver to ndev. Platform_set_drvdata (pdev, ndev); // register the network device driver 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 ;}

Let's take a look at the IOR and Iow used to read and write Nic registers.

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);}

It can be seen that the Register address to be accessed is first written to the address register, and then the data is written to the data register. Address.

3. Enable the NIC

 

Call the net_device OPEN function when using the ifconfig command on a Linux terminal to open the NIC device.

Static intdm9000_open (struct net_device * Dev) {board_info_t * DB = netdev_priv (Dev); unsigned long irqflags = DB-> irq_res-> flags & volumes; If (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 = ir1__trigger_none) dev_warn (db-> Dev, "Warning: No IRQ resource flags set. \ n "); irqflags | = ir1__shared; // request to interrupt if (request_irq (Dev-> IRQ, & dm9000_interrupt, irqflags, Dev-> name, Dev) Return-eagain; /* initialize dm9000 Board * // reset the NIC chip dm9000_reset (db); // initialize the NIC (related register settings) dm9000_init_dm9000 (Dev ); /* init driver variable */DB-> dbug_cnt = 0; mii_check_media (& DB-> MII, netif_msg_link (DB), 1); // open the sending queue netif_start_queue (Dev ); // schedule the sending queue to start working dm9000_schedule_poll (db); Return 0 ;}

4. Data Transmission

 

Next, let's talk about the storage in dm9000a. dm9000a has a 4 k dword sram, where 3 kb is sent and 16 KB is received, as shown in. 0x0000 ~ 0x0bff is the legendary TX buffer (TX buffer can only store two packets), 0x0c00 ~ 0x3fff is the RX buffer. Therefore, when writing memory operations, when the IMR 7th bit is set, if it reaches the end of the address, for example, to 3 kb, it will be rolled back to 0. In a similar way, when the 7th-bit IMR is set to reach the end of the address, for example, 16 K, it is rolled back to 0x0c00.

The TX ram of dm9000 can put two packages at the same time. It can be seen in the code of Line 3 that if the number of packages in txram is greater than 2, dm9000 will first send the first package and then send the second package.

 
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 _); // if there are more than two packages in tx Ram, return if (db-> tx_pkt_cnt> 1) return 1; spin_lock_irqsave (& DB-> lock, flags); * mwcmd is the txt ram address to be accessed by memory data write command with address increment register (f8h. /* Move data to dm9000 TX Ram */writeb (dm9000_mwcmd, DB-> io_addr); // copy data to txram (db-> outblk) (db-> io_data, SKB-> data, SKB-> Len); Dev-> stats. tx_bytes + = SKB-> Len; DB-> tx_pkt_cnt ++; // increase the packet count, this value is automatically subtracted when the sending is interrupted. If it is the first package, it is directly sent/* TX control: first packet immediately send, second packet queue */If (db-> tx_pkt_cnt = 1) {/* Set TX length to dm9000 * // * fill in the Data Length to txpll (the sending package length is low in bytes) and txplh (high packet length) */Iow (dB, dm9000_txpll, SKB-> Len); Iow (dB, dm9000_txplh, SKB-> Len> 8);/* set the sending control register (TX control register) txreq (Auto clears after sending completely), so that you can send it out * // ** to write down the time at this time. Here is a timestamp, later timeout will be used. If the current system time exceeds the trans_start time of the device * at least one timeout period, the network layer will eventually call the tx_timeout of the driver. What is this "One timeout period? This is set in * probe function, ndev-> watchdog_timeo = msecs_to_jiffies (watchdog); */dev-> trans_start = jiffies; /* save the time stamp */} else {// if it is the second package, it will not be sent for the time being. Wait until tx_pkt_cnt is reduced to 1 when the first package is sent. /* Second packet */DB-> queue_pkt_len = SKB-> Len; netif_stop_queue (Dev); // stop sending queue} spin_unlock_irqrestore (& DB-> lock, flags ); /* free this SKB */dev_kfree_skb (SKB); Return 0 ;}

4. Interruption

Static region metadata (intirq, void * dev_id) {structnet_device * dev = dev_id; board_info_t * db = netdev_priv (dev); intint_status; unsignedlong flags; u8reg_save; region (db, 3, "entering % s \ n", _ func __); /* A real interrupt coming * // disable the interrupt used/* holders of db-> lock must always block IRQs */spin_lock_irqsave (& db-> lock, flags ); // Save the register address/* Save previous register address */reg_save = read B (db-> io_addr); // Disable all DM9000 interruptions/* Disable all interrupts */iow (db, DM9000_IMR, IMR_PAR ); /* Got DM9000 interrupt status * // get the value of the interrupt status Register 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 the read is interrupted, read if (int_status & ISR_PRS) dm9000_rx (d Ev);/* 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 * // Re-open the internal interrupt iow of DM9000 (db, DM9000_IMR, db-> imr_all ); /* Restore previous register address * // recover the value of the register writeb (reg_save, db-> io_addr); // re-Allow all suspensions in the spin_unlock_irqrestore (& db-> lock, flags); returnIRQ_HANDLED ;}

5. receive data

 
Static compile (struct net_device * Dev) {board_info_t * DB = netdev_priv (Dev); struct initialize rxhdr; struct sk_buff * SKB; u8 rxbyte, * rdptr; bool goodpacket; int rxlen; /* Check packet ready or not */do {ior (dB, dm9000_mr1_x ); /* dummy read * // get the length of the received data/* get most updated data */rxbyte = readb (db-> io_data ); // check the device receiving status/* status check: This byte must be 0 or 1 */If (rxbyte> dm9000_pkt_rdy) {dev_wa RN (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_1_o_errors ++;} If (rxhdr. rxst ATUS & 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 the receiving is correct, start to receive if (goodpacket & (SKB = dev_alloc_skb (rxlen + 4 ))! = NULL) {skb_reserve (SKB, 2); rdptr = (u8 *) skb_put (SKB, rxlen-4 ); // obtain the SKB Data Pointer/* Read committed ed packet from rx sram */(db-> inblk) (db-> io_data, rdptr, rxlen ); // read data Dev-> stats. rx_bytes + = rxlen;/* pass to upper layer */SKB-> protocol = eth_type_trans (SKB, Dev); netif_rx (SKB ); // send the received SKB to the protocol layer Dev-> stats. rx_packets ++;} else {/* need to dump the packet's data */(db-> dumpblk) (db-> io_data, rxlen );}} while (rxbyte = dm9000_pkt_rdy );}

6. Sent successfully

 
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 & (ns_tx2end | ns_tx1end) {/* One packet sent complete * // reduce the packet count by 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 * // if the number of data packets is still greater than 0, it indicates that the second package in tx ram is sent again, send the second package in tx ram out if (db-> tx_pkt_cnt> 0) {/* fill in the Data Length to TXPLL (low packet length) and TXPLH (high packet length) */iow (db, DM9000_TXPLL, skb-> len); iow (db, DM9000_TXPLH, skb-> len> 8 ); /* set the send request bit TXREQ (Auto clears after sending completely) of the sending Control Register (TX Control Register), so that the request can be sent out */dev-> trans_start = jiffies ;} netif_wake_queue (dev); // wake up the sending queue }}

7. Timeout Processing

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 ); // stop the sending queue and reset the dm9000 Nic netif_stop_queue (Dev); dm9000_reset (db); dm9000_init_dm9000 (Dev ); /* We can accept TX packets again * // resend Dev-> trans_start = jiffies; netif_wake_queue (Dev);/* restore previous Register address */writeb (reg_save, DB-> io_addr); spin_unlock_irqrestore (& DB-> lock, flags );}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.