?? dp83815.c
字號:
* This routine receives the data from Rx queue as long as it gets a valid
* rx_descriptor and resets the descriptor's CMDSTS field back to the Buffer
* size, and updates the BUFPTR and SKBPTR fields to the newly allocated SKB.
*/
static int
dp83815_start_receive (struct net_device *dev)
{
u32 cmdsts;
int len;
bool do_copy;
virt_addr rx_desc;
struct sk_buff *cur_skb;
struct sk_buff *new_skb;
struct sk_buff *rx_skb;
struct net_device_stats *stats_p;
#if LINK_AGGR
NsmContext *pNsm = &((struct dp83815_priv *)(dev->priv))->NsmCtxt;
AdapterContext *pAdp = &pNsm->AdpCtxt;
AdapterContext *pAggrCtxt = pAdp->pAggregatorContext;
NsmContext *pAggrNsmContext = (NsmContext *)(pAggrCtxt->pNsmContext);
#endif
stats_p = &((struct dp83815_priv *)(dev->priv))->stats;
for (rx_desc = dp83815_rx_desc_get(dev);
(rx_desc != NULL);
rx_desc = dp83815_rx_desc_get(dev)) {
DP_DEBUG (DP_DEBUG_RX,
(KERN_INFO "%s Rx: rx_desc=0x%x, CMDSTS = 0x%x",
dev->name, (u32)rx_desc, DP_DESC_CMDSTS_XLATE_GET(rx_desc)));
cmdsts = DP_DESC_CMDSTS_XLATE_GET (rx_desc);
/* Send the packet to the stack if no errors */
if ((cmdsts & DP_DESC_CMDSTS_RX_ERRORS) == 0) {
len = (cmdsts & DP_DESC_CMDSTS_SIZE) - ETH_CRC_LEN;
/*
* Allocate a new SKB
* small data packets less than DP_RX_COPY_THRESHOLD are copied
* into the new SKB, other allocate one to replace the current SKB.
*/
if (len < DP_RX_COPY_THRESHOLD) {
do_copy = TRUE;
new_skb = alloc_skb (len + 2, GFP_ATOMIC);
} else {
do_copy = FALSE;
new_skb = alloc_skb (ETH_MAX_PKT_SIZE, GFP_ATOMIC);
}
if (new_skb) {
cur_skb = (struct sk_buff *) DP_DESC_SKBPTR_GET (rx_desc);
if (do_copy) {
/* Copy data from current SKB and send the new SKB up */
rx_skb = new_skb;
skb_reserve (rx_skb, 2);
memcpy (skb_put(rx_skb, len), cur_skb->data, len);
} else {
/* Replace the the current SKB with the new SKB */
rx_skb = cur_skb;
DP_DESC_BUFPTR_XLATE_SET (rx_desc, new_skb->data);
DP_DESC_SKBPTR_SET (rx_desc, (u32) new_skb);
(void) skb_put(rx_skb, len);
}
/* update the SKB and set it up */
#ifdef LINK_AGGR
if (pAdp->nFlags & GEC_FLAG)
rx_skb->dev = pAggrNsmContext->dev_aggr;
else
rx_skb->dev = pNsm->dev;
#else
rx_skb->dev = dev;
#endif
rx_skb->protocol = eth_type_trans (rx_skb, dev);
netif_rx (rx_skb);
dev->last_rx = jiffies;
stats_p->rx_packets++;
stats_p->rx_bytes += len;
} else
stats_p->rx_dropped++; /* no resources */
if (cmdsts & DP_DESC_CMDSTS_RX_DEST_MC)
stats_p->multicast++;
}
else {
stats_p->rx_errors++; /* bad packet */
/* Update individual counters */
if (cmdsts & (DP_DESC_CMDSTS_RX_RUNT |
DP_DESC_CMDSTS_RX_LONG))
stats_p->rx_length_errors++;
if (cmdsts & DP_DESC_CMDSTS_RX_CRCE)
stats_p->rx_crc_errors++;
if (cmdsts & DP_DESC_CMDSTS_RX_FAE)
stats_p->rx_frame_errors++;
if (cmdsts & DP_DESC_CMDSTS_RX_RXO)
stats_p->rx_fifo_errors++;
}
/* Cleanup the descriptor and make available for reception */
DP_DESC_CMDSTS_XLATE_SET (rx_desc, ETH_MAX_PKT_SIZE);
}
return OK;
}
/* dp83815_get_stats - get current device statistics */
static struct net_device_stats *
dp83815_get_stats (struct net_device *dev)
{
return &((struct dp83815_priv *)(dev->priv))->stats;
}
/* dp83815_set_multicast_list - sets multicast, & promiscuous mode */
static void
dp83815_set_multicast_list (struct net_device *dev)
{
u32 rfcr_flags;
#ifndef LINK_AGGR
u32 iobase = dev->base_addr;
u16 hash_table[32];
int i;
#endif
struct dev_mc_list * mc_list;
#ifdef LINK_AGGR
MultiList *pMultiList = NULL;
MultiList *pMulti, *pMultiNext;
NsmContext *pNsm = &((struct dp83815_priv *)(dev->priv))->NsmCtxt;
AdapterContext *pAdp = &(pNsm->AdpCtxt);
#endif
/* default RFCR mode */
#ifdef LINK_AGGR
rfcr_flags = ACCEPT_PERFECT_MATCH_ON | ACCEPT_ALL_BROADCAST_ON;
#else
rfcr_flags = DP_RFCR_APM | DP_RFCR_AAB | DP_RFCR_RFEN;
#endif
/* Setup promiscuous mode */
if (dev->flags & IFF_PROMISC) {
DP_DEBUG (DP_DEBUG_OPEN,
(KERN_INFO "IFF_PROMISC\n"));
#ifdef LINK_AGGR
rfcr_flags = PROMISCUOUS_ON;
#else
rfcr_flags = (DP_RFCR_AAU | DP_RFCR_AAM | DP_RFCR_AAB |
DP_RFCR_RFEN);
#endif
} else if (dev->flags & IFF_ALLMULTI) {
/* Receive all multicast packets */
DP_DEBUG (DP_DEBUG_OPEN,
(KERN_INFO "IFF_ALLMULTI\n"));
#ifdef LINK_AGGR
rfcr_flags |= ACCEPT_ALL_MULTICAST_ON;
#else
rfcr_flags |= DP_RFCR_AAM;
#endif
} else {
#ifdef LINK_AGGR
mc_list = dev->mc_list;
pMultiList = NULL;
/* Get the multicast address list from the mc_list and allocate a
MultiList structure and put the multicast addresses into the
MultiList structure */
while(mc_list)
{
pMulti = (MultiList *)kmalloc(sizeof(MultiList), GFP_KERNEL);
if(pMulti == NULL)
{
if(pMultiList)
{
pMulti = pMultiList;
while(pMulti)
{
pMultiNext = pMulti->Next;
kfree(pMulti);
pMulti = pMultiNext;
}
}
return;
}
memcpy( pMulti->MulticastAddr, mc_list->dmi_addr, 6);
pMulti->Next = pMultiList;
pMultiList = pMulti;
mc_list = mc_list->next;
}
/* Call the HSM function to add the list of multicast addresses to the
filter */
dp83815_multicast_add(pAdp, pMultiList, TRUE);
/* Free up the list of MultiList structures */
pMulti = pMultiList;
while(pMulti)
{
pMultiNext = pMulti->Next;
kfree(pMulti);
pMulti = pMultiNext;
}
#else
/* Setup to receive programmed multicast packets */
memset (hash_table, 0, 32);
for (i=0, mc_list=dev->mc_list; mc_list && i < dev->mc_count;
i++, mc_list = mc_list->next) {
DP_DEBUG (DP_DEBUG_OPEN,
(KERN_INFO "mc_addr=%p\n", mc_list->dmi_addr));
set_bit (dp83815_crc((char *)mc_list->dmi_addr) & 0x1ff, hash_table);
}
/* install the hash table */
for (i=0; i<32; i++) {
DP_REG32_WRITE (DP_RFCR, DP_RFCR_RFADDR_FMEM_LO + i*2);
DP_REG32_WRITE (DP_RFDR, (u32) hash_table[i]);
}
rfcr_flags |= DP_RFCR_MHEN;
#endif
}
#ifdef LINK_AGGR
dp83815_rxfilter (pAdp, rfcr_flags);
#else
DP_REG32_WRITE (DP_RFCR, 0);
DP_REG32_WRITE (DP_RFCR, rfcr_flags);
#endif
DP_DEBUG (DP_DEBUG_OPEN,
(KERN_INFO "%s : MC Setup RFCR flags=0x%x\n",dev->name, rfcr_flags));
return;
}
/* dp83815_crc - computer CRC for hash table entries */
static int
dp83815_crc (char * mc_addr)
{
u32 crc;
u8 cur_byte;
u8 msb;
u8 byte, bit;
crc = ~0;
for (byte=0; byte<6; byte++) {
cur_byte = *mc_addr++;
for (bit=0; bit<8; bit++) {
msb = crc >> 31;
crc <<= 1;
if (msb ^ (cur_byte & 1)) {
crc ^= DP_POLYNOMIAL;
crc |= 1;
}
cur_byte >>= 1;
}
}
crc >>= 23;
return (crc);
}
/* dp83815_interrupt - handle driver specific ioctls */
static int
dp83815_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
{
#if LINK_AGGR
void *data = &(rq->ifr_data);
NsmContext *pNsm = &((struct dp83815_priv *)(dev->priv))->NsmCtxt;
AdapterContext *pAdp = &(pNsm->AdpCtxt);
switch (cmd)
{
case SIOCSIFADDR:
memcpy ((void *)dev->dev_addr, data, 6);
memcpy ((void *)pAdp->CurrMacAddr, data, 6);
dp83815_mac_address_set (pAdp, pAdp->CurrMacAddr);
break;
case SIOCDEVPRIVATE:
break;
default:
return -EOPNOTSUPP;
}
return OK;
#else
return -EOPNOTSUPP;
#endif
}
static void
dp83815_interrupt (int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device * dev = dev_id;
u16 iobase = dev->base_addr;
u32 reg_isr;
u32 CurrentLinkStatus;
u16 tmpVal;
u32 version;
struct dp83815_priv *dev_priv = (struct dp83815_priv *)dev->priv;
#ifdef TEST_RX
static int rx_cnt = 0;
u16 phy_status;
#endif
#ifdef LINK_AGGR
u16 phy_status;
NsmContext *pNsm = &((struct dp83815_priv *)(dev->priv))->NsmCtxt;
AdapterContext *pAdp = &pNsm->AdpCtxt;
#endif
CurrentLinkStatus= DP_REG32_READ(DP_PHYSTS);
if(dev_priv->PrevLinkSts!=(CurrentLinkStatus&DP_PHYSTS_LNK_VALID)){ //Link Changed
if( CurrentLinkStatus&DP_PHYSTS_LNK_VALID){
if( ~(CurrentLinkStatus&DP_PHYSTS_SPEED_10)){
if( (dev_priv->autoneg !=1) || (dev_priv->speed100 !=2) || (dev_priv->fullduplex!=2))
dp83815_phy_setup(dev);
else
dp83815_PhyCoefAdjust(dev);
}
}
else{
dp83815_ResetPhy(dev);
dp83815_PhyAdjust(dev);
}
dev_priv->PrevLinkSts = (CurrentLinkStatus&DP_PHYSTS_LNK_VALID);
}
reg_isr = DP_REG32_READ (DP_ISR);
DP_DEBUG (DP_DEBUG_IOCTL,
(KERN_INFO "%s: intr_status=0x%x\n", dev->name,
reg_isr));
if (reg_isr & DP_ISR_RXOK)
dp83815_start_receive (dev);
if (reg_isr & (DP_ISR_TXOK | DP_ISR_TXERR | DP_ISR_TXURN | DP_ISR_TXIDLE |
DP_ISR_TXDESC))
dp83815_tx_skb_reclaim_irq (dev, NULL);
if (reg_isr & DP_ISR_PHY)
{
#ifdef LINK_AGGR
phy_status = DP_REG16_READ (DP_PHYSTS);
if ((phy_status & DP_PHYSTS_LNK_VALID) &&
!(pAdp->AdapterStatus & LINK_UP))
{
DP_DEBUG (DP_DEBUG_IOCTL,
(KERN_INFO " %s: is up \n", dev->name));
pAdp->AdapterStatus |= LINK_UP;
}
if (!(phy_status & DP_PHYSTS_LNK_VALID) &&
(pAdp->AdapterStatus & LINK_UP))
{
DP_DEBUG (DP_DEBUG_IOCTL,
(KERN_INFO "%s: is down \n", dev->name));
pAdp->AdapterStatus &= ~LINK_UP;
}
if (pAdp->nFlags)
LacpAdapterStatusCheck(pAdp);
#else
DP_DEBUG (DP_DEBUG_IOCTL,
(KERN_INFO " %s: Link status changed \n", dev->name));
#endif
}
}
/* dp83815_mac_address_set - set the ethernet address */
static void
#ifdef LINK_AGGR
dp83815_mac_address_set (AdapterContext *pAdp, char* mac_addr)
#else
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -