📄 ae531xlnx.c
字号:
} /* Check if we can transport this packet */ length = max((u32)60, length); /* total length */ mtu = dev->mtu; max_buf_size = mtu + ETH_HLEN; if (length > max_buf_size) { AE531X_PRINT(AE531X_DEBUG_ERROR, ("eth%d Tx: length %d too long. mtu=%d, trailer=%d\n", dev_sw_state->enetUnit, length, mtu, PHY_TRAILER_SIZE)); MAC_state->stats.tx_errors++; MAC_state->stats.tx_aborted_errors++; goto dropFrame; } #ifdef CONFIG_VLAN_ROUTER#ifdef HEADER_MODE skb_push(skb,PHY_HEADER_SIZE); length += PHY_HEADER_SIZE;#else length += PHY_TRAILER_SIZE;#endif phySetDestinationPort(skb->data, length, MACInfo->unit); MACInfo = &per_MAC_info[0].MACInfo;#endif /* Reap any old, completed Tx descriptors */ ae531x_TxReap(MAC_state, skb->len); txDesc = MACInfo->txQueue.curDescAddr; if (txDesc == MACInfo->txQueue.reapDescAddr) { int i; AE531X_PRINT(AE531X_DEBUG_ERROR, ("eth%d Tx: cannot get txDesc\n", dev_sw_state->enetUnit)); MAC_state->stats.tx_dropped++; MAC_state->stats.tx_fifo_errors++; /* * Stop transmit queues for any ethernet devices * associated with this MAC. */#if 0 /* XXX: no way to recover from queue stop until ae531x_MAC_tx_timeout() * is rewritten to avoid calls to shedule(). */ for (i=0; i<AE531X_DEV_PER_MAC; i++) { if (MAC_state->dev_sw_state[i]->dev) netif_stop_queue(MAC_state->dev_sw_state[i]->dev); }#endif goto dropFrame; } /* We won't fail now; so consume this descriptor */ AE531X_CONSUME_DESC((&MACInfo->txQueue)); #if TX_TWO_BUF == 1 if (!buf2) { /* break tx dma into two blocks, the second being sdram burst aligned */ lenb1 = 0x10 - ((UINT32)skb->data & 0x0f); buf2 = (char *)skb->data + lenb1; } buf2 = virt_to_bus(skb->data + lenb1);#endif /* Update the descriptor */ buf = virt_to_bus(skb->data); AE531X_DESC_BUFPTR_SET(txDesc, buf); AE531X_DESC_SWPTR_SET(txDesc, skb); ctrlen = AE531X_DESC_CTRLEN_GET(txDesc); ctrlen = (ctrlen & (DescEndOfRing)) | DescTxFirst | DescTxLast | DescTxIntEnable; if (buf2) { AE531X_DESC_LNKBUF_SET(txDesc, (UINT32)buf2); ctrlen |= ((lenb1 << DescSize1Shift) & DescSize1Mask) | (((length - lenb1) << DescSize2Shift) & DescSize2Mask); } else { ctrlen |= ((length << DescSize1Shift) & DescSize1Mask); } AE531X_DESC_CTRLEN_SET(txDesc, ctrlen); AE531X_DESC_STATUS_SET(txDesc, DescOwnByDma); /* Alert DMA engine to resume Tx */ ae531x_WriteDmaReg(MACInfo, DmaTxPollDemand, 0); sysWbFlush(); AE531X_PRINT(AE531X_DEBUG_TX, ("eth%d Tx: Desc=0x%8.8x, L=0x%8.8x, D=0x%8.8x, d=0x%8.8x, length=0x%8.8x\n", dev_sw_state->enetUnit, (UINT32)txDesc, AE531X_DESC_CTRLEN_GET(txDesc), buf, AE531X_DESC_LNKBUF_GET(txDesc), length)); /* Tell upper layers to keep it coming */ dev->trans_start = jiffies; LEAVE(); MAC_state->stats.tx_bytes += skb->len;//AE531X_DESC_STATUS_RX_SIZE(cmdsts); MAC_state->stats.tx_packets++; return 0;dropFrame: kfree_skb(skb); LEAVE(); return 0;}/******************************************************************************** ae531x_MAC_tx_timeout handles transmit timeouts*/static voidae531x_MAC_tx_timeout(struct net_device *dev){ ae531x_dev_sw_state_t *dev_sw_state; ae531x_MAC_state_t *MAC_state; ae531x_MAC_t *MACInfo; ARRIVE(); dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv; MAC_state = dev_sw_state->MAC_state; MACInfo = &MAC_state->MACInfo; AE531X_PRINT(AE531X_DEBUG_ERROR, ("enet%d: Tx timeout\n", dev_sw_state->enetUnit)); ae531x_restart(MACInfo); LEAVE();}/******************************************************************************** ae531x_MAC_do_ioctl is a placeholder for future ioctls.*/#define SIOCDEVPRIVATEGETPORTSPEED (SIOCDEVPRIVATE + 0)#define SIOCDEVPRIVATESETPORTSPEEDANDDUPLEX (SIOCDEVPRIVATE + 1)#define SIOCDEVPRIVATEGETPORTDUPLEX (SIOCDEVPRIVATE + 2)#define SIOCDEVPRIVATEGETPORTLINKED (SIOCDEVPRIVATE + 3)#define SIOCDEVPRIVATELOCKPORTMAC (SIOCDEVPRIVATE + 4)#define SIOCDEVPRIVATELOCKPORTDB (SIOCDEVPRIVATE + 5)#define SIOCDEVPRIVATETESTSWITCH (SIOCDEVPRIVATE + 6)#define SIOCDEVPRIVATENETSTATS (SIOCDEVPRIVATE + 7)static intae531x_MAC_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){ int rv = 1; ae531x_MAC_t *MACInfo; struct parse_t { int port; //port number int svalue; //set value int gvalue; //get value unsigned char mac[6]; }; ae531x_dev_sw_state_t *dev_sw_state; ae531x_MAC_state_t *MAC_state; struct parse_t *parse; ARRIVE(); dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv; MAC_state = dev_sw_state->MAC_state; MACInfo = &MAC_state->MACInfo; parse = (struct parse_t*)(ifr->ifr_data); switch( cmd ) { case SIOCDEVPRIVATEGETPORTSPEED: parse->gvalue = phyIsSpeed100(parse->port); break; case SIOCDEVPRIVATEGETPORTDUPLEX: parse->gvalue = phyIsFullDuplex_ext(parse->port); break; case SIOCDEVPRIVATESETPORTSPEEDANDDUPLEX: phySet(parse->port, MV_PHY_CONTROL, (parse->svalue << 8)); break; case SIOCDEVPRIVATEGETPORTLINKED: parse->gvalue = phyIsLinkAlive(parse->port); break; case SIOCDEVPRIVATENETSTATS: memcpy(ifr->ifr_data, dev->get_stats(dev), sizeof(struct net_device_stats)); break; default: AE531X_PRINT(AE531X_DEBUG_ERROR, ("Unsupported ioctl: 0x%x\n", cmd)); rv = -EOPNOTSUPP; } LEAVE(); return rv;}static voidae531x_MAC_setup_fntable(struct net_device *dev){ ARRIVE(); dev->get_stats = ae531x_MAC_get_stats; dev->open = ae531x_MAC_open; dev->stop = ae531x_MAC_stop; dev->hard_start_xmit = ae531x_MAC_start_xmit; dev->do_ioctl = ae531x_MAC_do_ioctl; dev->poll = ae531x_MAC_poll; dev->weight = 128; dev->mtu = dev->mtu; #if 0 /* XXX: currently, ae531x_MAC_tx_timeout() will call functions * that in turn call schedule(). this is BAD, since the * timeout call runs at interrupt time. until ae531x_MAC_tx_timeout * is rewritten to avoid schedule() calls, we do not use it. */ dev->tx_timeout = ae531x_MAC_tx_timeout;#else dev->tx_timeout = NULL;#endif dev->features = NETIF_F_HW_CSUM |\ NETIF_F_HIGHDMA; LEAVE();}static voidar5312EepromRead(char *EepromAddr, u_int16_t id, unsigned int off, unsigned int nbytes, char *data){ int i; for (i=0; i<nbytes; i++, off++) { data[i] = EepromAddr[off]; }}intae531x_get_numMACs(void){ int devid; u16 radioMask; /* Probe to find out the silicon revision and enable the correct number of macs */ devid = ((u_int16_t) ((sysRegRead(AR531X_REV) >>8) & (AR531X_REV_MAJ | AR531X_REV_MIN))); switch (devid) { case AR5212_AR5312_REV2: case AR5212_AR5312_REV7: /* Need to determine if we have a 5312 or a 2312 since they have the same Silicon Rev ID*/ ar5312EepromRead(radioConfig,0,2*AR531X_RADIO_MASK_OFF,2, (char *) &radioMask); if ((radioMask & AR531X_RADIO0_MASK) != 0) { return 2; } return 1; case AR5212_AR2313_REV8: return 1; }#ifdef CONFIG_VLAN_ROUTER return 2;#else /* default to 1 */ return 1;#endif }BOOLae531x_twisted_enet(void){ int wisoc_revision; wisoc_revision = (sysRegRead(AR531X_REV) & AR531X_REV_MAJ) >> AR531X_REV_MAJ_S; if ( (wisoc_revision == AR531X_REV_MAJ_AR2313) || /* next clause is used to determine AR2312, based on number of MACs. * must do this since revision is same for 5312 and 2312. */ (wisoc_revision == AR531X_REV_MAJ_AR5312 && ae531x_get_numMACs() == 1) ) { return TRUE; } else { return FALSE; }}#define BOARD_DATA_CONFIG 0xa87ff000//#define BOARD_DATA_CONFIG 0xbffff000intae531x_get_board_config(void){ int dataFound; char *bd_config; /* * Find start of Board Configuration data, using heuristics: * Search back from the (aliased) end of flash by 0x1000 bytes * at a time until we find the string "5311", which marks the * start of Board Configuration. Give up if we've searched * more than 500KB. */ dataFound = 0; for (bd_config = (char *)BOARD_DATA_CONFIG; bd_config > (char *)(BOARD_DATA_CONFIG - 0x30000); bd_config -= 0x1000) { if ( *(int *)bd_config == AR531X_BD_MAGIC) { dataFound = 1; break; } } if (!dataFound) { printk("Could not find Board Configuration Data\n"); bd_config = NULL; } ar531x_boardConfig = (struct ar531x_boarddata *) bd_config; return(dataFound);}intae531x_get_radio_config(void){ int dataFound; char *radio_config; /* * Now find the start of Radio Configuration data, using heuristics: * Search forward from Board Configuration data by 0x1000 bytes * at a time until we find non-0xffffffff. */ dataFound = 0; for (radio_config = ((char *) ar531x_boardConfig) + 0x1000; radio_config < (char *)0xbffff000; radio_config += 0x1000) { if (*(int *)radio_config != 0xffffffff) { dataFound = 1; break; } } if (!dataFound) { /* AR2316 relocates radio config to new location */ dataFound = 0; for (radio_config = ((char *) ar531x_boardConfig) + 0xf8; radio_config < (char *)0xbffff0f8; radio_config += 0x1000) { if (*(int *)radio_config != 0xffffffff) { dataFound = 1; break; } } } if (!dataFound) { printk("Could not find Radio Configuration data\n"); radio_config = NULL; } radioConfig = radio_config; return(dataFound);}static int __initae531x_MAC_setup(void){ int next_dev, i; struct net_device *dev; ae531x_dev_sw_state_t *dev_sw_state; ae531x_MAC_state_t *MAC_state; ae531x_MAC_t *MACInfo; char *addr; ARRIVE(); MOD_INC_USE_COUNT; for (i=0;i<AR531X_NUM_ENET_MAC * AE531X_DEV_PER_MAC; i++) { ae531x_MAC_dev[i] = NULL; } if (!ae531x_get_board_config()) { LEAVE(); return -1; } if (!ae531x_get_radio_config()) { LEAVE(); return(-1); }#ifdef CONFIG_VLAN_ROUTER for(i=0, next_dev = 0; i<ae531x_get_numMACs() && next_dev < AR531X_NUM_ENET_MAC; i++, next_dev++){#else for(i=0, next_dev = AR531X_NUM_ENET_MAC-1; i<ae531x_get_numMACs() && next_dev>=0; i++, next_dev--){#endif /* if MAC is bogus in config data, skip */ addr = ae531x_enet_mac_address_get(next_dev); if((*(u32 *)addr == 0xffffffff) && (*(u16 *)(addr+4)==0xffff)){ /* bogus MAC config data */ continue; } dev = ae531x_MAC_dev[next_dev] = init_etherdev(NULL, sizeof(ae531x_dev_sw_state_t)); if (dev == NULL) { LEAVE(); return -1; } ae531x_MAC_setup_fntable(dev); dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv; dev_sw_state->enetUnit = next_dev; dev_sw_state->unit_on_MAC = 0; MAC_state = &per_MAC_info[next_dev]; dev_sw_state->MAC_state = MAC_state; MAC_state->dev_sw_state[AE531X_LAN_PORT] = dev_sw_state; MAC_state->primary_dev = -1; /* Initialize per-MAC information */ MACInfo = &MAC_state->MACInfo; MACInfo->unit = next_dev; if (MACInfo->unit == 0) { MACInfo->macBase = (u32)(PHYS_TO_K1(AR531X_ENET0)+AE531X_MAC_OFFSET); MACInfo->dmaBase = (u32)(PHYS_TO_K1(AR531X_ENET0)+AE531X_DMA_OFFSET); MACInfo->phyBase = (u32)(PHYS_TO_K1(AR531X_ENET0)+AE531X_PHY_OFFSET); MAC_state->irq = AR531X_IRQ_ENET0_INTRS; } else {#ifndef CONFIG_AR531X_COBRA MACInfo->macBase = (u32) (PHYS_TO_K1(AR531X_ENET1)+AE531X_MAC_OFFSET); MACInfo->dmaBase = (u32) (PHYS_TO_K1(AR531X_ENET1)+AE531X_DMA_OFFSET); if (ae531x_twisted_enet()) { MACInfo->phyBase = (u32)(PHYS_TO_K1(AR531X_ENET0)+AE531X_PHY_OFFSET); } else { MACInfo->phyBase = (u32)(PHYS_TO_K1(AR531X_ENET1)+AE531X_PHY_OFFSET); } MAC_state->irq = AR531X_IRQ_ENET1_INTRS;#endif#ifdef CONFIG_VLAN_ROUTER MACInfo->macBase = (u32)(PHYS_TO_K1(AR531X_ENET0)+AE531X_MAC_OFFSET); MACInfo->dmaBase = (u32)(PHYS_TO_K1(AR531X_ENET0)+AE531X_DMA_OFFSET); MACInfo->phyBase = (u32)(PHYS_TO_K1(AR531X_ENET0)+AE531X_PHY_OFFSET); MAC_state->irq = AR531X_IRQ_ENET1_INTRS;#endif } MACInfo->OSinfo = (void *)MAC_state; } LEAVE(); return 0;}module_init(ae531x_MAC_setup);/******************************************************************************** ae531x_MAC_unload is the module unload function*/static void __exitae531x_MAC_unload(void){ int i; for (i=0;i<AR531X_NUM_ENET_MAC * AE531X_DEV_PER_MAC; i++) { if (ae531x_MAC_dev[i] != NULL) { if( (((ae531x_dev_sw_state_t *)ae531x_MAC_dev[i]->priv)->dev) != NULL) ae531x_MAC_stop(ae531x_MAC_dev[i]); unregister_netdev(ae531x_MAC_dev[i]); ae531x_MAC_dev[i] = NULL; } } MOD_DEC_USE_COUNT;}MODULE_AUTHOR("Atheros Communications, Inc.");MODULE_DESCRIPTION("Support for Atheros WiSoC Ethernet device");#ifdef MODULE_LICENSEMODULE_LICENSE("Atheros");#endifmodule_exit(ae531x_MAC_unload);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -