?? dp83815.c
字號:
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
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -