📄 dmfe.c
字号:
#if 0
/* show statistic counter */
printk("<DM9XS>: FU:%lx EC:%lx LC:%lx NC:%lx LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n",
db->tx_fifo_underrun, db->tx_excessive_collision,
db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier,
db->tx_jabber_timeout, db->reset_count, db->reset_cr8,
db->reset_fatal, db->reset_TXtimeout);
#endif
return 0;
}
/*
DM9102 insterrupt handler
receive the packet to upper layer, free the transmitted packet
*/
#ifdef SA_SHIRQ
static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
#else
static void dmfe_interrupt(int irq, struct pt_regs *regs)
#endif
{
#ifdef SA_SHIRQ
struct DEVICE *dev=dev_id;
#else
struct DEVICE *dev = (struct DEVICE *)(irq2dev_map[irq]);
#endif
struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv;
u32 ioaddr = dev->base_addr;
DMFE_DBUG(0, "dmfe_interrupt()", 0);
if (!dev)
{
DMFE_DBUG(1, "dmfe_interrupt() without DEVICE arg", 0);
return;
}
/* Got DM910X status */
db->cr5_data=inl(ioaddr+DCR5);
outl(db->cr5_data, ioaddr+DCR5);
if ( !(db->cr5_data & 0xc1) )
return;
/* Disable MAC interrupt in CR7 to solve the interrupt edge problem */
outl(0, ioaddr+DCR7);
/* Check system status */
if (db->cr5_data & 0x2000)
{
/* system bus error happen */
DMFE_DBUG(1, "System bus error happen. CR5=", db->cr5_data);
#if LINUX_VERSION_CODE < 0x20400
dev->tbusy=1;
#else
netif_stop_queue(dev);
#endif
db->reset_fatal++;
db->wait_reset=1; /* Need to RESET */
return;
}
/* Received the coming packet */
if ( (db->cr5_data & 0x40) && db->rx_avail_cnt )
dmfe_rx_packet(dev, db);
/* reallocated rx descriptor buffer */
if (db->rx_avail_cnt<RX_DESC_CNT)
allocated_rx_buffer(db);
/* Free the transmitted descriptor */
//if ( db->cr5_data & 0x01)
dmfe_free_tx_pkt(dev, db);
// mark_bh(NET_BH); /* Active upper layer */
/* Mode Check */
if (db->dm910x_chk_mode & 0x2)
{
db->dm910x_chk_mode = 0x4;
db->cr6_data |= 0x100;
update_cr6(db->cr6_data, db->ioaddr);
}
/* Restore CR7 to enable MAC interrupt mask */
outl(db->cr7_data, ioaddr+DCR7);
}
/*
* Free TX resource after TX complete
*/
static void dmfe_free_tx_pkt(struct DEVICE *dev, struct dmfe_board_info * db)
{
struct tx_desc *txptr;
u32 ioaddr = dev->base_addr;
txptr = db->tx_remove_ptr;
while(db->tx_packet_cnt) {
/* printk("<DMFE>: tdes0=%x\n", txptr->tdes0); */
if (txptr->tdes0 & 0x80000000)
break;
/* A packet sent completed */
db->tx_packet_cnt--;
db->stats.tx_packets++;
/* Transmit statistic counter */
if ( txptr->tdes0 != 0x7fffffff ) {
/* printk("<DMFE>: tdes0=%x\n", txptr->tdes0); */
db->stats.collisions += (txptr->tdes0 >> 3) & 0xf;
#if LINUX_VERSION_CODE > 0x20127
db->stats.tx_bytes += txptr->tdes1 & 0x7ff;
#endif
if (txptr->tdes0 & TDES0_ERR_MASK) {
db->stats.tx_errors++;
if (txptr->tdes0 & 0x0002) { /* UnderRun */
db->tx_fifo_underrun++;
if ( !(db->cr6_data & CR6_SFT) ) {
db->cr6_data = db->cr6_data | CR6_SFT;
update_cr6(db->cr6_data, db->ioaddr);
}
}
if (txptr->tdes0 & 0x0100)
db->tx_excessive_collision++;
if (txptr->tdes0 & 0x0200)
db->tx_late_collision++;
if (txptr->tdes0 & 0x0400)
db->tx_no_carrier++;
if (txptr->tdes0 & 0x0800)
db->tx_loss_carrier++;
if (txptr->tdes0 & 0x4000)
db->tx_jabber_timeout++;
}
}
txptr = (struct tx_desc *) txptr->next_tx_desc;
}/* End of while */
/* Update TX remove pointer to next */
db->tx_remove_ptr = (struct tx_desc *) txptr;
/* Send the Tx packet in queue */
if ( (db->tx_packet_cnt < TX_MAX_SEND_CNT) && db->tx_queue_cnt ) {
txptr->tdes0 = 0x80000000; /* Set owner bit */
db->tx_packet_cnt++; /* Ready to send */
db->tx_queue_cnt--;
outl(0x1, ioaddr + DCR1); /* Issue Tx polling */
dev->trans_start = jiffies; /* saved time stamp */
}
/* Resource available check */
if ( db->tx_queue_cnt < TX_WAKE_DESC_CNT )
#if LINUX_VERSION_CODE < 0x20400
{ dev->tbusy=0; mark_bh(NET_BH); } /* Active upper layer */
#else
netif_wake_queue(dev); /* Active upper layer */
#endif
}
/*
Receive the come packet and pass to upper layer
*/
static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db)
{
struct rx_desc *rxptr;
struct sk_buff *skb;
int rxlen;
rxptr=db->rx_ready_ptr;
while(db->rx_avail_cnt)
{
if (rxptr->rdes0 & 0x80000000) /* packet owner check */
break;
db->rx_avail_cnt--;
db->interval_rx_cnt++;
if ((rxptr->rdes0 & 0x300)!=0x300)
{
/* A packet without First/Last flag */
/* reused this SKB */
DMFE_DBUG(0, "Reused SK buffer, rdes0", rxptr->rdes0);
dmfe_reused_skb(db, (struct sk_buff *)rxptr->rx_skb_ptr);
}
else
{
/* A packet with First/Last flag */
rxlen=((rxptr->rdes0 >> 16) & 0x3fff) - 4; /* skip CRC */
if (rxptr->rdes0 & 0x8000) /* error summary bit check */
{
/* This is a error packet */
/* printk("rdes0 error : %x \n", rxptr->rdes0); */
db->stats.rx_errors++;
if (rxptr->rdes0 & 1) db->stats.rx_fifo_errors++;
if (rxptr->rdes0 & 2) db->stats.rx_crc_errors++;
if (rxptr->rdes0 & 0x80) db->stats.rx_length_errors++;
}
if ( !(rxptr->rdes0 & 0x8000) ||
((db->cr6_data & CR6_PM) && (rxlen>6)) )
{
skb=(struct sk_buff *)rxptr->rx_skb_ptr;
/* Received Packet CRC check need or not */
if ( (db->dm910x_chk_mode & 1) && (cal_CRC(skb->tail, rxlen, 1)!=(*(unsigned long *)(skb->tail+rxlen))) )
{
/* Found a error received packet */
dmfe_reused_skb(db, (struct sk_buff *)rxptr->rx_skb_ptr);
db->dm910x_chk_mode = 3;
}
else
{
/* A good packet coming, send to upper layer */
/* Shorst packet used new SKB */
if ( (rxlen<RX_COPY_SIZE) && ((skb=dev_alloc_skb(rxlen+2))!=NULL) )
{
/* Rx packet size less than COPY_SIZE, allocated a rxlen SKB */
skb->dev=dev;
skb_reserve(skb, 2); /* 16byte align */
memcpy(skb_put(skb, rxlen), ((struct sk_buff *)rxptr->rx_skb_ptr)->tail, rxlen);
dmfe_reused_skb(db, (struct sk_buff *)rxptr->rx_skb_ptr);
}
else
{
/* Pass this Rx buffer to upper layer */
skb->dev=dev;
skb_put(skb, rxlen);
}
skb->protocol=eth_type_trans(skb, dev);
netif_rx(skb); /* Send to upper layer */
dev->last_rx = jiffies;
db->stats.rx_packets++;
#if LINUX_VERSION_CODE > 0x20127
db->stats.rx_bytes+=rxlen;
#endif
}
}
else
{
/* Reuse SKB buffer when the packet is error */
DMFE_DBUG(0, "Reused SK buffer, rdes0", rxptr->rdes0);
dmfe_reused_skb(db, (struct sk_buff *)rxptr->rx_skb_ptr);
}
}
rxptr=(struct rx_desc *)rxptr->next_rx_desc;
}
db->rx_ready_ptr=rxptr;
}
/*
Get statistics from driver.
*/
#if LINUX_VERSION_CODE < 0x20400
static struct enet_statistics * dmfe_get_stats(struct DEVICE *dev)
#else
static struct net_device_stats * dmfe_get_stats(struct DEVICE *dev)
#endif
{
struct dmfe_board_info *db=(struct dmfe_board_info *)dev->priv;
DMFE_DBUG(0, "dmfe_get_stats", 0);
return &db->stats;
}
/*
Set DM910X multicast address
*/
static void dmfe_set_filter_mode(struct DEVICE * dev)
{
struct dmfe_board_info *db=dev->priv;
DMFE_DBUG(0, "dmfe_set_filter_mode()", 0);
if (dev->flags & IFF_PROMISC)
{
DMFE_DBUG(0, "Enable PROM Mode", 0);
db->cr6_data |=CR6_PM | CR6_PBF;
update_cr6(db->cr6_data, db->ioaddr);
return;
}
if (dev->flags & IFF_ALLMULTI || dev->mc_count > DMFE_MAX_MULTICAST)
{
DMFE_DBUG(0, "Pass all multicast address", dev->mc_count);
db->cr6_data&=~(CR6_PM | CR6_PBF);
db->cr6_data|=CR6_PAM;
return;
}
DMFE_DBUG(0, "Set multicast address", dev->mc_count);
if (db->chip_id == PCI_DM9132_ID)
dm9132_id_table(dev, dev->mc_count); /* DM9132 */
else
send_filter_frame(dev, dev->mc_count); /* DM9102/DM9102A */
}
/*
Process the upper socket ioctl command
*/
static int dmfe_do_ioctl(struct DEVICE *dev, struct ifreq *ifr, int cmd)
{
DMFE_DBUG(0, "dmfe_do_ioctl()", 0);
return 0;
}
/*
A periodic timer routine
Dynamic media sense, allocated Rx buffer...
*/
static void dmfe_timer(unsigned long data)
{
u32 tmp_cr8;
unsigned char tmp_cr12;
struct DEVICE *dev=(struct DEVICE *)data;
struct dmfe_board_info *db=(struct dmfe_board_info *)dev->priv;
DMFE_DBUG(0, "dmfe_timer()", 0);
/* Media mode process when Link OK before enter this route */
if (db->first_in_callback==0)
{
db->first_in_callback=1;
if (db->chip_type && (db->chip_id==PCI_DM9102_ID))
{
db->cr6_data &= ~0x40000;
update_cr6(db->cr6_data, db->ioaddr);
phy_write(db->ioaddr, db->phy_addr, 0, 0x1000, db->chip_id);
db->cr6_data |= 0x40000;
update_cr6(db->cr6_data, db->ioaddr);
db->timer.expires = DMFE_TIMER_WUT + HZ * 2;
add_timer(&db->timer);
return;
}
}
/* Operating Mode Check */
if ((db->dm910x_chk_mode & 0x1) && (db->stats.rx_packets > MAX_CHECK_PACKET) )
{
db->dm910x_chk_mode = 0x4;
}
/* Dynamic reset DM910X : system error or transmit time-out */
tmp_cr8=inl(db->ioaddr+DCR8);
if ((db->interval_rx_cnt==0) && (tmp_cr8))
{
db->reset_cr8++;
db->wait_reset=1;
}
db->interval_rx_cnt=0;
/* TX polling kick monitor */
if ( db->tx_packet_cnt &&
((jiffies - dev->trans_start) > DMFE_TX_KICK) )
{
outl(0x1, dev->base_addr + DCR1); /* Tx polling again */
/* TX Timeout */
if ( db->tx_packet_cnt && ((jiffies - dev->trans_start) > DMFE_TX_TIMEOUT) )
{
db->reset_TXtimeout++;
db->wait_reset = 1;
}
}
if (db->wait_reset)
{
DMFE_DBUG(0, "Warn!! Warn!! Tx/Rx moniotr step1", db->tx_packet_cnt);
db->reset_count++;
dmfe_dynamic_reset(dev);
db->first_in_callback=0;
db->timer.expires = DMFE_TIMER_WUT;
add_timer(&db->timer);
return;
}
/* Link status check, Dynamic media type change */
if (db->chip_id == PCI_DM9132_ID)
tmp_cr12=inb(db->ioaddr+DCR9+3); /* DM9132 */
else
tmp_cr12=inb(db->ioaddr+DCR12); /* DM9102/DM9102A */
if ( ((db->chip_id == PCI_DM9102_ID) && (db->chip_revision == 0x02000030)) ||
((db->chip_id == PCI_DM9132_ID) && (db->chip_revision == 0x02000010)) )
{
/* DM9102A Chip */
if (tmp_cr12 & 2)
tmp_cr12=0x0; /* Link failed */
else tmp_cr12=0x3; /* Link OK */
}
if (!(tmp_cr12 & 0x3) && !db->link_failed)
{
/* Link Failed */
DMFE_DBUG(0, "Link Failed", tmp_cr12);
db->link_failed=1;
/* For Force 10/100M Half/Full mode: Enable Auto-Nego mode */
/* AUTO or force 1M Homerun/Longrun don't need */
if ( !(db->media_mode & 0x38) )
phy_write(db->ioaddr, db->phy_addr, 0, 0x1000, db->chip_id);
/* In AUTO mode, if INT phyxcer link failed, select EXT device */
if (db->media_mode & DMFE_AUTO)
{
/* 10/100M link failed, used 1M Home-Net */
db->cr6_data|=0x00040000; /* CR6 bit18 = 1, select Home-Net */
db->cr6_data&=~0x00000200; /* CR6 bit9 =0, half duplex mode */
update_cr6(db->cr6_data, db->ioaddr);
}
}
else if ((tmp_cr12 & 0x3) && db->link_failed)
{
DMFE_DBUG(0, "Link link OK", tmp_cr12);
db->link_failed=0;
/* Auto Sense Speed */
if (db->media_mode & DMFE_AUTO)
if (dmfe_sense_speed(db))
db->link_failed=1;
dmfe_process_mode(db);
/* SHOW_MEDIA_TYPE(db->op_mode); */
}
/* HPNA remote command check */
if (db->HPNA_command & 0xf00)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -