📄 ae531xlnx.c
字号:
} return NULL;} #endif/******************************************************************************** ae531x_phy_poll periodically checks for changes in phy status* (e.g. dropped link).*/static intae531x_phy_poll(void *data){ ae531x_dev_sw_state_t *dev_sw_state = (ae531x_dev_sw_state_t *)data; ae531x_MAC_t *MACInfo = &dev_sw_state->MAC_state->MACInfo; int unit = dev_sw_state->enetUnit;#if 0 while(dev_sw_state->dev!=NULL) { if (MACInfo->port_is_up) { phyCheckStatusChange(unit); } set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(AE531X_PHY_POLL_SECONDS * HZ); }#else if(dev_sw_state->dev!=NULL) { if (MACInfo->port_is_up) { phyCheckStatusChange(unit); } dev_sw_state->timer.expires = TIMER_WUT; add_timer(&dev_sw_state->timer); }#endif return 0;}static char invalid_enet_MAC_addr[] = {0, 0, 0, 0, 0, 0};/* * Fetch a pointer to an ethernet's MAC address * in the Board Configuration data (in flash). */char *ae531x_enet_mac_address_get(int MACUnit){ /* XXX: Hack for poorly configured boards. * Cannot setup bridging properly (brctl) when both enet * interfaces share the same MAC address. * */#ifdef CONFIG_ASK_MULT_MAC_HACK static u8 enet0Mac[6] = {0x00, 0x0d, 0x0b, 0x13, 0x6b, 0x16}; static u8 enet1Mac[6] = {0x00, 0x0d, 0x0b, 0x13, 0x6b, 0x17};#endif static u8 enet0Mac[6] = {0x00, 0x0d, 0x0b, 0x13, 0x6b, 0x16}; static u8 enet1Mac[6] = {0x00, 0x0d, 0x0b, 0x13, 0x6b, 0x17}; if (!ar531x_boardConfig) return invalid_enet_MAC_addr; if (MACUnit == 0) {#ifndef CONFIG_ASK_MULT_MAC_HACK return enet0Mac;//ar531x_boardConfig->enet0Mac;#else return enet0Mac;#endif } if (MACUnit == 1) {#ifndef CONFIG_ASK_MULT_MAC_HACK return enet1Mac;//ar531x_boardConfig->enet1Mac;#else return enet1Mac;#endif } printk("Invalid ethernet MAC unit number (%d)!\n", MACUnit); return invalid_enet_MAC_addr;}/******************************************************************************** ae531x_MAC_open is the standard Linux open function. It puts* hardware into a known good state, allocates queues, starts* the phy polling task, and arranges for interrupts to be handled.*/static int ae531x_MAC_open(struct net_device *dev){ ae531x_dev_sw_state_t *dev_sw_state; ae531x_MAC_state_t *MAC_state; ae531x_MAC_t *MACInfo; u8 *MACAddr; int rv; struct tq_struct *restart_task; pid_t phy_poll_pid; ARRIVE(); dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv; dev_sw_state->dev = dev; MAC_state = dev_sw_state->MAC_state; MACInfo = &MAC_state->MACInfo; restart_task = &MAC_state->restart_task; restart_task->routine = ae531x_restart; restart_task->data = (void *)MACInfo; AE531X_PRINT(AE531X_DEBUG_RESET, ("ae531x_MAC_open eth%d ethmac%d macBase=0x%x dmaBase=0x%x irq=0x%x\n", dev_sw_state->enetUnit, MACInfo->unit, MACInfo->macBase, MACInfo->dmaBase, MAC_state->irq)); /* Default MAC address */ MACAddr = ae531x_enet_mac_address_get(MACInfo->unit); if((dev->dev_addr[0] == 0x00) && (dev->dev_addr[1] == 0x00) && (dev->dev_addr[2] == 0x00) && (dev->dev_addr[3] == 0x00) && (dev->dev_addr[4] == 0x00) && (dev->dev_addr[5] == 0x00)) memcpy(dev->dev_addr, MACAddr, dev->addr_len ); if (!MACInfo->port_is_up ) { /* Bring MAC and PHY out of reset */ #ifdef CONFIG_VLAN_ROUTER if(!hwInit && MACInfo->unit == 0) { #endif ae531x_reset(MACInfo); /* Attach interrupt handler */ rv = request_irq(MAC_state->irq, ae531x_MAC_intr, SA_INTERRUPT, "ae531x_MAC_intr", (void *)MACInfo); if (rv < 0) { AE531X_PRINT(AE531X_DEBUG_ERROR, ("request_irq(0x%x) failed (%d)\n", MAC_state->irq, rv)); goto open_failure; } /* Initialize PHY */ AE531X_PRINT(AE531X_DEBUG_RESET, ("\n --- phyBase: %08x\n", MACInfo->phyBase)); phySetup(MACInfo->unit, MACInfo->phyBase); #if 0 /* Start thread to poll for phy link status changes */ phy_poll_pid = kernel_thread(ae531x_phy_poll, dev_sw_state, 0); if (phy_poll_pid < 0) { AE531X_PRINT(AE531X_DEBUG_ERROR, ("ethmac%d unable to start Phy Poll thread\n", MACInfo->unit)); } #else /* set and active a timer process */ init_timer(&dev_sw_state->timer); dev_sw_state->timer.expires = TIMER_WUT; dev_sw_state->timer.data = (unsigned long)dev_sw_state; dev_sw_state->timer.function = &ae531x_phy_poll; add_timer(&dev_sw_state->timer); #endif /* Allocate RX/TX Queues */ if (ae531x_AllocateQueues(MACInfo) < 0) { AE531X_PRINT(AE531X_DEBUG_RESET, ("Queue allocation failed")); free_irq(MAC_state->irq, (void *)MACInfo); goto open_failure; } /* Initialize DMA and descriptors */ ae531x_DmaReset(MACInfo); /* Initialize MAC */ ae531x_MACReset(MACInfo); /* Enable Receive/Transmit */ ae531x_EnableComm(MACInfo);#ifdef CONFIG_VLAN_ROUTER hwInit = TRUE; } #endif MAC_state->primary_dev = dev_sw_state->unit_on_MAC; MACInfo->port_is_up = TRUE; }#ifdef CONFIG_VLAN_ROUTER#ifndef HEADER_MODE if(MACInfo->unit == 1) { mv_setATUDB(CPU_PORT, dev->dev_addr, 0); mv_setATUDB(CPU_PORT, dev->dev_addr, 1); //mv_showATUDB(CPU_PORT); for debug } #endif#endif dev->trans_start = jiffies; SET_MODULE_OWNER(dev); LEAVE(); return 0;open_failure: LEAVE(); return -1;}/* * Shut down MAC hardware. */static voidae531x_MAC_shutdown(ae531x_MAC_state_t *MAC_state){ ae531x_MAC_t *MACInfo; MACInfo = &MAC_state->MACInfo; MACInfo->port_is_up = FALSE; /* Disable Receive/Transmit */ ae531x_DisableComm(MACInfo); /* Disable Interrupts */ ae531x_DmaIntDisable(MACInfo); sysWbFlush(); free_irq(MAC_state->irq, (void *)MACInfo);#ifdef CONFIG_VLAN_ROUTER hwInit = FALSE;#endif /* Free Transmit & Receive skb's/descriptors */ ae531x_TxReap(MAC_state, 0); /* one last time */ ae531x_FreeQueues(MACInfo);}/******************************************************************************** ae531x_MAC_stop is the standard Linux stop function. It undoes* everything set up by ae531x_MAC_open.*/static intae531x_MAC_stop(struct net_device *dev){ ae531x_dev_sw_state_t *dev_sw_state; ae531x_MAC_state_t *MAC_state; ae531x_MAC_t *MACInfo; int i; ARRIVE(); dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv; MAC_state = dev_sw_state->MAC_state; MACInfo = &MAC_state->MACInfo;#ifdef CONFIG_VLAN_ROUTER if(MACInfo->unit == 0) #endif del_timer(&dev_sw_state->timer); for (i=0; i<AE531X_DEV_PER_MAC; i++) { if ((MAC_state->dev_sw_state[i]->dev) && (MAC_state->dev_sw_state[i]->dev != dev_sw_state->dev)) { break; } } if (i < AE531X_DEV_PER_MAC) { /* Physical MAC is still in use */ if (MAC_state->primary_dev == dev_sw_state->unit_on_MAC) { /* * If the primary_dev is being stopped * then we need to assign a new one. */ MAC_state->primary_dev = i; } } else {#ifdef CONFIG_VLAN_ROUTER if(MACInfo->unit == 0) #endif /* Physical MAC is no longer in use */ ae531x_MAC_shutdown(MAC_state); } dev_sw_state->dev = NULL; LEAVE(); return 0;}/******************************************************************************** ae531x_rxbuf_alloc - Allocate an skb to be associated with an RX descriptor.** RETURNS: A pointer to the skb. Also returns a pointer to the underlying* buffer and the size of that buffer. */void *ae531x_rxbuf_alloc(ae531x_MAC_t *MACInfo, char **rxBuffp, int *rxBuffSizep){ int buf_size; struct sk_buff *skb; char *rxBuff; int rxBuffSize; buf_size = AE531X_RX_BUF_SIZE; skb = dev_alloc_skb(buf_size); if (skb) { /* skb->dev = dev; */ skb_reserve(skb, RXBUFF_RESERVE); rxBuffSize = skb_tailroom(skb); rxBuff = skb->tail; *rxBuffp = rxBuff; *rxBuffSizep = rxBuffSize; } return skb;}/******************************************************************************** ae531x_swptr_free - Free the skb, if any, associated with a descriptor.*/voidae531x_swptr_free(VIRT_ADDR desc){ struct sk_buff *skb; skb = (struct sk_buff *)AE531X_DESC_SWPTR_GET(desc); if (skb) { AE531X_DESC_SWPTR_SET(desc, NULL); kfree_skb(skb); }}/********************************************************************************* ae531x_TxReap - the driver Tx completion routine.** This routine reaps sk_buffs which have already been transmitted.**/static voidae531x_TxReap(ae531x_MAC_state_t *MAC_state, int length){ AE531X_QUEUE *txq; VIRT_ADDR txDesc; UINT32 cmdsts; struct sk_buff *skb; int reaped; ae531x_MAC_t *MACInfo; static int aeUselessReap = 0;#ifdef DEBUG static int aeMaxReap = 0;#endif ARRIVE(); #ifdef CONFIG_VLAN_ROUTER MACInfo = &per_MAC_info[0].MACInfo; txq = &per_MAC_info[0].MACInfo.txQueue;#else MACInfo = &MAC_state->MACInfo; txq = &MACInfo->txQueue;#endif reaped = 0; while (1) { txDesc = AE531X_QUEUE_ELE_NEXT_GET(txq, txq->reapDescAddr); if (txDesc == txq->curDescAddr) { break; } cmdsts = AE531X_DESC_STATUS_GET(KSEG1ADDR(txDesc)); if (cmdsts & DescOwnByDma) { break; } /* Release sk_buff associated with completed transmit */ skb = (struct sk_buff *)AE531X_DESC_SWPTR_GET(txDesc); if (skb) { kfree_skb(skb); AE531X_DESC_SWPTR_SET(txDesc, NULL); }#if 0 /* Update statistics according to completed transmit desc */ if (cmdsts & DescTxErrors) { AE531X_PRINT(AE531X_DEBUG_ERROR, ("enetmac%d Tx prior error: 0x%8.8x <0x%8.8x> 0x%8.8x\n", MACInfo->unit, cmdsts, DescTxErrors, (int)txDesc));#ifdef DEBUG //my_mvPhyShow(MACInfo->unit); printk ("ae531xMacControl: 0x%08x\tMacFlowControl: 0x%08x\n", ae531x_ReadMacReg(MACInfo, MacControl), ae531x_ReadMacReg(MACInfo, MacFlowControl));#endif MAC_state->stats.tx_errors++; if (cmdsts & (DescTxLateCollision | DescTxExcCollisions)) { MAC_state->stats.tx_aborted_errors++; } if (cmdsts & (DescTxLostCarrier | DescTxNoCarrier)) { MAC_state->stats.tx_carrier_errors++; } } else { // MAC_state->stats.tx_bytes += length;//AE531X_DESC_STATUS_RX_SIZE(cmdsts); // MAC_state->stats.tx_packets++; }#endif MAC_state->stats.collisions += ((cmdsts & DescTxCollMask) >> DescTxCollShift); txq->reapDescAddr = txDesc; reaped++; } if (reaped > 0) { int i;#ifdef DEBUG if (reaped > aeMaxReap) { aeMaxReap = reaped; printk("max reaped = %d\n", reaped); }#endif AE531X_PRINT(AE531X_DEBUG_TX_REAP, ("reaped %d\n", reaped)); /* * Re-start transmit queues for all ethernet devices * associated with this MAC. */ for (i=0; i<AE531X_DEV_PER_MAC; i++) { if (MAC_state->dev_sw_state[i]->dev) netif_start_queue(MAC_state->dev_sw_state[i]->dev); } } else { aeUselessReap++; } LEAVE();}/******************************************************************************** ae531x_MAC_start_xmit sends a packet.*/static intae531x_MAC_start_xmit(struct sk_buff *skb, struct net_device *dev){ ae531x_dev_sw_state_t *dev_sw_state; ae531x_MAC_state_t *MAC_state; ae531x_MAC_t *MACInfo; u32 buf; u32 ctrlen; u32 length, lenb1 = 0; char *buf2 = NULL; int mtu; int max_buf_size; VIRT_ADDR txDesc; int iface; unsigned long flags; ARRIVE(); dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv; MAC_state = dev_sw_state->MAC_state; MACInfo = &MAC_state->MACInfo; iface = MACInfo->unit; length = skb->len; /* Check if this port is up, else toss packet */ if (!MACInfo->port_is_up) { buf = virt_to_bus(skb->data); AE531X_PRINT(AE531X_DEBUG_ERROR, ("eth%d Tx Down, dropping buf=0x%8.8x, length=0x%8.8x, skb=%p\n", dev_sw_state->enetUnit, buf, length, (void *)skb)); MAC_state->stats.tx_dropped++; MAC_state->stats.tx_carrier_errors++; goto dropFrame; } if (ae531x_IsInResetMode(MACInfo)) { AE531X_PRINT(AE531X_DEBUG_ERROR, ("eth%d Tx: In Chip reset - drop frame\n", dev_sw_state->enetUnit)); MAC_state->stats.tx_dropped++; MAC_state->stats.tx_aborted_errors++; goto dropFrame;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -