⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dp83815.c

📁 linux下的DP83815网卡驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
dp83815_mac_address_set (u32 iobase, char *mac_addr)
#endif    
{
    u16 *    mac_addr_ptr;
    int i;
#ifdef LINK_AGGR
    u32 iobase = (u32) pAdp->RegAddr;
#endif
    
    for (i=0, mac_addr_ptr = (u16 *)mac_addr; i<3; i++, mac_addr_ptr++) {
        DP_REG32_WRITE (DP_RFCR, DP_RFCR_RFADDR_PMATCH1 + i*2);
        DP_REG32_WRITE (DP_RFDR, CPU_TO_BUS_SWAP_16(*mac_addr_ptr));
    }
#ifdef LINK_AGGR
    if (pAdp->nFlags)
        LacpSetMacAddress(pAdp, mac_addr);
#endif    
}

#define EEPROM_READ  (0x6 << 6)

static void
dp83815_eeprom_delay (u32 iobase)
{
    DP_REG32_READ(DP_MEAR);
}

static u16
dp83815_eeprom_read (u32 iobase, int addr)
{
    int cmd = addr | EEPROM_READ;
    int i;
    u16 val = 0;

    DP_REG32_WRITE (DP_MEAR, DP_MEAR_EESEL);

    for (i = 10; i>=0; i--)
    {
        if ( cmd & (1 << i))
            DP_REG32_WRITE (DP_MEAR, DP_MEAR_EESEL | DP_MEAR_EEDI);
        else
            DP_REG32_WRITE (DP_MEAR, DP_MEAR_EESEL);
        dp83815_eeprom_delay (iobase);
        DP_REG32_WRITE (DP_MEAR, DP_MEAR_EECLK |
                        DP_REG32_READ(DP_MEAR));
        dp83815_eeprom_delay (iobase);
    }
    
    DP_REG32_WRITE (DP_MEAR, DP_MEAR_EESEL);
    dp83815_eeprom_delay (iobase);

    for (i = 0; i < 16; i++) {
        DP_REG32_WRITE (DP_MEAR, DP_MEAR_EECLK | DP_MEAR_EESEL);
        dp83815_eeprom_delay (iobase);
        if (DP_REG32_READ (DP_MEAR) & DP_MEAR_EEDO)
            val |= 1 << i;
        DP_REG32_WRITE (DP_MEAR, DP_MEAR_EESEL);
        dp83815_eeprom_delay (iobase);
    }
    DP_REG32_WRITE (DP_MEAR, DP_MEAR_EESEL);   
    DP_REG32_WRITE (DP_MEAR, 0);
    return val;
}

/* dp83815_mac_address_get - get the ethernet address */
static void
dp83815_mac_address_get (u32 iobase, char *mac_addr)
{
    u16 old_val, new_val;
    int  i;
    
    old_val = dp83815_eeprom_read (iobase, 6);
    for (i = 0; i < 3; i++)
    {
        new_val = dp83815_eeprom_read (iobase, i + 7);
        mac_addr[i*2] = (new_val << 1) + (old_val >> 15);
        mac_addr[(i*2) + 1] = new_val >> 7;
        old_val = new_val;
    }
    /* If address is not set, set up a default one */
    /* XXX needed only for pre-release versions of the hardware */
    if ((mac_addr[0] == 0) && (mac_addr[1] == 0) &&
	(mac_addr[2] == 0) && (mac_addr[3] == 0) &&
	(mac_addr[4] == 0) && (mac_addr[5] == 0)) {
         u32   random = jiffies;
         u8 *  ptr = (u8 *) &random;

	 mac_addr[0] = 0x08; /* National's Ethernet ID 0 */
	 mac_addr[1] = 0x00; /* National's Ethernet ID 1 */
	 mac_addr[2] = 0x17; /* National's Ethernet ID 2 */
	 mac_addr[3] = *ptr++;
	 mac_addr[4] = *ptr++;
	 mac_addr[5] = *ptr;
    }

}

/* dp83815_dev_reset - soft reset DP83815 */
static status
#ifdef LINK_AGGR
dp83815_dev_reset (AdapterContext *pAdp)
#else    
dp83815_dev_reset (u32 iobase)
#endif    
{
    int  timeout = 100;     /* XXX cleanup: use macro */
#ifdef LINK_AGGR
    u32 iobase = (u32) pAdp->RegAddr;
    pAdp->MacStats.txOkCount = 0;
#endif
    
    DP_REG32_WRITE (DP_CR, DP_CR_RST);
    DP_REG32_WRITE (DP_BMCR, DP_BMCR_RESET);
    while (timeout--) {
        if (DP_REG32_READ (DP_ISR) == 0x03008000) {
            return (OK);
        }
        udelay (5);
    }
    return ERROR;
}

/*
 * dp83815_queue_create - create a circular queue of descriptors
 *
 * This routine allocates a descriptor buffer array aligned  on a word
 * boundary, initializes and links the array to make a circular queue.
 */
static status
dp83815_queue_create (struct dp83815_queue *q, int count, int qtype)
{
    virt_addr     desc_addr;
    int           i;
    struct sk_buff *skb;
    
    /* allocate the desc buffer array */
    q->qbuf = (virt_addr) kmalloc (DP_QUEUE_ELE_SIZE * count + DP_ALIGN,
                                   GFP_DMA);
    if (q->qbuf == (virt_addr) NULL)
        return ERROR;

    memset ((char *)q->qbuf, 0, DP_QUEUE_ELE_SIZE * count + DP_ALIGN);

    /* Adjust alignment and Initialize queue data */
    q->cur_desc_addr =
        q->first_desc_addr =
        (virt_addr)(((u32)q->qbuf + DP_ALIGN) & ~(DP_ALIGN - 1));
    q->last_desc_addr = q->first_desc_addr + ((count -1) * DP_QUEUE_ELE_SIZE);
    q->count = count;
    q->read_desc_addr = q->cur_desc_addr;

    /* Initialize each buffer descriptor, and link them into circular queue */
    for (i=0, desc_addr=q->first_desc_addr; i<count;
         i++, desc_addr+=DP_QUEUE_ELE_SIZE) {
        DP_DESC_LNK_XLATE_SET (desc_addr, desc_addr + DP_QUEUE_ELE_SIZE);
            
        /* Update the size, BUFPTR, and SKBPTR fields for RX descriptors */
        if (qtype == DP_QUEUE_TYPE_RX) {
            skb = alloc_skb (ETH_MAX_PKT_SIZE, GFP_ATOMIC);
            if (skb == NULL) {
                dp83815_queue_delete (q);
                return (ERROR);
            }
            DP_DESC_CMDSTS_XLATE_SET (desc_addr, ETH_MAX_PKT_SIZE);
            DP_DESC_BUFPTR_XLATE_SET (desc_addr, skb->data);
            DP_DESC_SKBPTR_SET (desc_addr, (u32) skb);
        }
    }
    /* Make the queue circular */
    DP_DESC_LNK_XLATE_SET (q->last_desc_addr, q->first_desc_addr);
    return OK;
}

/* dp83815_queue_delete - frees an allocated descriptor queue */
static status
dp83815_queue_delete (struct dp83815_queue *q)
{
    int       i;
    virt_addr desc_addr;
    struct sk_buff *skb;
        
    /* Free all SKBs in the queue */
    for (i=0, desc_addr=q->first_desc_addr;
         (i < q->count);
         i++, desc_addr += DP_QUEUE_ELE_SIZE) {
        skb = (struct sk_buff *) DP_DESC_SKBPTR_GET (desc_addr);
        if (skb != NULL)
            dev_kfree_skb (skb);
    }

    /* Free the queue buffer */
    kfree ((char *)q->qbuf);
    
    return (OK);
}

/*
 * dp83815_tx_desc_get - get a valid transmit descriptor
 *
 * This routine returns the current descriptor from the tx_queue if driver is 
 * the owner, else returns NULL
 */
static virt_addr
dp83815_tx_desc_get (struct net_device *dev)
{
    struct dp83815_queue *   q;
    virt_addr  desc_addr = NULL;

    q = &((struct dp83815_priv *)(dev->priv))->tx_queue;

    /* Check if we own the descriptor */
    if  (((DP_DESC_CMDSTS_XLATE_GET (q->cur_desc_addr) & DP_DESC_CMDSTS_OWN)
          == 0) &&
         (DP_DESC_SKBPTR_GET(q->cur_desc_addr) == (u32)NULL)) {
        desc_addr = q->cur_desc_addr;
        DP_QUEUE_ELE_NEXT (q);                 /* Move to the next element */
    }

    return desc_addr;
}

/* dp83815_tx_skb_reclaim_irq - reclaim SKBs in transmitted descriptors */
static void
dp83815_tx_skb_reclaim_irq (struct net_device *dev, virt_addr desc_addr)
{
    struct sk_buff *       skb;
    struct dp83815_queue * q;

    /* Reclaim buffers from all descriptors we own. */
    q = &((struct dp83815_priv *)(dev->priv))->tx_queue;
    while (((DP_DESC_CMDSTS_XLATE_GET(q->read_desc_addr) & DP_DESC_CMDSTS_OWN) == 0) &&
           ((skb=(struct sk_buff *) DP_DESC_SKBPTR_GET(q->read_desc_addr)) != NULL))
    {
        dev_kfree_skb_irq (skb);
        DP_DESC_SKBPTR_SET (q->read_desc_addr, 0);
        q->read_desc_addr = DP_QUEUE_ELE_NEXT_GET (q, q->read_desc_addr);
    }
}

/*
 * dp83815_rx_desc_get - get a valid receive descriptor
 *
 * This routine returns the current descriptor from the rx_queue if driver is 
 * the owner, else returns NULL
 */
static virt_addr
dp83815_rx_desc_get (struct net_device *dev)
{
    struct dp83815_queue *   q;
    virt_addr                desc_addr = NULL;

    q = &((struct dp83815_priv *)(dev->priv))->rx_queue;
    /* Check if we own the descriptor */
    if  (DP_DESC_CMDSTS_XLATE_GET (q->cur_desc_addr) & DP_DESC_CMDSTS_OWN) {
        desc_addr = q->cur_desc_addr;
        DP_QUEUE_ELE_NEXT(q);                 /* Move to the next element */
    }

    return desc_addr;
}

/* dp83815_phy_setup - reset and setup the PHY device */
static status
dp83815_phy_setup (struct net_device *dev)
{
    u32  iobase = dev->base_addr;
    u32  dp_cfg_val;
    u16  phy_status;
    u16  timeout;
	u32  tmpVal;
	u32  version;

    char strbuf[80];
    struct dp83815_priv *dev_priv = (struct dp83815_priv *)dev->priv;
#ifdef LINK_AGGR
    NsmContext     *pNsm = &((struct dp83815_priv *)(dev->priv))->NsmCtxt;
    AdapterContext *pAdp =  &pNsm->AdpCtxt;
#endif

#define ATAN_AT8989P
#ifdef ATAN_AT8989P
#define DP_DSPTST 0xEC /* ATAN AT8989P switch does not meet IEEE 802.3u FLP SPEC */
	tmpVal = DP_REG32_READ(DP_DSPTST);
	tmpVal &= 0x00ff;
	DP_REG32_WRITE(DP_DSPTST, tmpVal | 0x80ff);
#endif

    if (dev_priv->autoneg == 1)
    {
        dp_cfg_val =  (DP_CFG_PESEL           |     /* parity error detect */
                       DP_CFG_PAUSE_ADV       |     /* pause capable */
                       DP_CFG_PINT_ACEN       |     /* phy intr auto clear */
                       0x00040000);                 /* phy config */

        if ((dev_priv->speed100 == 2) && (dev_priv->fullduplex == 2))
	{
            dp_cfg_val |= DP_CFG_ANEG_SEL_ALL_XD;     /* negotiate 10/100 full/half */
            sprintf (strbuf, "auto negotiate for 10/100 full/half duplex\n");
	}
	else if ((dev_priv->speed100 == 2) && (dev_priv->fullduplex == 0))
	{
            dp_cfg_val |= DP_CFG_ANEG_SEL_ALL_HD;     /* negotiate 10/100 half duplex */
            sprintf (strbuf, "auto negotiate for 10/100 half duplex\n");
	}
	else if ((dev_priv->speed100 == 0) && (dev_priv->fullduplex == 2))
	{
            dp_cfg_val |= DP_CFG_ANEG_SEL_10_XD;     /* negotiate 10 half/full duplex */
            sprintf (strbuf, "auto negotiate 10 half/full duplex\n");
	}
	else if ((dev_priv->speed100 == 1) && (dev_priv->fullduplex == 2))
	{
            dp_cfg_val |= DP_CFG_ANEG_SEL_100_XD;     /* negotiate 100 half/full duplex */
            sprintf (strbuf, "auto negotiate 100 half/full duplex\n");
	}

	DP_DEBUG (DP_DEBUG_OPEN, (KERN_INFO "%s: %s \n",dev->name, strbuf));    

	// NSC20030123 for Atan Fix start
//	DP_REG32_WRITE (DP_CFG, dp_cfg_val | DP_CFG_PHY_RST);
//	udelay (500);

	dp83815_ResetPhy(dev);
	// NSC20030123 for Atan Fix End
	dp83815_PhyAdjust(dev);
	DP_REG32_WRITE (DP_CFG, dp_cfg_val);
	for (timeout=10000; timeout; timeout--) {
	    if (DP_REG32_READ (DP_CFG) & DP_CFG_ANEG_DN)
                break;
	    udelay (500);
	}

	if (timeout == 0) {
	    printk (KERN_INFO "Phy Autonegotiate Failed, please check the cable\n");
	}
    } 
    else {
        dp_cfg_val =  (DP_CFG_PESEL           |     /* parity error detect */
                       DP_CFG_PAUSE_ADV       |     /* pause capable */
                       DP_CFG_PINT_ACEN       |     /* phy intr auto clear */
                       0x00040000);                 /* phy config */
    
        if ((dev_priv->fullduplex == 1) && (dev_priv->speed100 == 1))
	{
	    dp_cfg_val |= DP_CFG_ANEG_SEL_100_FD;   /* force 100 & full duplex */
            sprintf (strbuf, "force 100 & full duplex\n");
	}
        else if ((dev_priv->fullduplex != 1) && (dev_priv->speed100 == 1))
        {
	    dp_cfg_val |= DP_CFG_ANEG_SEL_100_HD;   /* force 100 & half duplex */
            sprintf (strbuf, "force 100 & half duplex\n");
	}
	else if ((dev_priv->fullduplex != 1) && (dev_priv->speed100 != 1))
	{
            dp_cfg_val |= DP_CFG_ANEG_SEL_10_HD;    /* force 10 & half duplex */
            sprintf (strbuf, "force 10 & half duplex\n");
        }
        else if ((dev_priv->fullduplex == 1) && (dev_priv->speed100 != 1))
	{
            dp_cfg_val |= DP_CFG_ANEG_SEL_10_FD;    /* force 10 & full duplex */
            sprintf (strbuf, "force 10 & full duplex\n");
	}

	DP_DEBUG (DP_DEBUG_OPEN, (KERN_INFO "%s: %s",dev->name, strbuf));    

	DP_REG32_WRITE (DP_CFG, DP_CFG_PHY_RST);
        udelay (1000);	

	DP_REG32_WRITE (DP_CFG, dp_cfg_val);     
    }

    /**** enable the phy interrupt ****/
    DP_REG16_WRITE (DP_MICR, DP_MICR_PHY_INT);
   
    phy_status = DP_REG16_READ (DP_PHYSTS);
    printk (KERN_INFO "%s: speed=%d duplex=%s link=%s\n",
            dev->name,
            (phy_status & DP_PHYSTS_SPEED_10) ? 10 : 100,
            (phy_status & DP_PHYSTS_FDX)? "full" : "half",
            (phy_status & DP_PHYSTS_LNK_VALID) ? "up" : "down");

    if(phy_status&DP_PHYSTS_LNK_VALID){
	    dev_priv->PrevLinkSts = 1;
    }
    else{
	    de

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -